Now, there are a couple of other considerations to take into account when picking whether to use the 32-bit or 64-bit DTW tools on 32-bit processes. Besides the ease of use consideration many third party extension DLLs (including SDbgExt, for the moment) are only available as 32-bit binaries. While these extension DLLs might support 64-bit targets, they will only run under a 32-bit debugger host.
I said I’d describe some of the reasons why debugging Wow64 processes under the native 64-bit debugger can be cumbersome. The main problem with doing this is that you need to be careful with whether the debugger is active as a 32-bit or 64-bit debugger. This is controlled by something that the DTW package calls the effective machine, which is a way to tell the debugger that it should be treating the program as a 32-bit or 64-bit program. If you are using the native 64-bit debugger on a Wow64 process, you will often find yourself having to manually switch between the native (x64) machine mode and the Wow64 (x86) mode.
To give you an idea of what I mean, let’s take a simple example of breaking into the 32-bit version of CMD.EXE, and getting a call stack of the first thread (thread 0). If you are experienced with the DTW tools, then you probably already know how to do this on x86-based systems: the “~0k” command, which means “show me a stack trace for thread 0″. If you run this on the 32-bit CMD.exe process, though, you won’t quite get what you were expecting:
0:000> ~0k Child-SP RetAddr Call Site 00000000`0013e318 00000000`78ef6301 ntdll!ZwRequestWaitReplyPort+0xa 00000000`0013e320 00000000`78bc0876 ntdll!CsrClientCallServer+0x9f 00000000`0013e350 00000000`78ba1394 wow64win!ReadConsoleInternal+0x236 00000000`0013e4c0 00000000`78be6866 wow64win!whReadConsoleInternal+0x54 00000000`0013e510 00000000`78b83c7d wow64!Wow64SystemServiceEx+0xd6 00000000`0013edd0 00000000`78be6a5a wow64cpu!ServiceNoTurbo+0x28 00000000`0013ee60 00000000`78be5e0d wow64!RunCpuSimulation+0xa 00000000`0013ee90 00000000`78ed8501 wow64!Wow64LdrpInitialize+0x2ed 00000000`0013f6c0 00000000`78ed6416 ntdll!LdrpInitializeProcess+0x17d9 00000000`0013f9d0 00000000`78ef3925 ntdll!LdrpInitialize+0x18f 00000000`0013fab0 00000000`78d59630 ntdll!KiUserApcDispatch+0x15 00000000`0013ffa8 00000000`00000000 0x78d59630 00000000`0013ffb0 00000000`00000000 0x0 00000000`0013ffb8 00000000`00000000 0x0 00000000`0013ffc0 00000000`00000000 0x0 00000000`0013ffc8 00000000`00000000 0x0 00000000`0013ffd0 00000000`00000000 0x0 00000000`0013ffd8 00000000`00000000 0x0 00000000`0013ffe0 00000000`00000000 0x0 00000000`0013ffe8 00000000`00000000 0x0
Hey, that doesn’t look like the 32-bit CMD at all! Well, the reason for the strange call stack is that the 32-bit CMD’s first thread is sleeping in a system call to the 64-bit kernel, and the last active processor state for that thread was native 64-bit mode, and NOT 32-bit mode. You will find that this is the common case for threads that are not spinning or doing actual work when you break in with the debugger.
In order to get the more useful 32-bit stack trace, we’ll have to use a debugger command that is probably unfamiliar to you if you haven’t done Wow64 debugging before: .effmach. This command controls the “effective machine” of the debugger, which I previously described. We’ll want to tell the debugger to show us the 32-bit state of the debugger, which we can do with the “.effmach x86″ command. Then, we can get a 32-bit stack trace for the first thread with the “~0k” command:
0:002> .effmach x86 Effective machine: x86 compatible (x86) 0:002:x86> ~0k ChildEBP RetAddr 002dfd68 7d542f32 KERNEL32!ReadConsoleInternal+0x15 002dfdf4 4ad0fe14 KERNEL32!ReadConsoleW+0x42 002dfe5c 4ad15803 cmd!ReadBufFromConsole+0xb5 002dfe88 4ad02378 cmd!FillBuf+0x174 002dfe8c 4ad02279 cmd!GetByte+0x11 002dfea8 4ad026c5 cmd!Lex+0x6b 002dfeb8 4ad02783 cmd!GeToken+0x20 002dfec8 4ad02883 cmd!ParseStatement+0x36 002dfedc 4ad164c0 cmd!Parser+0x46 002dff44 4ad04cdd cmd!main+0x1d6 002dffc0 7d4e6e1a cmd!mainCRTStartup+0x12f 002dfff0 00000000 KERNEL32!BaseProcessStart+0x28
Much better! That’s more in line with what we’d be expecting an idle CMD.EXE to be doing. We can now treat the target as a 32-bit process, including things like displaying and altering registry contexts, disassembling, and soforth. For instance:
0:002:x86> ~0s KERNEL32!ReadConsoleInternal+0x15: 00000000`7d54e9c3 c22000 ret 0x20 0:000:x86> r eax=00000001 ebx=002dfe84 ecx=00000000 edx=00000000 esi=00000003 edi=4ad2faa0 eip=7d54e9c3 esp=002dfd6c ebp=002dfdf4 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202 KERNEL32!ReadConsoleInternal+0x15: 00000000`7d54e9c3 c22000 ret 0x20 0:000:x86> u poi(esp) KERNEL32!ReadConsoleW+0x42: 00000000`7d542f32 8b4dfc mov ecx,[ebp-0x4] 00000000`7d542f35 5f pop edi 00000000`7d542f36 5e pop esi 00000000`7d542f37 5b pop ebx 00000000`7d542f38 e8545df9ff call KERNEL32!__security_check_cookie (7d4d8c91) 00000000`7d542f3d c9 leave 00000000`7d542f3e c21400 ret 0x14 00000000`7d542f41 90 nop
If we want to switch the debugger back to the 64-bit view of the process, we can use “.effmach .” to change to the native processor type:
0:000:x86> .effmach . Effective machine: x64 (AMD64)
Now, we’re back to 64-bit mode, and all of the debugger commands will reflect this:
0:000> r rax=000000000000000c rbx=000000000013e3a0 rcx=0000000000000000 rdx=00000000002df1f4 rsi=0000000000000000 rdi=00000000003e0cd0 rip=0000000078ef148a rsp=000000000013e318 rbp=00000000002dfdf4 r8=000000007d61c929 r9=000000007d61caf1 r10=0000000000000000 r11=00000000002df1f4 r12=00000000002dfe34 r13=0000000000000001 r14=00000000002dfe84 r15=000000004ad2faa0 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000244 ntdll!ZwRequestWaitReplyPort+0xa: 00000000`78ef148a c3 ret
That should give you a basic idea as to what you will be needing to do most of the time when you are doing Wow64 debugging. If you are running the 32-bit debugger packages, then all of this extra complexity is hidden and the process will appear to be a regular 32-bit process, with all of the transitions to Wow64 looking like 32-bit system calls (these typically happen in places like ntdll or user32.dll/gdi32.dll).