Instrumentation

You can implement process instrumentation in your Python scripts by using the provided set of classes: System, Process, Thread, Module and Window. Each one acts as a snapshot of the processes, threads and DLL modules in the system.

A System object is a snapshot of all running processes. It contains Process objects, which in turn are snapshots of threads and modules, containing Thread and Module objects.

System objects also contain Window objects, representing the windows in the current desktop.

Note

You don’t need to be attached as a debugger for these classes to work.

The System class

The System class groups functionality that lets you instrument some global aspects of the machine where you installed WinAppDbg. It also behaves like a snapshot of the running processes. It can enumerate processes and perform operations on a batch of processes.

Example #1: knowing on which platform we’re running

Download


from winappdbg import version
from winappdbg.system import System

# Show the Windows version and the current architecture.
print("WinAppDbg %s" % version)
print("Running on %s for the %s architecture." % (System.os, System.arch))
if System.wow64:
    print("Running in 32 bit emulation mode.")
print("From this Python VM we can attach to %d-bit processes." % System.bits)

Example #2: enumerating running processes

Download


from winappdbg.system import System

# Create a system snaphot.
system = System()

# Now we can enumerate the running processes.
for process in system:
    print(
        "%d:\t%s\t%d\t%s"
        % (
            process.get_pid(),
            process.get_arch(),
            process.get_bits(),
            process.get_filename(),
        )
    )

Example #3: starting a new process

Download


import sys

from winappdbg.system import System

# Instance a System object.
system = System()

# Get the target application.
command_line = system.argv_to_cmdline(sys.argv[1:])

# Start a new process.
process = system.start_process(command_line)  # see the docs for more options

# Show info on the new process.
print("Started process %d (%d bits)" % (process.get_pid(), process.get_bits()))

The System class has many more features, so we’ll be coming back to it later on in the tutorial.

The Process class

The Process class lets you manipulate any process in the system. You can get a Process instance by enumerating a System snapshot, or instancing one directly by providing the process ID.

A Process object allows you to manipulate the process memory (read, write, allocate and free operations), create new threads in the process, and more. It also acts as a snapshot of it’s threads and DLL modules.

Example #4: enumerating threads and DLL modules in a process

Download


from winappdbg.process import Process
from winappdbg.textio import HexDump


def print_threads_and_modules(pid):
    # Instance a Process object.
    process = Process(pid)
    print("Process %d" % process.get_pid())

    # Now we can enumerate the threads in the process...
    print("Threads:")
    for thread in process.iter_threads():
        print("\t%d" % thread.get_tid())

    # ...and the modules in the process.
    print("Modules:")
    bits = process.get_bits()
    for module in process.iter_modules():
        print(
            "\t%s\t%s"
            % (HexDump.address(module.get_base(), bits), module.get_filename())
        )


Example #5: killing a process

Download


from winappdbg.process import Process


def process_kill(pid):
    # Instance a Process object.
    process = Process(pid)

    # Kill the process.
    process.kill()


Example #6: reading the process memory

Download


from winappdbg.process import Process


def process_read(pid, address, length):
    # Instance a Process object.
    process = Process(pid)

    # Read the process memory.
    data = process.read(address, length)

    # You can also change the process memory.
    # process.write( address, "example data" )

    # Return a Python string with the memory contents.
    return data


Example #7: getting the command line for a process

Download


from winappdbg.process import Process


def show_command_line(pid):
    # Instance a Process object.
    process = Process(pid)

    # Print the process command line.
    print(process.get_command_line())

    # The same thing could be done with the environment variables.
    # import pprint
    # pprint.pprint( process.get_environment() )


Example #8: getting the environment variables for a process

Download


from winappdbg.process import Process


def show_environment(pid):
    # Instance a Process object.
    process = Process(pid)

    # Get its environment variables.
    environment = process.get_environment()

    # Print the environment variables.
    for variable, value in sorted(environment.items()):
        print("%s=%s" % (variable, value))


Example #9: loading a DLL into the process

Download


from winappdbg.process import Process


def load_dll(pid, filename):
    # Instance a Process object.
    process = Process(pid)

    # Load the DLL library in the process.
    process.inject_dll(filename)


Example #10: getting the process memory map

Download


from winappdbg import win32
from winappdbg.process import Process
from winappdbg.textio import HexDump


def print_memory_map(pid):
    # Instance a Process object.
    process = Process(pid)

    # Find out if it's a 32 or 64 bit process.
    bits = process.get_bits()

    # Get the process memory map.
    memoryMap = process.get_memory_map()

    # Now you could do this...
    #
    #   from winappdbg import CrashDump
    #   print CrashDump.dump_memory_map( memoryMap ),
    #
    # ...but let's do it the hard way:

    # For each memory block in the map...
    print("Address   \tSize      \tState     \tAccess    \tType")
    for mbi in memoryMap:
        # Address and size of memory block.
        BaseAddress = HexDump.address(mbi.BaseAddress, bits)
        RegionSize = HexDump.address(mbi.RegionSize, bits)

        # State (free or allocated).
        if mbi.State == win32.MEM_RESERVE:
            State = "Reserved  "
        elif mbi.State == win32.MEM_COMMIT:
            State = "Commited  "
        elif mbi.State == win32.MEM_FREE:
            State = "Free      "
        else:
            State = "Unknown   "

        # Page protection bits (R/W/X/G).
        if mbi.State != win32.MEM_COMMIT:
            Protect = "          "
        else:
            ##            Protect = "0x%.08x" % mbi.Protect
            if mbi.Protect & win32.PAGE_NOACCESS:
                Protect = "--- "
            elif mbi.Protect & win32.PAGE_READONLY:
                Protect = "R-- "
            elif mbi.Protect & win32.PAGE_READWRITE:
                Protect = "RW- "
            elif mbi.Protect & win32.PAGE_WRITECOPY:
                Protect = "RC- "
            elif mbi.Protect & win32.PAGE_EXECUTE:
                Protect = "--X "
            elif mbi.Protect & win32.PAGE_EXECUTE_READ:
                Protect = "R-X "
            elif mbi.Protect & win32.PAGE_EXECUTE_READWRITE:
                Protect = "RWX "
            elif mbi.Protect & win32.PAGE_EXECUTE_WRITECOPY:
                Protect = "RCX "
            else:
                Protect = "??? "
            if mbi.Protect & win32.PAGE_GUARD:
                Protect += "G"
            else:
                Protect += "-"
            if mbi.Protect & win32.PAGE_NOCACHE:
                Protect += "N"
            else:
                Protect += "-"
            if mbi.Protect & win32.PAGE_WRITECOMBINE:
                Protect += "W"
            else:
                Protect += "-"
            Protect += "   "

        # Type (file mapping, executable image, or private memory).
        if mbi.Type == win32.MEM_IMAGE:
            Type = "Image     "
        elif mbi.Type == win32.MEM_MAPPED:
            Type = "Mapped    "
        elif mbi.Type == win32.MEM_PRIVATE:
            Type = "Private   "
        elif mbi.Type == 0:
            Type = "Free      "
        else:
            Type = "Unknown   "

        # Print the memory block information.
        fmt = "%s\t%s\t%s\t%s\t%s"
        print(fmt % (BaseAddress, RegionSize, State, Protect, Type))


Example #11: searching the process memory

Download



def memory_search(pid, bytestr):
    # Instance a Process object.
    process = Process(pid)

    # Search for the string in the process memory.
    for address in process.search_bytes(bytestr):
        # Print the memory address where it was found.
        print(HexDump.address(address))


Example #12: searching the process memory using wildcards

Download



def wildcard_search(pid, pattern):
    #
    # Hex patterns must be in this form:
    #     "68 65 6c 6c 6f 20 77 6f 72 6c 64"  # "hello world"
    #
    # Spaces are optional. Capitalization of hex digits doesn't matter.
    # This is exactly equivalent to the previous example:
    #     "68656C6C6F20776F726C64"            # "hello world"
    #
    # Wildcards are allowed, in the form of a "?" sign in any hex digit:
    #     "5? 5? c3"          # pop register / pop register / ret
    #     "b8 ?? ?? ?? ??"    # mov eax, immediate value
    #

    # Instance a Process object.
    process = Process(pid)

    # Search for the hexadecimal pattern in the process memory.
    for address, data in process.search_hexa(pattern):
        # Print a hex dump for each memory location found.
        print(HexDump.hexblock(data, address=address))


The Thread class

A Thread object lets you manipulate any thread in any process in the system. You can get a Thread instance by enumerating a Process snapshot, or instancing one manually by providing the thread ID.

You can manipulate the thread context (read and write to it’s registers), perform typical debugger operations (getting stack traces, etc), suspend and resume execution, and more.

Example #13: freeze all threads in a process

Download


from winappdbg.process import Process
from winappdbg.system import System


def freeze_threads(pid):
    # Request debug privileges.
    System.request_debug_privileges()

    # Instance a Process object.
    process = Process(pid)

    # This would also do the trick...
    #
    #   process.suspend()
    #
    # ...but let's do it the hard way:

    # Lookup the threads in the process.
    process.scan_threads()

    # For each thread in the process...
    for thread in process.iter_threads():
        # Suspend the thread execution.
        thread.suspend()


def unfreeze_threads(pid):
    # Request debug privileges.
    System.request_debug_privileges()

    # Instance a Process object.
    process = Process(pid)

    # This would also do the trick...
    #
    #   process.resume()
    #
    # ...but let's do it the hard way:

    # Lookup the threads in the process.
    process.scan_threads()

    # For each thread in the process...
    for thread in process.iter_threads():
        # Resume the thread execution.
        thread.resume()


Example #14: print a thread’s context

Download


from winappdbg.crash import CrashDump
from winappdbg.system import System
from winappdbg.thread import Thread


def print_thread_context(tid):
    # Request debug privileges.
    System.request_debug_privileges()

    # Instance a Thread object.
    thread = Thread(tid)

    # Suspend the thread execution.
    thread.suspend()

    # Get the thread context.
    try:
        context = thread.get_context()

    # Resume the thread execution.
    finally:
        thread.resume()

    # Display the thread context.
    print()
    print(CrashDump.dump_registers(context), end="")


Example #15: print a thread’s code disassembly

Download


from winappdbg.crash import CrashDump
from winappdbg.system import System
from winappdbg.thread import Thread


def print_thread_disassembly(tid):
    # Request debug privileges.
    System.request_debug_privileges()

    # Instance a Thread object.
    thread = Thread(tid)

    # Suspend the thread execution.
    thread.suspend()

    # Get the thread's currently running code.
    try:
        eip = thread.get_pc()
        code = thread.disassemble_around(eip)

        # You can also do this:
        # code = thread.disassemble_around_pc()

        # Or even this:
        # process = thread.get_process()
        # code    = process.disassemble_around( eip )

    # Resume the thread execution.
    finally:
        thread.resume()

    # Display the disassembled code.
    print()
    print(CrashDump.dump_code(code, eip), end="")


The Module class

A Module object lets you manipulate any thread in any process in the system. You can get a Module instance by enumerating a Process snapshot. Module objects can be used to resolve the addresses of exported functions in the process address space.

Example #16: resolve an API function in a process

Download


from winappdbg.process import Process
from winappdbg.system import System


def print_api_address(pid, modName, procName):
    # Request debug privileges.
    System.request_debug_privileges()

    # Instance a Process object.
    process = Process(pid)

    # Lookup it's modules.
    process.scan_modules()

    # Get the module.
    module = process.get_module_by_name(modName)
    if not module:
        print("Module not found: %s" % modName)
        return

    # Resolve the requested API function address.
    address = module.resolve(procName)

    # Print the address.
    if address:
        print("%s!%s == 0x%.08x" % (modName, procName, address))
    else:
        print("Could not resolve %s in module %s" % (procName, modName))


The Window class

A Window object lets you manipulate any window in the current desktop. You can get a Window instance by querying a System object.

Example #17: enumerate the top-level windows

Download


import sys

from winappdbg.system import System
from winappdbg.textio import HexDump

# Create a system snaphot.
system = System()

# Now we can enumerate the top-level windows.
for window in system.get_windows():
    handle = HexDump.integer(window.get_handle())
    caption = window.get_text()
    if caption is not None:
        try:
            print("%s:\t%s" % (handle, caption))
        except UnicodeEncodeError:
            # Handle encoding errors by replacing problematic characters
            print(
                "%s:\t%s"
                % (
                    handle,
                    caption.encode(
                        sys.stdout.encoding or "utf-8", errors="replace"
                    ).decode(sys.stdout.encoding or "utf-8"),
                )
            )

Example #18: minimize all top-level windows

Download


from winappdbg.system import System

# Create a system snaphot.
system = System()

# Enumerate the top-level windows.
for window in system.get_top_level_windows():
    # Minimize the window.
    if window.is_visible() and not window.is_minimized():
        window.minimize()

    # You could also maximize, restore, show, hide, enable and disable.
    # For example:
    #
    # if window.is_maximized():
    #     window.restore()
    #
    # if not window.is_visible():
    #     window.show()
    #
    # if not window.is_disabled():
    #     window.enable()
    #
    # ...and so on.

Example #19: traverse the windows tree

Download


from winappdbg.system import System
from winappdbg.textio import HexDump


def show_window_tree(window, indent=0):
    # Show this window's handle and caption.
    # Use some ASCII art to show the layout. :)
    handle = HexDump.integer(window.get_handle())
    caption = window.get_text()
    line = ""
    if indent > 0:
        print("|   " * indent)
        line = "|   " * (indent - 1) + "|---"
    else:
        print("|")
    if caption is not None:
        line += handle + ": " + caption
    else:
        line += handle
    print(line)

    # Recursively show the child windows.
    for child in window.get_children():
        show_window_tree(child, indent + 1)


def main():
    # Create a system snaphot.
    system = System()

    # Get the Desktop window.
    root = system.get_desktop_window()

    # Now show the window tree.
    show_window_tree(root)

    # You can also ge the tree as a Python dictionary:
    # tree = root.get_tree()
    # print tree


Example #20: get windows by screen position

Download


import sys

from winappdbg.system import System
from winappdbg.textio import HexDump

try:
    # Get the coordinates from the command line.
    x = int(sys.argv[1])
    y = int(sys.argv[2])

    # Get the window at the requested position.
    window = System.get_window_at(x, y)

    # Get the window coordinates.
    rect = window.get_screen_rect()
    position = (rect.left, rect.top, rect.right, rect.bottom)
    size = (rect.right - rect.left, rect.bottom - rect.top)

    # Print the window information.
    print("Handle:   %s" % HexDump.integer(window.get_handle()))
    print("Caption:  %s" % window.text)
    print("Class:    %s" % window.classname)
    print("Style:    %s" % HexDump.integer(window.style))
    print("ExStyle:  %s" % HexDump.integer(window.exstyle))
    print("Position: (%i, %i) - (%i, %i)" % position)
    print("Size:     (%i, %i)" % size)

except WindowsError:
    print("No window at those coordinates!")

Example #21: find windows by class and caption

Download


import sys

from winappdbg.system import System
from winappdbg.textio import HexDump


def find_window():
    # If two arguments are given, the first is the classname
    # and the second is the caption text.
    if len(sys.argv) > 2:
        classname = sys.argv[1]
        caption = sys.argv[2]
        if not classname:
            classname = None
        if not caption:
            caption = None
        window = System.find_window(classname, caption)

    # If only one argument is given, try the caption text, then the classname.
    else:
        try:
            window = System.find_window(windowName=sys.argv[1])
        except WindowsError:
            window = System.find_window(className=sys.argv[1])

    return window


def show_window(window):
    # Get the window coordinates.
    rect = window.get_screen_rect()
    position = (rect.left, rect.top, rect.right, rect.bottom)
    size = (rect.right - rect.left, rect.bottom - rect.top)

    # Print the window information.
    print("Handle:   %s" % HexDump.integer(window.get_handle()))
    print("Caption:  %s" % window.text)
    print("Class:    %s" % window.classname)
    print("Style:    %s" % HexDump.integer(window.style))
    print("ExStyle:  %s" % HexDump.integer(window.exstyle))
    print("Position: (%i, %i) - (%i, %i)" % position)
    print("Size:     (%i, %i)" % size)


def main():
    try:
        show_window(find_window())
    except WindowsError:
        print("No window found!")


Example #22: kill a program using its window

Download



def user_confirmed():
    print()
    answer = input("Are you sure you want to kill this program? (y/N):")
    answer = answer.strip().upper()
    return answer.startswith("Y")


def main():
    # Find the window.
    try:
        window = find_window()
    except WindowsError:
        print("No window found!")
        return

    # Show the window info to the user.
    show_window(window)

    # Ask the user for confirmation.
    if user_confirmed():
        # Kill the program.
        window.kill()


Back to the System class

As promised, we’re back on the System class to see more of its features. We’ll now see how to access the Windows Registry and work with system services.

Example #23: exporting a Registry key

Download


import struct

from winappdbg import win32
from winappdbg.system import System

# RegistryEditorVersion = "REGEDIT4"  # for Windows 95
RegistryEditorVersion = "Windows Registry Editor Version 5.00"


# Helper function to serialize data to hexadecimal format.
def reg_hexa(value, type):
    return "hex(%x):%s" % (type, ",".join(["%.2x" % x for x in value]))


# Registry export function.
def reg_export(reg_path, filename):
    # Queue of registry keys to visit.
    queue = []

    # Get the registry key the user requested.
    key = System.registry[reg_path]

    # Add it to the queue.
    queue.append(key)

    # Open the output file.
    with open(filename, "w", encoding="utf-16") as output:
        # Write the file format header.
        output.write("%s\n" % RegistryEditorVersion)

        # For each registry key in the queue...
        while queue:
            key = queue.pop()

            # Write the key path.
            output.write("\n[%s]\n" % key.path)

            # If there's a default value, write it.
            default = str(key)
            if default:
                output.write('@="%s"\n' % default)

            # For each value in the key...
            for name, value in key.items():
                # Skip the default value since we already wrote it.
                if not name:
                    continue

                # Serialize the name.
                s_name = '"%s"' % name

                # Serialize the value.
                t_value = key.get_value_type(name)
                if t_value == win32.REG_SZ and isinstance(value, str):
                    s_value = '"%s"' % value.replace('"', '\\"')
                elif t_value == win32.REG_DWORD:
                    s_value = "dword:%.8X" % value
                else:
                    new_value = value
                    if t_value == win32.REG_QWORD:
                        new_value = struct.pack("<Q", value)
                    elif t_value == win32.REG_DWORD:
                        new_value = struct.pack("<L", value)
                    elif t_value == win32.REG_DWORD_BIG_ENDIAN:
                        new_value = struct.pack(">L", value)
                    elif t_value == win32.REG_MULTI_SZ:
                        # The value is a list of strings.
                        # It must be encoded as a sequence of null-terminated
                        # UTF-16LE strings, terminated by a final null character.
                        new_value = ("\0".join(value) + "\0\0").encode("utf-16le")

                    if isinstance(new_value, str):
                        # This will handle REG_EXPAND_SZ and any other
                        # string-like types that were not packed into bytes.
                        s_value = reg_hexa(new_value.encode("utf-16le"), t_value)
                    else:
                        # This will handle values from struct.pack and
                        # our already encoded REG_MULTI_SZ.
                        s_value = reg_hexa(new_value, t_value)

                # Write the name and value.
                output.write("%s=%s\n" % (s_name, s_value))

            # Add the subkeys to the queue.
            queue.extend(key.children())


Example #24: searching the Registry

Download


from winappdbg.system import System
from winappdbg.textio import Color


def reg_search(search):
    # Show the user what we're searching for.
    print("Searching for: %r" % search)

    # For each Registry key...
    for path in System.registry.iterkeys():
        # Try to open the key. On error skip it.
        try:
            key = System.registry[path]
        except Exception:
            continue

        # Get the default value. On error skip it.
        try:
            default = str(key)
        except KeyError:
            default = ""
        except Exception:
            continue

        # Does the default value match?
        if search in default:
            text = "%s\\@: %s" % (path, default)
            highlight(search, text)

        # Does the key match?
        elif search in path[path.rfind("\\") :]:
            highlight(search, path)

        # For each Registry value...
        for name in key.keys():
            # Try to get the value. On error ignore it.
            try:
                value = key[name]
            except Exception:
                value = ""

            # Registry values can be of many data types.
            # For this search we need to force all values to be strings.
            if not isinstance(value, str):
                value = str(value)

            # Do the name or value match?
            if search in name or search in value:
                text = "%s\\%s: %r" % (path, name, value)
                highlight(search, text)


# Helper function to print text with a highlighted search string.
def highlight(search, text):
    if can_highlight:
        try:
            Color.default()
            p = 0
            while p < len(text):
                q = text.find(search, p)
                if q == -1:
                    sys.stdout.write(text[p:])
                    break
                sys.stdout.write(text[p:q])
                Color.red()
                Color.light()
                sys.stdout.write(search)
                Color.default()
                p = q + len(search)
            sys.stdout.write("\r\n")
        finally:
            Color.default()
    else:
        print(text)


# Determine if the output is a console or a file.
# Trying to use colors fails if the output is not the console.
can_highlight = Color.can_use_colors()

Example #25: listing system services

Download


from winappdbg import win32
from winappdbg.system import System


def show_services():
    # Get the list of services.
    services = System.get_services()

    # You could get only the running services instead.
    # services = System.get_active_services()

    # For each service descriptor...
    for descriptor in services:
        # Print the service information, the easy way.
        # print str(descriptor)

        # You can also do it the hard way, accessing its members.
        print("Service name: %s" % descriptor.ServiceName)
        print("Display name: %s" % descriptor.DisplayName)
        if descriptor.ServiceType & win32.SERVICE_INTERACTIVE_PROCESS:
            print("Service type: Win32 GUI")
        elif descriptor.ServiceType & win32.SERVICE_WIN32:
            print("Service type: Win32")
        elif descriptor.ServiceType & win32.SERVICE_DRIVER:
            print("Service type: Driver")
        if descriptor.CurrentState == win32.SERVICE_CONTINUE_PENDING:
            print("Current status: RESTARTING...")
        elif descriptor.CurrentState == win32.SERVICE_PAUSE_PENDING:
            print("Current status: PAUSING...")
        elif descriptor.CurrentState == win32.SERVICE_PAUSED:
            print("Current status: PAUSED")
        elif descriptor.CurrentState == win32.SERVICE_RUNNING:
            print("Current status: RUNNING")
        elif descriptor.CurrentState == win32.SERVICE_START_PENDING:
            print("Current status: STARTING...")
        elif descriptor.CurrentState == win32.SERVICE_STOP_PENDING:
            print("Current status: STOPPING...")
        elif descriptor.CurrentState == win32.SERVICE_STOPPED:
            print("Current status: STOPPED")
        print()


# When invoked from the command line,
# call the show_services() function.

Example #26: stopping and starting a system service

Download


from time import sleep

from winappdbg import win32
from winappdbg.system import System


# Function that restarts a service.
# Requires UAC elevation in Windows Vista and above.
def restart_service(service):
    try:
        # Get the display name.
        try:
            display_name = System.get_service_display_name(service)
        except WindowsError:
            display_name = service

        # Get the service descriptor.
        descriptor = System.get_service(service)

        # Is the service running?
        if descriptor.CurrentState != win32.SERVICE_STOPPED:
            # Tell the service to stop.
            print('Stopping service "%s"...' % display_name)
            System.stop_service(service)

            # Wait for the service to stop.
            wait_for_service(service, win32.SERVICE_STOP_PENDING)
            print("Service stopped successfully.")

        # Tell the service to start.
        print('Starting service "%s"...' % display_name)
        System.start_service(service)

        # Wait for the service to start.
        wait_for_service(service, win32.SERVICE_START_PENDING)
        print("Service started successfully.")

        # Show the new process ID.
        # This feature requires Windows XP and above.
        descriptor = System.get_service(service)
        try:
            print("New process ID is: %d" % descriptor.ProcessId)
        except AttributeError:
            pass

    # On error, show an error message.
    except WindowsError as e:
        if e.winerror == win32.ERROR_ACCESS_DENIED:
            print("Access denied! Is this an UAC elevated prompt?")
        else:
            print(str(e))


# Helper function to wait for the service to change its state.
def wait_for_service(service, wait_state, timeout=20):
    descriptor = System.get_service(service)
    while descriptor.CurrentState == wait_state:
        timeout -= 1
        if timeout <= 0:
            raise RuntimeError("Error: timed out.")
        sleep(0.5)
        descriptor = System.get_service(service)


Generating minidump files

Minidump files are the standard Windows format for crash dumps and process snapshots. The Process class provides a convenient method to generate minidump files for any running process, which can then be analyzed with tools like WinDbg, Visual Studio, or other debuggers.

Example #27: generating a minidump of a running process

Download


import sys

from winappdbg import win32
from winappdbg.process import Process

# Get the process ID and output filename from the command line.
if len(sys.argv) < 2:
    print("Usage: %s <process_id> [output_file] [dump_type]" % sys.argv[0])
    print()
    print("  process_id  : Process ID to dump")
    print("  output_file : Output minidump file (default: minidump.dmp)")
    print("  dump_type   : Dump type flags (default: MiniDumpNormal)")
    print()
    print("Example dump types:")
    print("  MiniDumpNormal              - Basic information only")
    print("  MiniDumpWithFullMemory      - Include all accessible memory")
    print("  MiniDumpWithHandleData      - Include handle information")
    print("  MiniDumpWithThreadInfo      - Include thread information")
    print("  MiniDumpWithDataSegs        - Include data segments")
    print()
    print("Multiple flags can be combined with | (OR operator).")
    print("Example: MiniDumpWithFullMemory | MiniDumpWithHandleData")
    sys.exit(1)

pid = int(sys.argv[1])
output_file = sys.argv[2] if len(sys.argv) > 2 else "minidump.dmp"

# Parse dump type if provided
if len(sys.argv) > 3:
    # Allow user to specify flags like: MiniDumpWithFullMemory | MiniDumpWithHandleData
    dump_type_str = sys.argv[3]
    # Evaluate in a namespace with win32 constants
    dump_type = eval(dump_type_str, {"__builtins__": {}}, vars(win32))
else:
    dump_type = win32.MiniDumpNormal

try:
    # Create a Process object for the target process.
    process = Process(pid)

    # Generate the minidump file.
    print("Generating minidump for process %d..." % pid)
    print("Output file: %s" % output_file)
    print("Dump type: 0x%08X" % dump_type)

    process.generate_minidump(output_file, DumpType=dump_type)

    print("Minidump generated successfully!")

except WindowsError as e:
    print("Error: %s" % e)
    sys.exit(1)
except Exception as e:
    print("Unexpected error: %s" % e)
    import traceback

    traceback.print_exc()
    sys.exit(1)

Working with UWP and packaged apps

Starting with Windows 8, Microsoft introduced Universal Windows Platform (UWP) and packaged applications (also known as Windows Store apps, MSIX packages). These applications have a package identity that includes a full package name.

WinAppDbg provides support for both querying and launching packaged applications.

Note

Launching packaged apps requires the comtypes library. Install it with: pip install winappdbg[packaged_apps]

Querying packaged apps

The Process class provides a method to retrieve package information from running processes. Example #28 shows how to scan all running processes and display detailed information about packaged apps, including the AUMID needed for launching.

Example #28: getting package information from running processes

Download


import sys
from winappdbg.system import System
from winappdbg import appmodel


def main():
    # Create a system snapshot
    system = System()
    system.scan_processes()

    # Iterate through all processes
    for process in system.iter_processes():
        try:
            # Try to get the package full name
            package_full_name = process.get_package_full_name()

            # Only process packaged apps
            if not package_full_name:
                continue

            # Parse the package full name to extract components
            info = appmodel.parse_package_full_name(package_full_name)

            if not info:
                # Couldn't parse, just show the raw name
                print("%d\t%s" % (process.get_pid(), package_full_name))
                continue

            # Build the AUMID (assume App ID is "App")
            aumid = appmodel.build_aumid(info['package_family_name'], "App")

            # Print formatted information
            print("PID %d:" % process.get_pid())
            print("  Name:         %s" % info['name'])
            print("  Version:      %s" % info['version'])
            print("  Architecture: %s" % info['architecture'])
            print("  Family Name:  %s" % info['package_family_name'])
            print("  AUMID:        %s" % aumid)
            print()

        except Exception:
            # Skip processes we can't access
            pass


# When invoked from the command line,
# call the main() function.
if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass

Application User Model IDs (AUMIDs)

To launch a packaged application, you need its Application User Model ID (AUMID). An AUMID has the format: PackageFamilyName!ApplicationId

You can find AUMIDs by:

  1. Running example #28 to see running packaged apps with their AUMIDs

  2. Using PowerShell: Get-StartApps or Get-AppxPackage

Common AUMIDs for built-in Windows apps:

  • Calculator: Microsoft.WindowsCalculator_8wekyb3d8bbwe!App

  • Notepad: Microsoft.WindowsNotepad_8wekyb3d8bbwe!App

  • Microsoft Store: Microsoft.WindowsStore_8wekyb3d8bbwe!App

  • Photos: Microsoft.Windows.Photos_8wekyb3d8bbwe!App

Launching packaged apps

The System class provides methods to launch packaged applications using their Application User Model ID (AUMID).

Example #29: launching a packaged application

Download


import sys
from winappdbg.system import System
from winappdbg import appmodel


def main(argv):
    # Check if comtypes is available
    if not appmodel.HAS_COMTYPES:
        print("Error: comtypes library is not installed")
        print("Install it with: pip install winappdbg[packaged_apps]")
        return 1

    # Check command line arguments
    if len(argv) < 2:
        print("Usage: %s <AUMID> [arguments]" % argv[0])
        print()
        print("AUMID format: PackageFamilyName!ApplicationId")
        print()
        print("Examples:")
        print("  %s Microsoft.WindowsCalculator_8wekyb3d8bbwe!App" % argv[0])
        print("  %s Microsoft.WindowsNotepad_8wekyb3d8bbwe!App" % argv[0])
        print()
        print("To find AUMIDs:")
        print("  Run example 28 to see running packaged apps and their AUMIDs")
        print("  Or use PowerShell: Get-StartApps")
        return 1

    # Get the AUMID from command line
    aumid = argv[1]

    # Get optional arguments
    arguments = " ".join(argv[2:]) if len(argv) > 2 else None

    # Launch the app
    print("Launching: %s" % aumid)
    if arguments:
        print("Arguments: %s" % arguments)

    try:
        system = System()
        process = system.start_packaged_app(aumid, arguments=arguments)

        print("Process ID: %d" % process.get_pid())

        # Try to get the package full name
        try:
            package_full_name = process.get_package_full_name()
            if package_full_name:
                print("Package: %s" % package_full_name)
        except Exception:
            pass

    except ImportError as e:
        print("Error: %s" % e)
        return 1
    except WindowsError as e:
        print("Failed to launch application: %s" % e)
        return 1

    return 0


# When invoked from the command line,
# call the main() function.
if __name__ == "__main__":
    try:
        sys.exit(main(sys.argv))
    except KeyboardInterrupt:
        print()
        print("Interrupted by user")