#navi_header|Python| pykdはC言語で書かれたPython拡張で、WinDBG拡張機能の一部をPython経由で呼び出せます。 以前 [[935]] で紹介した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 のアルファ版、生まれたばかりです。 - Python extension for WinDbg -- http://pykd.codeplex.com/ boost/pythonをフル活用してたり、64bit対応が強く意識されていたりとかなり気合が入っているのですが、弱点があります。 ''英語ドキュメントが無い!'' 上のURL見てみれば分かりますが、トップページが既にキリル文字・・・つまり、ロシア語です。 ということで、Googleの翻訳機能を使うかソースを読んで自分で使い方を学ぶしかありません。まぁ若いプロジェクトですから、これからのドキュメントの充実に期待したいところです。 本記事ではpykdを自分の環境に合わせてビルドする方法と、pykdのソースに付属するサンプルをいくつか紹介してみます。 本当は「オリジナルのデバッガを作ってみる!」とかやってみたいんですけど、上述の通り英語ドキュメントが無くて手探り状態に加え、ソースを読むのにも前提となる知識が C++, Python拡張の作り方、boost/python, WinDBG拡張機能とかなりヘヴィで正直そこまで潜れませんでした(´Д⊂グスン。 #more|| #outline|| ---- * ビルドとインストール 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" でヘッダーファイルが見つからずエラーになってしまいました。 - Visual C++ 2008 Express Edition + WinRing0 -- http://crystaldew.info/2007/12/19/visual-c-2008-express-edition-winring0/ - Momma's Wiki: Windows/VisualC/2008 - Visual C++ 2008 Express Editionについて -- http://www.eml.ele.cst.nihon-u.ac.jp/~momma/wiki/wiki.cgi/Windows/VisualC/2008.html 上記を参考に #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 でスタックを表示してみる。 #pre||> 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) #pre||> 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) #pre||> 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には直接触れず、独自の公開インターフェイスを使うようになってます。 #pre||> 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 を読みます。'' #code|c|> // pykdモジュールのインターフェイス定義の開始 BOOST_PYTHON_MODULE( pykd ) { // setExecutionStatus を "go" というシンボルでPythonに公開 boost::python::def( "go", &setExecutionStatus ); ||< このように、"boost::python::def"を目印に公開インターフェイスを探していきます。 ボトムアップであちこち調べるよりは dbgext.cpp でインターフェイスを特定してからその実体のソースを読む、という流れのほうが分かりやすいと思います。 ・boost/python参考 とにもかくにも、boost/pythonを知らなければソースも読めません。 [[938]] で紹介している本家や解説ページを参考に、ざっくりとでも良いのでboost/pythonに目を通しておきましょう。 ---- 最後に: まだまだ若いプロジェクトですので今後どのように変化していくか未知数です。 将来、マルウェア解析やクラッシュダンプ解析の現場でpykdがバリバリ使われるようになると面白そうですね。 #navi_footer|Python|