home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

Python/WinDBG拡張機能その2:pykdを使ってみる

Python/WinDBG拡張機能その2:pykdを使ってみる

Python / WinDBG拡張機能その2:pykdを使ってみる
id: 939 所有者: msakamoto-sf    作成日: 2011-04-04 22:43:16
カテゴリ: Python WinDBG Windows 

pykdはC言語で書かれたPython拡張で、WinDBG拡張機能の一部をPython経由で呼び出せます。
以前 Python/WinDBG拡張機能でデバッガを作ってみる で紹介したPyDbgEngと異なる点は、DbgEngのCOMコンポーネントをC++で隠蔽し、独自のインターフェイスでラップしてPython側に公開している点です。さらにWinDBG拡張機能としても使えるようになっていて、WinDBGやCDBのプロンプトから

!py foobar.py

みたいにしてPythonスクリプトを実行できます。このPythonスクリプト内からpykdが公開しているインターフェイスを通じてDbgEngを使うことが出来ます。つまりImmunity DebuggerみたいにPythonスクリプトを使って色々弄れちゃいます。

pykdはオープンソースとして codeplex で公開されています。2011年4月現時点で 0.0.16 のアルファ版、生まれたばかりです。

boost/pythonをフル活用してたり、64bit対応が強く意識されていたりとかなり気合が入っているのですが、弱点があります。
英語ドキュメントが無い!
上のURL見てみれば分かりますが、トップページが既にキリル文字・・・つまり、ロシア語です。
ということで、Googleの翻訳機能を使うかソースを読んで自分で使い方を学ぶしかありません。まぁ若いプロジェクトですから、これからのドキュメントの充実に期待したいところです。

本記事ではpykdを自分の環境に合わせてビルドする方法と、pykdのソースに付属するサンプルをいくつか紹介してみます。
本当は「オリジナルのデバッガを作ってみる!」とかやってみたいんですけど、上述の通り英語ドキュメントが無くて手探り状態に加え、ソースを読むのにも前提となる知識が C++, Python拡張の作り方、boost/python, WinDBG拡張機能とかなりヘヴィで正直そこまで潜れませんでした(´Д⊂グスン。


ビルドとインストール

2011/04/02現在、公式からDL出来る pykd-0.0.16 (Alpha) バイナリはPython2.6を使うようにビルドされている。

他のバージョンのPythonで使いたい場合は自分でビルドする。

以下、ビルドメモ。

用意するもの:

  • お好みのバージョンのPython(公式のバイナリビルドが2.6使ってるので、2.6以上の方が良いかも)。
  • Visual C++ 2005 以上。Express EditionでOK。今回はVC++2008 Express Editionを使用。
  • WinDBG(Debugging Tools for Windows)、SDK付きでインストール。
  • Boost C++ : boost/pytho, boost/scoped_array を使用。

ビルドとインストールの概要:細かい部分は自分の環境に合わせて微調整してください。

1.ソースの入手
公式HPからSubversion or Team Foundationでチェックアウトできます。最新バージョンをzipでダウンロードも出来ます。好きな方で入手してください。

2.主なディレクトリ構成

pykd\
    pykd.sln   : VisualStudio用ソリューションファイル
    pykd\
        *.c, *.h, pykd.def, pykd.rc, resource.h
        make.bat    : コマンドプロンプトでビルドする時に使う。
        pykd.vcproj : プロジェクト設定ファイル
    lib\
        pykdlib\*.py : pykdのユーティリティモジュール
    samples\*.py  : pykdのサンプルその1
    snippets\*.py : pykdのサンプルその2

3.環境変数とパス調整

pykd.vcprojでは次のマクロを使っているので、自分の環境に合わせて定義+微調整します。
ヘッダーパス:

$(DBG_SDK_ROOT)\inc
$(BOOST_ROOT)
$(PYTHON_ROOT)\x86\include

ライブラリパス:

$(DBG_SDK_ROOT)\lib\i386
$(PYTHON_ROOT)\x86\libs
$(BOOST_ROOT)\stage\lib

マクロの追加方法:「表示」→「プロパティマネージャー」、プロジェクトを選択して「新しいプロジェクトプロパティシートの追加」、プロパティシートを開いて「共通プロパティ」→「ユーザーマクロ」で追加できます。(参考: http://d.hatena.ne.jp/Wacky/20100214 )
他、適当に自分の環境に合わせて微調整してください。

make.batを使う場合は中身を確認し、適当に環境変数を調整してください(make.batによるビルドは確認してません)。

4.ちょっとだけリソースファイルを修正

VC++2008 Express Editionでビルドしてみたところ、pykd.rcの

#include "afxres.h"

でヘッダーファイルが見つからずエラーになってしまいました。

上記を参考に

#include "windows.h"

に修正したらビルド出来ました。

5.pykd.pyd 他を手動で site-packages 以下にコピー

pykd.pyd -> site-packagesの直下
lib\pykdlib -> site-packagesの直下

6.とりあえずimport出来るかだけ確認
普通にpython.exeを起動してimportしてみます:

import pykd
import pykdlib

正常にimportできたら、続けてnotepad.exeでサンプルのPythonスクリプトを動かしてみましょう。

pykdをWinDBGで使ってみる

1.WinDBGでnotepad.exeを起動、適当なタイミングでCtrl-BREAKでデバッガにブレークする。

2.pykd.pyd(拡張子は".pyd"だが中身はDLL)をロードする。

0:002> .load C:\Python27\Lib\site-packages\pykd.pyd

3.samples\stacks.py でスタックを表示してみる。

0:002> !py C:\work\SVNWORK\codeplex\pykd\samples\stacks.py
ntdll!DbgBreakPoint  (776540f0)
ntdll!DbgUiRemoteBreakin+3c  (776bf161)
kernel32!BaseThreadInitThunk+e  (773e3c45)
ntdll!__RtlUserThreadStart+70  (776837f5)
ntdll!_RtlUserThreadStart+1b  (776837c8)

ntdll!DbgBreakPoint  (776540f0)
ntdll!DbgUiRemoteBreakin+3c  (776bf161)
kernel32!BaseThreadInitThunk+e  (773e3c45)
ntdll!__RtlUserThreadStart+70  (776837f5)
ntdll!_RtlUserThreadStart+1b  (776837c8)

ntdll!DbgBreakPoint  (776540f0)
ntdll!DbgUiRemoteBreakin+3c  (776bf161)
kernel32!BaseThreadInitThunk+e  (773e3c45)
ntdll!__RtlUserThreadStart+70  (776837f5)
ntdll!_RtlUserThreadStart+1b  (776837c8)

4.ntdllのEATを表示してみる(snippets\export.py)

0:002> !py C:\in_vitro\SVNWORK\codeplex\pykd\snippets\export ntdll
Module: ntdll base: 77620000 end: 7775c000
Export RVA: 36190  Size: f018
========================
A_SHAFinal
...

5.notepad.exeのIATを表示してみる(snippets\iat.py)

0:002> !py C:\in_vitro\SVNWORK\codeplex\pykd\snippets\iat notepad
Module: notepad base: 910000 end: 940000
IAT RVA: 1000  Size: 400
========================
ADVAPI32!RegSetValueExWStub
...

pykdのソースを読むコツ

ざっくりと目を通しただけですが、とりあえずソースを読むときのポイントを未来の自分用にメモしておきます。

・アーキテクチャ

PyDbgEngはcomtypesを経由してDbgEngのCOMを直接操作することが出来ます。

PyDbgEng(Python) -> comtypes(Python) -> ctypes(Python拡張機能) -> DbgEng COM

comtypesに読み込ませるTLBはDbgEngのヘッダファイルからPerlで変換して自動生成してます。この時、変換スクリプトの限界でいくつか動作しない箇所も発生してました。

pykdの場合はDbgEngのCOMには直接触れず、独自の公開インターフェイスを使うようになってます。

Pythonスクリプト
       |
-------+-----[ pykd.pyd ]--------------------------+
       |                                           |
       V                                           |
boost/pythonで公開しているPython用インターフェイス |
       |                                           |
       V                                           |
   C++コード <------> WinDBG拡張機能用callback <---+----> WinDBG
       |                                           |
-------+-------------------------------------------+
       |
       V
   DbgEng COM

pykdではDbgEngのCOMと直接対話することは出来ません。boost/pythonを使って公開されているPython用インターフェイスを使うしかありません。

・Python用インターフェイスの探し方
ではどうやってPython用に公開されているインターフェイスを探すのかというと、dbgext.cpp の BOOST_PYTHON_MODULE を読みます。

// pykdモジュールのインターフェイス定義の開始
BOOST_PYTHON_MODULE( pykd )
{
    // setExecutionStatus<DEBUG_STATUS_GO> を "go" というシンボルでPythonに公開
    boost::python::def( "go", &setExecutionStatus<DEBUG_STATUS_GO> );

このように、"boost::python::def"を目印に公開インターフェイスを探していきます。

ボトムアップであちこち調べるよりは dbgext.cpp でインターフェイスを特定してからその実体のソースを読む、という流れのほうが分かりやすいと思います。

・boost/python参考
とにもかくにも、boost/pythonを知らなければソースも読めません。
Python/Boost.Pythonメモ で紹介している本家や解説ページを参考に、ざっくりとでも良いのでboost/pythonに目を通しておきましょう。


最後に:
まだまだ若いプロジェクトですので今後どのように変化していくか未知数です。
将来、マルウェア解析やクラッシュダンプ解析の現場でpykdがバリバリ使われるようになると面白そうですね。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2011-04-04 22:43:44
md5:81c56980f4010685e8ef72b118549fd8
sha1:d3429b3882e04353bbf660a095fb5d80899280d6
コメント
コメントを投稿するにはログインして下さい。