The Win32 API wrappers

The win32 submodule provides a collection of useful API wrappers for most operations needed by a debugger. This will allow you to perform any task that the abstraction layer for some reason can’t deal with, or won’t deal with in the way you need. In most cases you won’t need to resort to this, but it’s important to know it’s there.

Except in some rare cases, the rationale to port the API calls to Python was:

  • Take Python basic types as input, return Python basic types as output.
  • Functions that in C take an output pointer and a size as input, in Python take neither and return the output data directly (the wrapper takes care of allocating the memory buffers).
  • Functions that in C have to be called twice (first to get the buffer size, then to get the data) in Python only have to be called once (returns the data directly).
  • Functions in C with more than one output pointer return tuples of data in Python.
  • Functions in C that return an error condition, raise a Python exception (WindowsError) on error and return the data on success.
  • Default parameter values were added when possible. The default for all optional pointers is NULL. The default flags are usually the ones that provide all possible access (for example, the default flags value for GetThreadContext is CONTEXT_ALL)
  • For APIs with ANSI and Widechar versions, both versions are wrapped. If at least one parameter is a Unicode string en Widechar version is called (and all string parameters are converted to Unicode), otherwise the ANSI version is called. Either ANSI or Widechar versions can be used explicitly (for example, CreateFile can be called as CreateFileA or CreateFileW).

All handles returned by API calls are wrapped around the Handle class. This allows you to use the with statement to ensure proper cleanup, and causes handles to be closed automatically when they go out of scope, thus preventing handle leaks.

Example #1: finding a DLL in the search path

Download


import sys

from winappdbg import win32

try:
    fullpath, basename = win32.SearchPath( None, sys.argv[1], '.dll' )
except WindowsError, e:
    if e.winerror != win32.ERROR_FILE_NOT_FOUND:
        raise
    fullpath, basename = win32.SearchPath( None, sys.argv[1], '.exe' )

print "Full path: %s" % fullpath
print "Base name: %s" % basename

Example #2: killing a process by attaching to it

Download


import sys
import thread

from winappdbg import win32

def processKiller(dwProcessId):

    # Attach to the process.
    win32.DebugActiveProcess( dwProcessId )

    # Quit the current thread.
    thread.exit()

Example #3: enumerating heap blocks using the Toolhelp library

Download


from winappdbg.win32 import *  # NOQA

def print_heap_blocks( pid ):

    # Determine if we have 32 bit or 64 bit pointers.
    if sizeof(SIZE_T) == sizeof(DWORD):
        fmt = "%.8x\t%.8x\t%.8x"
        hdr = "%-8s\t%-8s\t%-8s"
    else:
        fmt = "%.16x\t%.16x\t%.16x"
        hdr = "%-16s\t%-16s\t%-16s"

    # Print a banner.
    print "Heaps for process %d:" % pid
    print hdr % ("Heap ID", "Address", "Size")

    # Create a snapshot of the process, only take the heap list.
    hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPHEAPLIST, pid )

    # Enumerate the heaps.
    heap = Heap32ListFirst( hSnapshot )
    while heap is not None:

        # For each heap, enumerate the entries.
        entry = Heap32First( heap.th32ProcessID, heap.th32HeapID )
        while entry is not None:

            # Print the heap id and the entry address and size.
            print fmt % (entry.th32HeapID, entry.dwAddress, entry.dwBlockSize)

            # Next entry in the heap.
            entry = Heap32Next( entry )

        # Next heap in the list.
        heap = Heap32ListNext( hSnapshot )

    # No need to call CloseHandle, the handle is closed automatically when it goes out of scope.
    return

Example #4: enumerating modules using the Toolhelp library

Download


from winappdbg.win32 import *  # NOQA

def print_modules( pid ):

    # Determine if we have 32 bit or 64 bit pointers.
    if sizeof(SIZE_T) == sizeof(DWORD):
        fmt = "%.8x    %.8x    %s"
        hdr = "%-8s    %-8s    %s"
    else:
        fmt = "%.16x    %.16x    %s"
        hdr = "%-16s    %-16s    %s"

    # Print a banner.
    print "Modules for process %d:" % pid
    print
    print hdr % ("Address", "Size", "Path")

    # Create a snapshot of the process, only take the heap list.
    hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid )

    # Enumerate the modules.
    module = Module32First( hSnapshot )
    while module is not None:

        # Print the module address, size and pathname.
        print fmt % ( module.modBaseAddr,
                      module.modBaseSize,
                      module.szExePath )

        # Next module in the process.
        module = Module32Next( hSnapshot )

    # No need to call CloseHandle, the handle is closed automatically when it goes out of scope.
    return

Example #5: enumerating device drivers

Download


from winappdbg.win32 import *  # NOQA

def print_drivers( fFullPath = False ):

    # Determine if we have 32 bit or 64 bit pointers.
    if sizeof(SIZE_T) == sizeof(DWORD):
        fmt = "%.08x\t%s"
        hdr = "%-8s\t%s"
    else:
        fmt = "%.016x\t%s"
        hdr = "%-16s\t%s"

    # Get the list of loaded device drivers.
    ImageBaseList = EnumDeviceDrivers()
    print "Device drivers found: %d" % len(ImageBaseList)
    print
    print hdr % ("Image base", "File name")

    # For each device driver...
    for ImageBase in ImageBaseList:

        # Get the device driver filename.
        if fFullPath:
            DriverName = GetDeviceDriverFileName(ImageBase)
        else:
            DriverName = GetDeviceDriverBaseName(ImageBase)

        # Print the device driver image base and filename.
        print fmt % (ImageBase, DriverName)