Search code examples
pythonwindbgpykd

Get the executable's module in PyKD


In PyKD I can get the executable's process name like this:

0:017> !py
...
>>> getProcessExeName()
u'C:\\Windows\\SysWOW64\\rundll32.exe'

and I can get module information with

>>> print module("rundll32")
Module: rundll32
Start: 7f0000 End: 7fe000 Size: e000
Image: C:\Windows\SysWOW64\rundll32.exe
Symbols: e:\debug\symbols\rundll32.pdb\EFAE0C870C2846EDB63B9A7274CD50422\rundll32.pdb
Timestamp: 4a5bc637
Check Sum: 11cf2

How do I convert from the process name to the module name?

It's not as simple as extracting the file name, since file names with special characters like Notepad++.exe converts to notepad__ as module name.

Background: I want to automate dump analysis and first I check whether it's my program at all and second I want to check the version of the crashed program for which I need the module information. I want to make it a bit more universal and consider the case that the user renames the executable.

Versions (if that matters): PyKD 0.3.0.25, 32 bit, WinDbg 6.2.9200, Python 2.7.8


Solution

  • Your issue is actually more insidious than you describe. I've seen where modules loaded using their short (MSDOS compatible) name are mangled even more.

    The only thing I can come up with to answer your question is a bit of a hack. If you assume that the module occupying the lowest address space is the executable's module, then you can use lm with the 1m flag to list all modules but only use the first one.

    This means you can do:

    0:001> !py c:\test.py
    Module: notepad__
    Start: 10000 End: 21c000 Size: 20c000
    Image: C:\Program Files (x86)\Notepad++\notepad++.exe
    Symbols: export symbols
    Timestamp: 55ad8d3e
    Check Sum: 0
    

    Where test.py is:

    from pykd import *
    
    exeModuleName = dbgCommand("lm1m").split('\n')[0]
    exeModule = module(exeModuleName)
    print exeModule
    

    This is still relies on an assumption. Although, I have observed it to be true for all versions of Windows back to NT 4.0, that may not always be the case. For example, I would not be the least bit surprised if Address Space Layout Randomization (ASLR) completely broke this assumption for any process linked with it enabled.


    EDIT:

    A little bit safer way to do this is to look at the PEB for the ImageBaseAddress. This is the module start address for the base module. You can construct a pykd module type out of the base address like so:

    from pykd import *
    
    peb = typedVar("ntdll!_PEB", getProcessOffset())
    exeModule = module(peb.ImageBaseAddress)
    print exeModule
    

    This should work a bit more reliably, and fail more predicably, were the _PEB structure ever to change.