« Win32デバッグ(10)・・・泣 | トップページ | Win32デバッグ(12)・・・SEH(Structured Exception Handling) »

2009年10月 6日 (火)

Win32デバッグ(11)・・・番外編

今回は寄り道。というより、前回までに示したコードに少し問題があった。

第1回で

  • ReadProcessMemory
  • WriteProcessMemory

を使えば、プロセスハンドルからそのプロセスのアドレス空間を読み書きできるし、また、

  • GetThreadContext
  • SetThreadContext

を使えば、スレッドハンドルからそのスレッドのコンテキスト(レジスタの値)を読み書きできる。

と書いたが、大切な事が抜けていたshock

ということで、例えば、あるスレッドが次に実行する命令を読み込むプログラムを上記のAPIを使って書いてみる。x86アキーテクチャではインストラクションポインタ(EIP)レジスタが次に実行される命令をポイントするので、例えば、次のようになる(繰り返すが、対象スレッドは停止してないとまずいと思う)。

x86命令は可変長の命令で何バイト読みこめばよいか?という問題があるが、上記のプログラムではとりあえず4バイト読み込んでいる。上記のプログラムを実際に動かすと正しく動いているように見えるが、問題があるのである。

何が問題かと言うと、ReadProcessMemory/WriteProcessMemoryの第2引数には読み書きするメモリの仮想アドレスを渡すのであり、上記のプログラムでは、EIPレジスタの値を渡しているのであるが、EIPレジスタの値は仮想アドレスの値ではないのである。EIPレジスタに格納されているのは確かにアドレスであるが、CSレジスタに格納されているセグメントセレクタによってポイントされるセグメント(コードセグメント)内の相対アドレス(segment-relative address)なのである。

ということで、仮想アドレスに変換する必要があるのであるが、そのために使うAPIがGetThreadSelectorEntryである。GetThreadSelectorEntryによって引数で指定したセグメントの仮想アドレス空間内のセグメントのベースアドレスが求まるので、それを使って正しく先ほどのプログラムを書き換えると次のようになる。

と、肝心な事を忘れたdash

ちなみに、最初に示したプログラムが動いてしまうのは、どうも、NT環境ではコードセグメントのベースアドレスが常に0になるからのようである。特にESPレジスタによってポイントされるスタックトップを読み書きするような場合、スレッド毎に異なるスタックセグメント(SSレジスタ)が割り当てられるので、なお更まずい。

« Win32デバッグ(10)・・・泣 | トップページ | Win32デバッグ(12)・・・SEH(Structured Exception Handling) »

Windows」カテゴリの記事

デバッグ」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1497665/39651701

この記事へのトラックバック一覧です: Win32デバッグ(11)・・・番外編:

« Win32デバッグ(10)・・・泣 | トップページ | Win32デバッグ(12)・・・SEH(Structured Exception Handling) »

自作ソフトウェア

無料ブログはココログ

メモ