Search code examples
debuggingwindbgsos

Is there a Windbg command to find out if a process is a 32-bit one or a 64-bit one?


Is there a Windbg/NTSD command to tell me if a process I have attached to in a live debugging session is a 32-bit one or a 64-bit one?

Could you please tell me for both:

  1. An unmanaged process?

and

  1. A managed one?

For a managed one, I can find that out programmatically in C# but still I'd like to know if there's a Windbg command for this.

UPDATE

The target process I am debugging is Microsoft Word (winword.exe). The Office version is 2016 but I am not sure if it is a 32-bit or a 64-bit binary. Here are some observations:

  1. The target location is C:\Program Files (x86)\Microsoft Office\root\Office16\WinWord.exe

  2. The pipe (|) command tells me nothing more than PID, whether the process is attached to the debugger or not and the path from where the image is loaded (as noted in #1 above).

  3. I am debugging this on a 64-bit machine. So, r reveals 64-bit registers.

  4. Upon attaching to a live, healthy process with no crashes (I just opened MS Word and said "Attach to Process"), the callstack for the current thread (k) reads wow64cpu!CpupSyscallStub+0x9 for the top-most call. This, with #1 suggests that the process is a 32-bit process.

Commands already tried

  1. !peb (Process Environment Block): Tells us the PROCESSOR ARCHITECTURE, not the bitness of the process being debugged.
  2. |
  3. vertarget
  4. r (indicates register size for my processor and does not tell me about the process)

But I'm wondering if there's a way to find out.


Solution

  • 32 bit / 64 bit decision

    For a quick test I often use

    lm m wow64
    

    which checks if the WOW64 layer was loaded. If so, it's a 32 bit process.

    This approach works in many cases, because OS is likely 64 bit today. However, you could also have a 32 bit dump of a 32 bit OS, in which case this approach does not work well.

    A more authorative approach is

    .load wow64exts
    !info
    

    which gives a lot of output unfortunately, so it'll be hard to use in a script.

    The 32 bit output looks like

    0:000> !info
    
    PEB32: 0xe4d000
    PEB64: 0xe4c000
    
    Wow64 information for current thread:
    
    TEB32: 0xe50000
    TEB64: 0xe4e000
    
    [...]
    

    In case of 64 bit it is

    0:000> !info
    Could not get the address of the 32bit PEB, error 0
    
    PEB32: 0
    PEB64: 0x6b33c50000
    
    Wow64 information for current thread:
    
    TEB32: 0
    TEB64: 0x6b33c51000
    
    [...]
    

    I don't have a 32 bit Windows OS dump available, but I assume it's safe to say that

    • if PEB32 is not 0, it's a 32 bit process.
    • if PEB64 is 0, it's a 32 bit OS

    If you know the module name, you can also inspect the file headers:

    0:000> .shell -ci "!dh -f notepad" findstr "machine"
        8664 machine (X64)
    .shell: Process exited
    

    Things that do not work

    vertarget as suggested in the comments does not work well for 64 bit crash dumps of 32 bit applications.

    $ptrsize would have been so nice, but it depends on the debugger mode:

    0:000> ? $ptrsize
    Evaluate expression: 8 = 00000000`00000008
    0:000> .effmach x86
    Effective machine: x86 compatible (x86)
    0:000:x86> ? $ptrsize
    Evaluate expression: 4 = 00000004
    

    .NET decision

    Similar to the WOW64 layer, you can check for .NET:

    lm m mscorwks
    lm m clr
    lm m coreclr
    

    Of course it might be possible to load such a DLL via LoadLibrary() from native code directly and not using .NET, but I think that's a rare usage of someone who wants to fool you.