More examples

Set a debugging timeout

Sometimes you’ll want to set a maximum time to debug your target, especially when fuzzing. This is an example on how to code a custom debugging loop with a timeout. It launches the Windows Calculator and stops when the target process is closed or after a 5 seconds timeout.

Download

Dump the memory of a process

This is an example on how to dump the memory map and contents of a process into an SQLite database. A table is created where each row is a memory region, and the columns are the properties of that region (address, size, mapped filename, etc.) and it’s data. The data is compressed using zlib to reduce the database size, but simply commenting out line 160 stores the data in uncompressed form.

Download

Find alphanumeric addresses to jump to

This example will find all memory addresses in a target process that are executable and whose address consists of alphanumeric characters only. This is useful when exploiting a stack buffer overflow and the input string is limited to alphanumeric characters only.

Download


from struct import pack
from winappdbg import System, Process, HexDump

# Iterator of alphanumeric executable addresses
def iterate_alnum_jump_addresses(memory_snapshot):

    # Determine the size of a pointer in the current architecture
    if System.bits == 32:
        fmt = 'L'
    elif System.bits == 64:
        fmt = 'Q'
    else:
        raise NotImplementedError

    # Iterate the memory regions of the target process
    for mbi in memory_snapshot:

        # Discard non executable memory
        if not mbi.is_executable():
            continue

        # Yield each alphanumeric address in this memory region.
        address     = mbi.BaseAddress
        max_address = address + mbi.RegionSize
        while address < max_address:
            packed = pack(fmt, address)
            if packed.isalnum():
                yield address, packed
            address = address + 1

# Iterate and print alphanumeric executable addresses.
def print_alnum_jump_addresses(pid):

    # Request debug privileges so we can inspect the memory of services too.
    System.request_debug_privileges()

    # Suspend the process so there are no malloc's and free's while iterating.
    process = Process(pid)
    process.suspend()
    try:

        # Get an iterator for the target process memory.
        iterator = process.generate_memory_snapshot()

        # Print each executable alphanumeric address.
        for address, packed in iterate_alnum_jump_addresses(iterator):
            print HexDump.address(address), repr(packed)

    # Resume the process when we're done.
    # This is inside a "finally" block, so if the program is interrupted
    # for any reason we don't leave the process suspended.
    finally:
        process.resume()

Trace all calls to text drawing in GDI

This example hooks all text drawing functions in GDI and prints the text. It can be useful to extract text messages and logs from GUI programs.

Download


from winappdbg import Debug, EventHandler, DebugLog
from ctypes import *

#------------------------------------------------------------------------------

# BOOL TextOut(
#   __in  HDC hdc,
#   __in  int nXStart,
#   __in  int nYStart,
#   __in  LPCTSTR lpString,
#   __in  int cbString
# );

def TextOutA(event, ra, hdc, nXStart, nYStart, lpString, cbString):
    log_ansi(event, "TextOutA", lpString, cbString)

def TextOutW(event, ra, hdc, nXStart, nYStart, lpString, cbString):
    log_wide(event, "TextOutW", lpString, cbString)

# BOOL ExtTextOut(
#   __in  HDC hdc,
#   __in  int X,
#   __in  int Y,
#   __in  UINT fuOptions,
#   __in  const RECT *lprc,
#   __in  LPCTSTR lpString,
#   __in  UINT cbCount,
#   __in  const INT *lpDx
# );
def ExtTextOutA(event, ra, hdc, X, Y, fuOptions, lprc, lpString, cbCount, lpDx):
    log_ansi(event, "ExtTextOutA", lpString, cbCount)

def ExtTextOutW(event, ra, hdc, X, Y, fuOptions, lprc, lpString, cbCount, lpDx):
    log_wide(event, "ExtTextOutW", lpString, cbCount)

# typedef struct _POLYTEXT {
#   int     x;
#   int     y;
#   UINT    n;
#   LPCTSTR lpstr;
#   UINT    uiFlags;
#   RECT    rcl;
#   int     *pdx;
# } POLYTEXT, *PPOLYTEXT;
class POLYTEXT(Structure):
    _fields_ = [
        ('x',       c_int),
        ('y',       c_int),
        ('n',       c_uint),
        ('lpstr',   c_void_p),
        ('uiFlags', c_uint),
        ('rcl',     c_uint * 4),
        ('pdx',     POINTER(c_int)),
    ]

# BOOL PolyTextOut(
#   __in  HDC hdc,
#   __in  const POLYTEXT *pptxt,
#   __in  int cStrings
# );

def PolyTextOutA(event, ra, hdc, pptxt, cStrings):
    process = event.get_process()
    sizeof_polytext = sizeof(POLYTEXT)
    while cStrings:
        txt = process.read_structure(pptxt, POLYTEXT)
        log_ansi(event, "PolyTextOutA", txt.lpstr, txt.n)
        pptxt = pptxt + sizeof_polytext
        cStrings = cStrings - 1

def PolyTextOutW(event, ra, hdc, pptxt, cStrings):
    process = event.get_process()
    sizeof_polytext = sizeof(POLYTEXT)
    while cStrings:
        txt = process.read_structure(pptxt, POLYTEXT)
        log_wide(event, "PolyTextOutW", txt.lpstr, txt.n)
        pptxt = pptxt + sizeof_polytext
        cStrings = cStrings - 1

#------------------------------------------------------------------------------

def log_ansi(event, fn, lpString, nCount):
    if lpString and nCount:
        if c_int(nCount).value == -1:
            lpString = event.get_process().peek_string(lpString, fUnicode = False)
        else:
            lpString = event.get_process().peek(lpString, nCount)
        print DebugLog.log_text("%s( %r );" % (fn, lpString))

def log_wide(event, fn, lpString, nCount):
    if lpString and nCount:
        if c_int(nCount).value == -1:
            lpString = event.get_process().peek_string(lpString, fUnicode = True)
        else:
            lpString = event.get_process().peek(lpString, nCount * 2)
            lpString = unicode(lpString, 'U16', 'replace')
        print DebugLog.log_text("%s( %r );" % (fn, lpString))

class MyEventHandler( EventHandler ):
    def load_dll(self, event):
        pid = event.get_pid()
        module = event.get_module()
        if module.match_name("gdi32.dll"):
            event.debug.hook_function(pid, module.resolve("TextOutA"),       TextOutA,       paramCount = 5)
            event.debug.hook_function(pid, module.resolve("TextOutW"),       TextOutW,       paramCount = 5)
            event.debug.hook_function(pid, module.resolve("ExtTextOutA"),    ExtTextOutA,    paramCount = 8)
            event.debug.hook_function(pid, module.resolve("ExtTextOutW"),    ExtTextOutW,    paramCount = 8)
            event.debug.hook_function(pid, module.resolve("PolyTextOutA"),   PolyTextOutA,   paramCount = 2)
            event.debug.hook_function(pid, module.resolve("PolyTextOutW"),   PolyTextOutW,   paramCount = 2)

def simple_debugger(argv):
    print DebugLog.log_text("Trace started on %s" % argv[0])
    debug = Debug( MyEventHandler() )
    try:
        debug.execv(argv)
        debug.loop()
    finally:
        debug.stop()
    print DebugLog.log_text("Trace stopped on %s" % argv[0])

Enumerate all named global atoms

Global atoms are WORD numeric values that can be associated to arbitrary strings. They are used primarily for IPC purposes on Windows. This example shows how to retrieve the string from any atom value.

Download


from winappdbg.win32 import GlobalGetAtomName, MAXINTATOM

# print all valid named global atoms to standard output
def print_atoms():
    for x in xrange(0, MAXINTATOM):
        try:
            n = GlobalGetAtomName(x)
            if n == "#%d" % x:      # comment out to print
                continue            # valid numeric atoms
            print "Atom %4x: %r" % (x, n)
        except WindowsError:
            pass