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

技術/Windows/WinDbgメモ (v3)

技術/Windows/WinDbgメモ (v3)

技術 / Windows / WinDbgメモ (v3)
id: 706 所有者: msakamoto-sf    作成日: 2010-07-13 23:53:23
カテゴリ: WinDBG Windows プログラミング 

WinDBG参考図書:

※"AWD"サンプルコードのシンボルパスについて
本書中で紹介されているURLは2011年1月の時点でアクセス不能になっている。

http://www.advancedwindowsdebugging.com/symbols/symstore.pri

このため、"AWD"公式HPからダウンロードしたプライベートシンボルファイルをローカルPC上に展開し、そちらへのパスをシンボルパスに設定する必要がある。


WinDBGやWindowsデバッグ関連参考サイト:



簡単なBATファイルを作っておくと便利

デバッグ対象のEXEのあるディレクトリなど、適当なディレクトリにそのプロジェクト専用のWinDbg起動用BATファイルを作っておくと便利かもしれない。"_NT_"で始まる実行イメージやソース、シンボルディレクトリの環境変数を定義したり、windbgのコマンドラインオプションを埋め込んでおく。

windbg.bat:

@echo off
cd /d %~dp0

set PATH=C:\WinDDK\7600.16385.1\Debuggers;%PATH%
set _NT_SYMBOL_PATH=cache*C:\temp\symcache;srv*http://msdl.microsoft.com/download/symbols;.
set _NT_EXECUTABLE_IMAGE_PATH=.
set _NT_SOURCE_PATH=.
set _NT_DEBUG_LOG_FILE_APPEND=windbg.log

start windbg.exe -srcpath %_NT_SOURCE_PATH% -loga %_NT_DEBUG_LOG_FILE_APPEND% -WF foo.wew debugee.exe arg1 arg2 ...

"_NT_SYMBOL_PATH"については各自の環境に応じて調整する。cacheを入れておくと良い。
わざわざ"-srcpath"を指定しているのは、環境変数で"_NT_SOURCE_PATH"を指定してもGUI("File" -> "Source File Path ...")に反映ず、"-srcpath"で指定すればちゃんと反映されたため。

"-WF"でWorkspace設定を読み込ませるようにしているが、WinDbg終了時に"File" -> "Save Workspace"を実行しておかないと保存されない=意味無しので注意。終了時に自動保存してくれると楽なんだけど。

VMware上のゲストWindowsOSのカーネルデバッグ接続(Named Pipe)

ホストOS側での設定
VMwareマシンの設定でシリアルポートを追加する。「接続」で「名前付きパイプを使用する」を設定。「この端末はサーバです。」「接続先はアプリケーションです。」の組み合わせに設定する。
ゲストOS側での設定
技術/Windows/WinDbgメモ を参考にゲストOS側を COM1 でカーネルデバッガの接続を有効にして起動する。
接続

ホストOS側:

windbg -k com:pipe,port=\\.\pipe\xxxxyyyy

カーネルデバッグ中にEXEファイルのシンボルをロードしたい

AWDの第三章では、プロセスが例外やDebugBreakし、カーネルデバッガに制御が渡るシナリオが紹介されています。
サンプルとして提示されているコマンド実行結果では、バックトレースの中に例外を発行した02sample.exeのシンボルが表示されています。

実際に試してみると、カーネルデバッガにブレークした時点では特定のプロセスのEXEファイル(今回なら02sample.exe)のシンボルをロード出来ませんでした。こんなエラーになっちゃいます:

kd> !reload -f 02sample.exe

"02sample.exe" was not found in the image list.
Debugger will attempt to load "02sample.exe" at given base 00000000.

Please provide the full image name, including the extension (i.e. kernel32.dll)
for more reliable results.Base address and size overrides can be given as
.reload <image.ext>=<base>,<size>.
DBGENG:  02sample.exe - Partial symbol image load missing image info
...
Unable to add module at 00000000

色々試行錯誤してみたところ、".thread"メタコマンドに"/p"オプションを付けてコンテキストを切り替えると上手くいきました。
多分、特定プロセスのコンテキストに切り替わったためにEXEのメモリイメージを認識し、シンボルファイルを検索できるようになったんだと思います。

例:"AWD"第二章で使われている02sample.exeのシンボルファイルをKD上でロードしてみます。

1.まずスレッドアドレスを見つけます。

kd> !process 0 4 02sample.exe
PROCESS 81e4c020  SessionId: 0  Cid: 0474    Peb: 7ffdf000  ParentCid: 0278
    DirBase: 09bc0420  ObjectTable: e1837878  HandleCount:   7.
    Image: 02sample.exe

        THREAD 8203a810  Cid 0474.0ee0  Teb: 7ffde000 Win32Thread: 00000000 WAIT
        ^^^^^^^^^^^^^^^

2.".thread /p"でコンテキストを切り替えます。ついでに"/r"も付けて、ロード出来るシンボルファイルはロードさせちゃいます。

kd> .thread /p /r 8203a810
Implicit thread is now 8203a810
Implicit process is now 81e4c020
.cache forcedecodeuser done
Loading User Symbols
....
(ntdll.dllのシンボルファイルのロードメッセージ。
 "!sym noisy"に設定してたから出力されたのかも。)

3.バックトレースの表示をトリガーにして、02sample.exeのシンボルをロードしてみる。

kd> k
  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr  
b1f5a42c 80502cf0 nt!KiSwapContext+0x2e
b1f5a438 804fbd72 nt!KiSwapThread+0x46
b1f5a460 8063afc4 nt!KeWaitForSingleObject+0x1c2
b1f5a540 8063c099 nt!DbgkpQueueMessage+0x17c
b1f5a564 8063c1cb nt!DbgkpSendApiMessage+0x45
b1f5a5f0 804feccc nt!DbgkForwardException+0x8f
b1f5a9b0 8050245b nt!KiDispatchException+0x37e
b1f5ad34 80542ec1 nt!KiRaiseException+0x175
b1f5ad50 8053f668 nt!NtRaiseException+0x31
b1f5ad50 7c812afb nt!KiFastCallEntry+0xf8
(kernel32.dllのシンボルロードメッセージ)
0006ff04 77bd272c kernel32!RaiseException+0x53
(02sample.exeのシンボルロードメッセージ)
0006ff44 010016eb msvcrt!_CxxThrowException+0x36
0006ff58 01001d63 02sample!RaiseCPP+0x1b [c:\awd\chapter2\sample.cpp @ 50]
0006ff70 01001c7b 02sample!AppInfo::Loop+0xb3 [c:\awd\common\menu.h @ 47]
0006ff7c 01002038 02sample!wmain+0x1b [c:\awd\chapter2\sample.cpp @ 228]
0006ffc0 7c817077 02sample!__wmainCRTStartup+0x102 [d:\vistartm\base\crts\crtw32\dllstuff\crtexe.c @ 711]
0006fff0 00000000 kernel32!BaseProcessStart+0x23

02sampleのシンボルがロードされシンボル解決出来たことが分かりました。

オンライン(=Live)カーネルデバッグでユーザープロセス・スレッドにコンテキストを切り替えたい

基本の流れ:

  1. "!session"コマンドで現在ログイン中のセッションを確認
  2. "!sprocess" or "!process"コマンドでプロセスを検索
  3. ".process"コマンドでプロセスコンテキストを切り替え
  4. ".thread"コマンドでスレッドコンテキストを切り替え
  5. スタック、レジスタの確認、ブレークポイント設定など

例1:AWDの第二章サンプル(02sample.exe)のプロセスにコンテキストを切り替えてみる:

######## ログインセッションは一つしか無かったので、"!process"コマンドで02sample.exeを検索
kd> !process 0 0 02sample.exe
PROCESS 81cfb268  SessionId: 0  Cid: 0b68    Peb: 7ffda000  ParentCid: 09cc
    DirBase: 09c40360  ObjectTable: e226bd20  HandleCount:   9.
    Image: 02sample.exe

PROCESS 820a7340  SessionId: 0  Cid: 0bec    Peb: 7ffde000  ParentCid: 09cc
    DirBase: 09c40280  ObjectTable: e1c44c98  HandleCount:   9.
    Image: 02sample.exe

######## Process Address (EPROCESS) 0x820a7340 に切り替えてみる。
kd> .process 820a7340  
Implicit process is now 820a7340
kd> .context
User-mode page directory base is 9c40280

######## Process Environment Block (PEB)を見てみる。ちゃんと02sample.exeになってる。
kd> !peb
PEB at 7ffde000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            No
    ImageBaseAddress:         01000000
    Ldr                       00181e90
    Ldr.Initialized:          Yes
    Ldr.InInitializationOrderModuleList: 00181f28 . 00182070
    Ldr.InLoadOrderModuleList:           00181ec0 . 00182060
    Ldr.InMemoryOrderModuleList:         00181ec8 . 00182068
            Base TimeStamp                     Module
         1000000 472187dc Oct 26 15:23:24 2007 C:\awdbin\WinXP.x86.chk\02sample.exe

######## "!process"コマンドで直接EPROCESSを指定して確認してみる。
kd> !process 820a7340 2
PROCESS 820a7340  SessionId: 0  Cid: 0bec    Peb: 7ffde000  ParentCid: 09cc
    DirBase: 09c40280  ObjectTable: e1c44c98  HandleCount:   9.
    Image: 02sample.exe

        THREAD 81c35b90  Cid 0bec.082c  Teb: 7ffdd000 ...
            81c35d84  Semaphore Limit 0x1

kd> !thread 81c35b90  
THREAD 81c35b90  Cid 0bec.082c  Teb: 7ffdd000 ...
    81c35d84  Semaphore Limit 0x1
Waiting for reply to LPC MessageId 00009d87:
Current LPC port e113ec50
Not impersonating
DeviceMap                 e1884720

######## Thread Address (ETHREAD) 0x81c35b90 に切り替えてみる。
kd> .thread 81c35b90  
Implicit thread is now 81c35b90

######## スタックトレースを確認:ちゃんと02sample.exeのスタックになっている。
kd> k
  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr  
b1946c68 80502cf0 nt!KiSwapContext+0x2e
...
0006ff70 01001c7b 02sample!AppInfo::Loop+0x70 [c:\awd\common\menu.h @ 38]
0006ff7c 01002038 02sample!wmain+0x1b [c:\awd\chapter2\sample.cpp @ 228]
...

例2:手っ取り早くスタックトレースを確認してみる。

########### まず02sample.exeのEPROCESS, ETHREADを確認。
kd> !process 0 2 02sample.exe
PROCESS 81cfb268  SessionId: 0  Cid: 0b68    Peb: 7ffda000  ParentCid: 09cc
    DirBase: 09c40360  ObjectTable: e226bd20  HandleCount:   9.
    Image: 02sample.exe

        THREAD 81be5b80  Cid 0b68.0b6c  Teb: 7ffdf000 Win32Thread: 00000000 WAIT: (WrLpcReply) UserMode Non-Alertable
            81be5d74  Semaphore Limit 0x1


PROCESS 820a7340  SessionId: 0  Cid: 0bec    Peb: 7ffde000  ParentCid: 09cc
    DirBase: 09c40280  ObjectTable: e1c44c98  HandleCount:   9.
    Image: 02sample.exe

        THREAD 81c35b90  Cid 0bec.082c  Teb: 7ffdd000 Win32Thread: 00000000 WAIT: (WrLpcReply) UserMode Non-Alertable
            81c35d84  Semaphore Limit 0x1

########## ";" でつなげて一気にプロセス・スレッド両コンテキストを切り替える。
kd> .process /p 820a7340; .thread /p 81c35b90 ; .context
Implicit process is now 820a7340
.cache forcedecodeuser done
Implicit thread is now 81c35b90
Implicit process is now 820a7340
.cache forcedecodeuser done
User-mode page directory base is 9c40280

########## スタックトレースの確認→02sample.exeのものになっている。
kd> k
  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr  
b1946c68 80502cf0 nt!KiSwapContext+0x2e
...
0006ff70 01001c7b 02sample!AppInfo::Loop+0x70 [c:\awd\common\menu.h @ 38]
0006ff7c 01002038 02sample!wmain+0x1b [c:\awd\chapter2\sample.cpp @ 228]
...

".process", ".thread" で "/p" オプションがあったりなかったりしますが、WinDBGのヘルプを見てみると、オンラインデバッグの場合は"/p"オプションを付けたほうが良いようです。例ではEPROCESSやETHREAD・スタックトレースを確認出来れば良いので、付けたり付けなかったりしてます。

オンライン(=Live)カーネルデバッグでユーザープロセスにブレークポイント設定→ステップ実行

指定のプロセス・スレッドに切り替えるところまでは上と同じです。一点違うのは、".process"コマンドに"/i"オプションを付けることです。これが無いと、ユーザープロセスがブレークポイントを踏んだ時にカーネルデバッガがbreakしてくれませんでした。

kd> !process 0 2 02sample.exe
PROCESS 81bd1020  SessionId: 0  Cid: 0ff0    Peb: 7ffdf000  ParentCid: 09cc
    DirBase: 09c40360  ObjectTable: e20bfad8  HandleCount:   7.
    Image: 02sample.exe

        THREAD 81d1e020  Cid 0ff0.0ff4  Teb: 7ffde000 ...
            81d1e214  Semaphore Limit 0x1


PROCESS 820c29f0  SessionId: 0  Cid: 03d4    Peb: 7ffdf000  ParentCid: 09cc
    DirBase: 09c40280  ObjectTable: e1d34bb0  HandleCount:   7.
    Image: 02sample.exe

        THREAD 81cff450  Cid 03d4.01d8  Teb: 7ffde000 ...
            81cff644  Semaphore Limit 0x1

kd> .process /i 820c29f0; .thread 81cff450; .context
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
Implicit thread is now 81cff450
User-mode page directory base is b1f000
kd> k
  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr  
b1a56c68 80502cf0 nt!KiSwapContext+0x2e
...
0006ff70 01001c7b 02sample!AppInfo::Loop+0x70 [c:\awd\common\menu.h @ 38]
0006ff7c 01002038 02sample!wmain+0x1b [c:\awd\chapter2\sample.cpp @ 228]
...

02sample.exeのOutputDebug関数にブレークポイントを設定してみます。"/p"と"/t"でProcessAddress, ThreadAddress両方を指定する必要がありました。

kd> x 02sample!OutputDebug
01001c30 02sample!OutputDebug (void)

kd> bp /p 820c29f0 /t 81cff450 02sample!OutputDebug

kd> bl
 0 e 01001c30     0001 (0001) 02sample!OutputDebug
     Match thread data 81cff450  Match process data 820c29f0

kd> g
########### ".process /i"オプションにより一旦breakしますので、再度"g"で再開させます。

Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
80529c0c cc              int     3
kd> g

これで、指定されたプロセス・スレッドがOutputDebug関数に入るとカーネルデバッガにbreakします。あとは"t"や"p"コマンドなど一般的なデバッグコマンドを使ってユーザープロセスをデバッグできます。



プレーンテキスト形式でダウンロード
表示中のバージョン : 3
現在のバージョン : 4
更新者: msakamoto-sf
更新日: 2011-04-02 16:20:23
md5:9123980af015bc226aa10f3e7ac95eee
sha1:34816289eb1bde671758a04cf640e45743d67f6b
コメント
コメントを投稿するにはログインして下さい。