WOW64 デバッギング

ご無沙汰しております。なおきお~です。

少しずつ暖かくなり、過ごしやすい日が増えてきました。皆さん、如何お過ごしでしょうか?

暖かくなってきたとはいえ、季節の変わり目は、体調を崩しやすいので、お気を付けください。

 

春は、入学、入社など、新たな一歩を踏み出す季節でもあると思います。

新たな一歩というほど大げさなもの、新しいものではありませんが、今回は、WOW64 のデバッグの Tips を紹介したいと思います。

 

Windows 7 や Windows Server 2008 R2 のリリース以降、64 ビット Windows OS も浸透してきているように感じます。

ただ、32 ビットのアプリケーションは、まだまだ 多くあり、ユーザ モードのプロセスも含めて、完全に 64 ビットに移行できるのは、まだまだ 先のことになってしまうように思えます。

特に Windows OS に実装されている WOW64 は、完ぺきではないまでも、高い互換性を保持しているように思えます。

ただ、いざデバックをするとなると少々面倒になります。例えば、32 ビット プロセスに対して、64 ビットのメモリ ダンプを取得して、スタックが見られなかったり、カーネル モードのデバッギングの際で、32 ビット プロセスのコンテキストに合わせても、32 ビットのスタックが見られなかったりするなどです。

 

そんな時に、ちょっと便利な方法をユーザ モード デバッギングとカーネル モード デバッギングで、紹介します。

まず、ユーザ モード デバッギングでは、wow64exts.dll というデバッグ エクステンションを使用します。

このエクステンションは、ヘルプには記述されていないのですが、WinDbg のフォルダにあり、新たに入手する必要もありませんし、わざわざ .load でロードする必要はありません。

 

 

例えば、64 ビットの WinDbg で、以下のような、32 ビットの notepad.exe にアタッチします。

 

0:000> !peb

Wow64 PEB32 at 7efde000

    InheritedAddressSpace: No

    ReadImageFileExecOptions: No

    BeingDebugged: Yes

    ImageBaseAddress: 0000000000a50000

    Ldr 0000000077780200

    Ldr.Initialized: Yes

    Ldr.InInitializationOrderModuleList: 00000000002e2b08 . 00000000067d8698

    Ldr.InLoadOrderModuleList: 00000000002e2a78 . 00000000067d8688

    Ldr.InMemoryOrderModuleList: 00000000002e2a80 . 00000000067d8690

            Base TimeStamp Module

          a50000 4a5bc60f Jul 14 08:41:03 2009 c:\Windows\SysWOW64\notepad.exe

        77680000 4ec49b8f Nov 17 14:28:47 2011 C:\Windows\SysWOW64\ntdll.dll

        76760000 4e211318 Jul 16 13:27:04 2011 C:\Windows\syswow64\kernel32.dll

        76710000 4e211319 Jul 16 13:27:05 2011 C:\Windows\syswow64\KERNELBASE.dll

        76880000 4ce7b706 Nov 20 20:54:46 2010 C:\Windows\syswow64\ADVAPI32.dll

        76370000 4eeaf722 Dec 16 16:45:38 2011 C:\Windows\syswow64\msvcrt.dll

        766f0000 4a5bdb04 Jul 14 10:10:28 2009 C:\Windows\SysWOW64\sechost.dll

       751d0000 4ce7ba59 Nov 20 21:08:57 2010 C:\Windows\syswow64\RPCRT4.dll

        74d60000 4ec49b90 Nov 17 14:28:48 2011 C:\Windows\syswow64\SspiCli.dll

        74d50000 4a5bbf41 Jul 14 08:12:01 2009 C:\Windows\syswow64\CRYPTBASE.dll

        76ba0000 4ce7ba53 Nov 20 21:08:51 2010 C:\Windows\syswow64\GDI32.dll

        76920000 4ce7ba59 Nov 20 21:08:57 2010 C:\Windows\syswow64\USER32.dll

        75f20000 4a5bdb3b Jul 14 10:11:23 2009 C:\Windows\syswow64\LPK.dll

        76650000 4ce7ba29 Nov 20 21:08:09 2010 C:\Windows\syswow64\USP10.dll

        75fe0000 4ce7b82d Nov 20 20:59:41 2010 C:\Windows\syswow64\COMDLG32.dll

        762b0000 4ce7b9e2 Nov 20 21:06:58 2010 C:\Windows\syswow64\SHLWAPI.dll

---------- 省略 ----------

 

Wow64 PEB at 000000007efdf000

    InheritedAddressSpace: No

    ReadImageFileExecOptions: No

    BeingDebugged: Yes

    ImageBaseAddress: 0000000000a50000

    Ldr 00000000775d2640

    Ldr.Initialized: Yes

    Ldr.InInitializationOrderModuleList: 00000000001c2b30 . 00000000001c30e0

    Ldr.InLoadOrderModuleList: 00000000001c2a20 . 00000000001c3480

    Ldr.InMemoryOrderModuleList: 00000000001c2a30 . 00000000001c3490

            Base TimeStamp Module

          a50000 4a5bc60f Jul 14 08:41:03 2009 c:\Windows\SysWOW64\notepad.exe

        774a0000 4ec4aa8e Nov 17 15:32:46 2011 C:\Windows\SYSTEM32\ntdll.dll

        734c0000 4e212272 Jul 16 14:32:34 2011 C:\Windows\SYSTEM32\wow64.dll

        73460000 4e212275 Jul 16 14:32:37 2011 C:\Windows\SYSTEM32\wow64win.dll

        73450000 4e212273 Jul 16 14:32:35 2011 C:\Windows\SYSTEM32\wow64cpu.dll

---------- 省略 ----------

 

 

 

スレッドを見ても、64 ビットのスタックでのみであり、WOW64 より上の 32 ビットのスタックが見られません。

 

0:000> ~* kL

 

. 0 Id: a5c.a60 Suspend: 1 Teb: 00000000`7efdb000 Unfrozen

Child-SP RetAddr Call Site

00000000`0011d7c8 00000000`7345283e wow64cpu!CpupSyscallStub+0x9

00000000`0011d7d0 00000000`734cd07e wow64cpu!WaitForMultipleObjects32+0x3b

00000000`0011d890 00000000`734c8a40 wow64!RunCpuSimulation+0xa

00000000`0011d8e0 00000000`7349a3b4 wow64!Wow64KiUserCallbackDispatcher+0x204

00000000`0011dc30 00000000`774f1225 wow64win!whcbClientWaitMessageExMPH+0x58

00000000`0011e5e0 00000000`73452e09 ntdll!KiUserCallbackDispatcherContinue

00000000`0011e648 00000000`73452dbf wow64cpu!CpupSyscallStub+0x9

00000000`0011e650 00000000`734cd07e wow64cpu!Thunk0Arg+0x5

00000000`0011e710 00000000`734cc549 wow64!RunCpuSimulation+0xa

00000000`0011e760 00000000`774e4956 wow64!Wow64LdrpInitialize+0x429

00000000`0011ecb0 00000000`774e1a17 ntdll!LdrpInitializeProcess+0x17e4

00000000`0011f1a0 00000000`774cc32e ntdll!_LdrpInitialize+0x15687

00000000`0011f210 00000000`00000000 ntdll!LdrInitializeThunk+0xe

 

   1 Id: a5c.a64 Suspend: 1 Teb: 00000000`7efad000 Unfrozen

Child-SP RetAddr Call Site

00000000`0203eac8 00000000`7345283e wow64cpu!CpupSyscallStub+0x9

00000000`0203ead0 00000000`734cd07e wow64cpu!WaitForMultipleObjects32+0x3b

00000000`0203eb90 00000000`734cc549 wow64!RunCpuSimulation+0xa

00000000`0203ebe0 00000000`7751e707 wow64!Wow64LdrpInitialize+0x429

00000000`0203f130 00000000`774cc32e ntdll!_LdrpInitialize+0x52377

00000000`0203f1a0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

---------- 省略 ----------

 

 

# 20 Id: a5c.754 Suspend: 1 Teb: 00000000`7ef74000 Unfrozen

Child-SP RetAddr Call Site

00000000`0212fc48 00000000`77597ef8 ntdll!DbgBreakPoint

00000000`0212fc50 00000000`77504a00 ntdll!DbgUiRemoteBreakin+0x38

00000000`0212fc80 00000000`00000000 ntdll!RtlUserThreadStart+0x25

 

 

 

そこで、!wow64exts .k を使うと、64 ビットと 32 ビットのそれぞれのスタックが見ることができます。

 

0:000> ~0s

wow64cpu!CpupSyscallStub+0x9:

00000000`73452e09 c3 ret

0:000> !wow64exts .k

Walking 64bit Stack...

Child-SP RetAddr Call Site

00000000`0011d7c8 00000000`7345283e wow64cpu!CpupSyscallStub+0x9

00000000`0011d7d0 00000000`734cd07e wow64cpu!WaitForMultipleObjects32+0x3b

00000000`0011d890 00000000`734c8a40 wow64!RunCpuSimulation+0xa

00000000`0011d8e0 00000000`7349a3b4 wow64!Wow64KiUserCallbackDispatcher+0x204

00000000`0011dc30 00000000`774f1225 wow64win!whcbClientWaitMessageExMPH+0x58

00000000`0011e5e0 00000000`73452e09 ntdll!KiUserCallbackDispatcherContinue

00000000`0011e648 00000000`73452dbf wow64cpu!CpupSyscallStub+0x9

00000000`0011e650 00000000`734cd07e wow64cpu!Thunk0Arg+0x5

00000000`0011e710 00000000`734cc549 wow64!RunCpuSimulation+0xa

00000000`0011e760 00000000`774e4956 wow64!Wow64LdrpInitialize+0x429

00000000`0011ecb0 00000000`774e1a17 ntdll!LdrpInitializeProcess+0x17e4

00000000`0011f1a0 00000000`774cc32e ntdll!_LdrpInitialize+0x15687

00000000`0011f210 00000000`00000000 ntdll!LdrInitializeThunk+0xe

Walking 32bit Stack...

ChildEBP RetAddr

0009f9e8 76720bdd ntdll_77680000!NtWaitForMultipleObjects+0x15

0009fa84 76771a2c KERNELBASE!WaitForMultipleObjectsEx+0x100

0009facc 7694086a KERNEL32!WaitForMultipleObjectsExImplementation+0xe0

0009fb20 73f91717 USER32!RealMsgWaitForMultipleObjectsEx+0x14d

0009fb40 73f917b8 DUser!CoreSC::Wait+0x59

0009fb68 73f91757 DUser!CoreSC::WaitMessage+0x54

0009fb78 7697fceb DUser!MphWaitMessageEx+0x2b

0009fba4 7769010a USER32!__ClientWaitMessageExMPH+0x22

0009fc6c 75fe597b ntdll_77680000!KiUserCallbackDispatcher+0x2e

0009fcb8 00a53c2f COMDLG32!CFileOpenSave::Show+0x181

0009fcd0 00a53fdb notepad!ShowOpenSaveDialog+0x62

0009fcfc 00a53ef0 notepad!InvokeOpenDialog+0xba

0009fd74 00a517f7 notepad!NPCommand+0x147

0009fd90 769362fa notepad!NPWndProc+0x49f

0009fdbc 76936d3a USER32!InternalCallWinProc+0x23

0009fe34 769377c4 USER32!UserCallWinProcCheckWow+0x109

0009fe94 7693788a USER32!DispatchMessageWorker+0x3bc

0009fea4 00a514d7 USER32!DispatchMessageW+0xf

0009fed8 00a516ec notepad!WinMain+0xdd

0009ff68 7677339a notepad!__mainCRTStartup+0x140

0009ff74 776b9ef2 KERNEL32!BaseThreadInitThunk+0xe

0009ffb4 776b9ec5 ntdll_77680000!__RtlUserThreadStart+0x70

0009ffcc 00000000 ntdll_77680000!_RtlUserThreadStart+0x1b

 

 

 

特定のスレッドだけでなく、全スレッドの 32 ビットのスタックを見たい場合は、!wow64exts .sw を使用します。

あとは、通常の k コマンドで、全スレッドを見てみると、32 ビットのスタックになっています。

この状態で、ブレイク ポイントの設定など、従来の command も使用できますし、64 ビットに戻す場合は、再度 !wow64exts.sw を呼び出すだけですので、非常に簡単な操作です。

 

 

 

 

  

 

 

 

 

 

続いて、カーネル モード デバッギングは、wow64exts.dll を使う方法もありますが、もうちょっと、簡易的な方法を紹介いたします。

まず、ユーザ モード デバッギング同様に、64 ビットのスタックのみ表示され、WOW64 より上の 32 ビットのスタックが見られません。

 

2: kd> !process fffffa801940f7f0 1f

PROCESS fffffa801940f7f0

    SessionId: 1 Cid: 0a5c Peb: 7efdf000 ParentCid: 0a88

    DirBase: 53ee5000 ObjectTable: fffff8a002efa120 HandleCount: 300.

    Image: notepad.exe

    VadRoot fffffa8018f73870 Vads 221 Clone 0 Private 1807. Modified 93. Locked 0.

    DeviceMap fffff8a001b46770

    Token fffff8a003c80a90

    ElapsedTime 03:21:35.779

    UserTime 00:00:00.296

    KernelTime 00:00:00.358

    QuotaPoolUsage[PagedPool] 301752

    QuotaPoolUsage[NonPagedPool] 26344

    Working Set Sizes (now,min,max) (6817, 50, 345) (27268KB, 200KB, 1380KB)

    PeakWorkingSetSize 7307

    VirtualSize 154 Mb

    PeakVirtualSize 246 Mb

    PageFaultCount 9383

    MemoryPriority BACKGROUND

    BasePriority 8

    CommitCharge 3145

 

        THREAD fffffa801bfb1980 Cid 0a5c.0a60 Teb: 000000007efdb000 Win32Thread: fffff900c3010c20 WAIT: (UserRequest) UserMode Non-Alertable

            fffffa80193ed780 SynchronizationEvent

            fffffa801a97b6c0 SynchronizationEvent

        Not impersonating

        DeviceMap fffff8a001b46770

        Owning Process fffffa801940f7f0 Image: notepad.exe

        Attached Process N/A Image: N/A

        Wait Start TickCount 69519 Ticks: 100939 (0:00:26:14.658)

        Context Switch Count 3602 IdealProcessor: 2 LargeStack

        UserTime 00:00:00.936

  KernelTime 00:00:01.372

        Win32 Start Address notepad!WinMainCRTStartup (0x0000000000a53689)

        Stack Init fffff880061f3770 Current fffff880061f2980

        Base fffff880061f4000 Limit fffff880061e9000 Call fffff880061f39e0

        Priority 13 BasePriority 8 UnusualBoost 5 ForegroundBoost 0 IoPriority 2 PagePriority 5

        Kernel stack not resident.

        Child-SP RetAddr Call Site

        fffff880`061f29c0 fffff800`032906c2 nt!KiSwapContext+0x7a

        fffff880`061f2b00 fffff800`0329d2ea nt!KiCommitThreadWait+0x1d2

        fffff880`061f2b90 fffff800`035904bf nt!KeWaitForMultipleObjects+0x272

        fffff880`061f2e50 fffff800`035bd6fd nt!ObpWaitForMultipleObjects+0x294

        fffff880`061f3320 fffff800`03299fd3 nt!NtWaitForMultipleObjects32+0xec

        fffff880`061f3570 00000000`73452e09 nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff880`061f35e0)

        00000000`0011d7c8 00000000`7345283e wow64cpu!CpupSyscallStub+0x9

        00000000`0011d7d0 00000000`734cd07e wow64cpu!WaitForMultipleObjects32+0x3b

        00000000`0011d890 00000000`734c8a40 wow64!RunCpuSimulation+0xa

        00000000`0011d8e0 00000000`7349a3b4 wow64!Wow64KiUserCallbackDispatcher+0x204

        00000000`0011dc30 00000000`774f1225 wow64win!whcbClientWaitMessageExMPH+0x58

        00000000`0011e5e0 00000000`73452e09 ntdll!KiUserCallbackDispatcherContinue (TrapFrame @ 00000000`0011e4a8)

        00000000`0011e648 00000000`73452dbf wow64cpu!CpupSyscallStub+0x9

        00000000`0011e650 00000000`734cd07e wow64cpu!Thunk0Arg+0x5

        00000000`0011e710 00000000`734cc549 wow64!RunCpuSimulation+0xa

        00000000`0011e760 00000000`774e4956 wow64!Wow64LdrpInitialize+0x429

        00000000`0011ecb0 00000000`774e1a17 ntdll!LdrpInitializeProcess+0x17e4

        00000000`0011f1a0 00000000`774cc32e ntdll!_LdrpInitialize+0x15687

        00000000`0011f210 00000000`00000000 ntdll!LdrInitializeThunk+0xe

 

        THREAD fffffa801bbbf950 Cid 0a5c.0a64 Teb: 000000007efad000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Alertable

            fffffa8019fe5060 SynchronizationTimer

            fffffa8018f0d420 SynchronizationTimer

            fffffa801bbbf7e0 SynchronizationTimer

        Not impersonating

        DeviceMap fffff8a001b46770

        Owning Process fffffa801940f7f0 Image: notepad.exe

        Attached Process N/A Image: N/A

        Wait Start TickCount 69306 Ticks: 101152 (0:00:26:17.981)

        Context Switch Count 72 IdealProcessor: 3

        UserTime 00:00:00.015

        KernelTime 00:00:00.000

        Win32 Start Address ntdll_77680000!TppWaiterpThread (0x00000000776d2e25)

        Stack Init fffff88004ae1db0 Current fffff88004ae0fc0

        Base fffff88004ae2000 Limit fffff88004adc000 Call 0

        Priority 12 BasePriority 8 UnusualBoost 0 ForegroundBoost 2 IoPriority 2 PagePriority 5

        Kernel stack not resident.

        Child-SP RetAddr Call Site

        fffff880`04ae1000 fffff800`032906c2 nt!KiSwapContext+0x7a

        fffff880`04ae1140 fffff800`0329d2ea nt!KiCommitThreadWait+0x1d2

        fffff880`04ae11d0 fffff800`035904bf nt!KeWaitForMultipleObjects+0x272

        fffff880`04ae1490 fffff800`035bd6fd nt!ObpWaitForMultipleObjects+0x294

        fffff880`04ae1960 fffff800`03299fd3 nt!NtWaitForMultipleObjects32+0xec

        fffff880`04ae1bb0 00000000`73452e09 nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff880`04ae1c20)

        00000000`0203eac8 00000000`7345283e wow64cpu!CpupSyscallStub+0x9

        00000000`0203ead0 00000000`734cd07e wow64cpu!WaitForMultipleObjects32+0x3b

        00000000`0203eb90 00000000`734cc549 wow64!RunCpuSimulation+0xa

        00000000`0203ebe0 00000000`7751e707 wow64!Wow64LdrpInitialize+0x429

        00000000`0203f130 00000000`774cc32e ntdll!_LdrpInitialize+0x52377

        00000000`0203f1a0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

---------- 省略 ----------

 

 

 

そこで、.thread で対象のスレッドにコンテキストを設定する際に、 /w を指定すると、WOW64 上のスタックを確認することができます。

ユーザ モード デバッギングと同様に、この状態で、ブレイク ポイントの設定など、従来の command も使用できます。

 

2: kd> .thread /w fffffa801bfb1980

Implicit thread is now fffffa80`1bfb1980

WARNING: WOW context retrieval requires

switching to the thread's process context.

Use .process /p fffffa80`18d45b30 to switch back.

Implicit process is now fffffa80`1940f7f0

.cache forcedecodeuser done

The context is partially valid. Only x86 user-mode context is available.

x86 context set

2: kd:x86> kL

  *** Stack trace for last set context - .thread/.cxr resets it

ChildEBP RetAddr

0009f9e8 76720bdd ntdll_77680000!NtWaitForMultipleObjects+0x15

0009fa84 76771a2c KERNELBASE!WaitForMultipleObjectsEx+0x100

0009facc 7694086a kernel32!WaitForMultipleObjectsExImplementation+0xe0

0009fb20 73f91717 USER32!RealMsgWaitForMultipleObjectsEx+0x14d

0009fb40 73f917b8 DUser!CoreSC::Wait+0x59

0009fb68 73f91757 DUser!CoreSC::WaitMessage+0x54

0009fb78 7697fceb DUser!MphWaitMessageEx+0x2b

0009fba4 7769010a USER32!__ClientWaitMessageExMPH+0x22

0009fc6c 75fe597b ntdll_77680000!KiUserCallbackDispatcher+0x2e

0009fcb8 00a53c2f COMDLG32!CFileOpenSave::Show+0x181

0009fcd0 00a53fdb notepad!ShowOpenSaveDialog+0x62

0009fcfc 00a53ef0 notepad!InvokeOpenDialog+0xba

0009fd74 00a517f7 notepad!NPCommand+0x147

0009fd90 769362fa notepad!NPWndProc+0x49f

0009fdbc 76936d3a USER32!InternalCallWinProc+0x23

0009fe34 769377c4 USER32!UserCallWinProcCheckWow+0x109

0009fe94 7693788a USER32!DispatchMessageWorker+0x3bc

0009fea4 00a514d7 USER32!DispatchMessageW+0xf

0009fed8 00a516ec notepad!WinMain+0xdd

0009ff68 7677339a notepad!__mainCRTStartup+0x140

0009ff74 776b9ef2 kernel32!BaseThreadInitThunk+0xe

0009ffb4 776b9ec5 ntdll_77680000!__RtlUserThreadStart+0x70

0009ffcc 00000000 ntdll_77680000!_RtlUserThreadStart+0x1b

 

 

 

!wow64exts .sw と .thread で、64 ビットのコンテキストを設定すれば、64 ビットに戻すことができます。

 

 

2: kd:x86> !wow64exts .sw

Switched to 64bit mode

2: kd> .thread fffffa801bfb1980

Implicit thread is now fffffa80`1bfb1980

2: kd> kL

  *** Stack trace for last set context - .thread/.cxr resets it

Child-SP RetAddr Call Site

fffff880`061f29c0 fffff800`032906c2 nt!KiSwapContext+0x7a

fffff880`061f2b00 fffff800`0329d2ea nt!KiCommitThreadWait+0x1d2

fffff880`061f2b90 fffff800`035904bf nt!KeWaitForMultipleObjects+0x272

fffff880`061f2e50 fffff800`035bd6fd nt!ObpWaitForMultipleObjects+0x294

fffff880`061f3320 fffff800`03299fd3 nt!NtWaitForMultipleObjects32+0xec

fffff880`061f3570 00000000`73452e09 nt!KiSystemServiceCopyEnd+0x13

00000000`0011d7c8 00000000`7345283e wow64cpu!CpupSyscallStub+0x9

00000000`0011d7d0 00000000`734cd07e wow64cpu!WaitForMultipleObjects32+0x3b

00000000`0011d890 00000000`734c8a40 wow64!RunCpuSimulation+0xa

00000000`0011d8e0 00000000`7349a3b4 wow64!Wow64KiUserCallbackDispatcher+0x204

00000000`0011dc30 00000000`774f1225 wow64win!whcbClientWaitMessageExMPH+0x58

00000000`0011e5e0 00000000`73452e09 ntdll!KiUserCallbackDispatcherContinue

00000000`0011e648 00000000`73452dbf wow64cpu!CpupSyscallStub+0x9

00000000`0011e650 00000000`734cd07e wow64cpu!Thunk0Arg+0x5

00000000`0011e710 00000000`734cc549 wow64!RunCpuSimulation+0xa

00000000`0011e760 00000000`774e4956 wow64!Wow64LdrpInitialize+0x429

00000000`0011ecb0 00000000`774e1a17 ntdll!LdrpInitializeProcess+0x17e4

00000000`0011f1a0 00000000`774cc32e ntdll!_LdrpInitialize+0x15687

00000000`0011f210 00000000`00000000 ntdll!LdrInitializeThunk+0xe

 

 

 

ダンプ ファイルの解析でも、今回 紹介した live debugging (ユーザ モードとカーネル モード) と同様な方法で、32 ビットと 64 ビットを切り替えることができます。

このような感じで、32 ビット プロセスと 64 ビット プロセスが混在している環境でも、あまり手間をかけず、デバッギングすることができますので、もし、機会があれば、お試しください。

 

それでは、また。