モチベーション

Windowsアプリケーションのプロセスにデバッガをアタッチしてその動きを追いたい

前提条件

  • コンピュータの仕組みやバイナリ関連の基礎を身に付けていること

※ 自信がない場合は本記事下部のおまけを参考にする。

WinDBGをつかってメモ帳をデバッグしてみる

Windowsで使えるデバッガは色々あり、OllyDebugなんかはUIがユーザフレンドリで使いやすく多くのユーザに使われている。一方で、WinGDBはユーザビリティが良いとは言えないものの、Microsoft公式のデバッガであり、64bitアプリケーションのデバッグにも使える。今回は、WinGDBをつかってメモ帳のデバッグを行う。

環境準備

Windows環境を用意する

modern.IEから評価用Windowsをダウンロードして仮想化ツール、Virtualboxで起動する。IE8 on Win7、VirtualBoxを選択してインストールする。

WinDBGをインストールする

Microsoft Download CenterからWinDBGをダウンロードする。WinDBGはMicrosoft Windows SDKの中の1つのコンポーネントとして含まれており、SDKのインストーラでDebugging Toolsだけを選択すればWinDGBのみをインストールできる。また、cmd.exeからWinDBGを実行できるように以下の環境変数を設定する。

  • 環境変数名:PATH(既存のPATHの末尾に値を追加)
  • 値:C:\Program Files\Debugging Tools for Windows(x86)\

シンボルファイルのインストールとパスの設定

シンボルファイルとはソースコード、行番号、変数名、データ型などのプログラムの情報を格納しているファイルであり、デバッグに必要な情報(シンボル)が含まれたファイルのこと。拡張子はpdb(Program DataBase files)。デバッガとシンボルファイルリンクさせることで、デバッグでより詳細な情報を確認できる。インストールはWindows シンボル パッケージのダウンロードから行う。

また、都度WinDBGでパスの設定をするのは面倒なので、Use the Microsoft Symbol Server to obtain debug symbol filesを参考に環境変数にシンボルへのパスを設定する。

  • 環境変数名:_NT_SYMBOL_PATH
  • 値:SRV*c:\Symbols*http://msdl.microsoft.com/download/symbols

WinDBGでメモ帳をデバッグする

プロセスにデバッガをアタッチする

まずはnotepad.exeにWinDBGをアタッチする。

  1. notepade.exeを起動する
  2. windbg.exeを起動する
  3. WinDBGのウィンドウからFile > Attach to a Process > notepad.exeよりプロセスにデバッガをアタッチする

プロセスにデバッガをアタッチするとはじめはエントリポイントでブレーク状態になる。プロセスを動かしたいときはgを入力してブレーク状態を解放する。また、デバッガでプロセスの情報を確認したい場合は、WinDBGのBreakボタンをクリックする。この繰り返しがライブデバッグの基本的な流れとなる。

notepadに入力した文字列がメモリのどこに格納されているか確認する

notepadに入力した文字列はファイルに保存しないとデータとしては残らないと思われがちがだが、実際にはキーボードから入力した瞬間からメモリに展開される。これを確認するには、notepadeに”hello”という文字列を入力した後に以下のコマンドを実行する。

0:001> s -u 0 L?80000000/2 "hello"
0037f3e0  0068 0065 006c 006c 006f 0000 0000 0000  h.e.l.l.o.......

notepadeが読み込まれているメモリを確認する

プログラムが展開されているメモリをかくにんするにはlmfコマンドを使う。特に、特定のプロセスのみを指定したい場合は以下のように、lmf m プロセス名とする。

0:001> lmf m notepad
start    end        module name
00ea0000 00ed0000   notepad  C:\Windows\system32\notepad.exe

レジスタの値を確認する

現在のレジスタの値を確認するにはrコマンドを実行する。

0:001> r
eax=7ffdd000 ebx=00000000 ecx=00000000 edx=777ff1d3 esi=00000000 edi=00000000
eip=77794108 esp=0083f904 ebp=0083f930 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
77794108 cc              int     3
0:001> r eax
eax=7ffdd000

メモリの中身を確認する

ダブルワードでメモリを確認するにはdd、ASCIIで確認するにはdaコマンドを使う。

0:001> dd
0037f3e4  006c006c 0000006f 00000000 00000000
0037f3f4  00000000 00000000 00000000 00000000
0037f404  00000000 00000000 00000000 00000000
0037f414  00000000 00000000 00000000 00000000
0037f424  00110004 0835ad16 08004ae7 00000000
0037f434  00000000 2935ad37 0c004aef 74793e54
0037f444  0007019a 00000000 00000000 00000000
0037f454  00000000 00000000 00000000 00000000
0:001> da 0037f3e0
0037f3e0  "h"

コールスタックを確認する

現在トレースしている場所を確認するにはtコマンドを使う。

0:001>  t
eax=7ffdd000 ebx=00000000 ecx=00000000 edx=777ff1d3 esi=00000000 edi=00000000
eip=77794109 esp=0083f904 ebp=0083f930 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!DbgBreakPoint+0x1:
77794109 c3              ret

また、コールスタックを確認する場合はKを入力する。

0:001> K
ChildEBP RetAddr  
0083f900 777ff20f ntdll!DbgBreakPoint+0x1
0083f930 7666ee1c ntdll!DbgUiRemoteBreakin+0x3c
0083f93c 777c37eb kernel32!BaseThreadInitThunk+0xe
0083f97c 777c37be ntdll!__RtlUserThreadStart+0x70
0083f994 00000000 ntdll!_RtlUserThreadStart+0x1b

ディスアセンブルする

ディスアセンブル結果を出力するにはu "アドレス"とする。アドレスを指定しない場合はeipが指すアドレスからディスアセンブル結果を表示する。

ntdll!DbgBreakPoint+0x1:
77794109 c3              ret
7779410a 90              nop
7779410b 90              nop
ntdll!RtlInitString:
7779410c 57              push    edi
7779410d 8b7c240c        mov     edi,dword ptr [esp+0Ch]
77794111 8b542408        mov     edx,dword ptr [esp+8]
77794115 c70200000000    mov     dword ptr [edx],0
7779411b 897a04          mov     dword ptr [edx+4],edi

おまけ:最低限のバイナリ関連の知識を身に付ける

いきなりWinDBGを触っても良いが、バイナリ関連の基礎を身に付けた上でWinDBGでのデバッグにつなげて行きたい。色々読んだが、以下だけ実施すればとりあえずOK。あとは実践形式で学習していく。

Step1:レジスタ周辺の用語に慣れる

はじめは用語もわからないのでスタックやレジスタに纏わる単語を理解する。

Step2:バイナリ周りの体系的な知識を養う書籍

用語になれた所で体系的に基礎を身につけるためにバイナリ周辺知識について体系的にまとめている書籍を幾つか読む。Hacking: 美しき策謀 第2版 ―脆弱性攻撃の理論と実際はLinuxを対象にバイナリ関連の知識を身に付けられる。時間が無い時は2章だけ読む。デバッガによるx86プログラム解析入門【x64対応版】はWindowsが対象。

参考

WinDBG Tutorial