winappdbg.event
Event handling module.
Contains the logic to handle debugging events in your scripts and tools.
- @group Debugging:
EventHandler, EventSift
- @group Debug events:
EventFactory, EventDispatcher, Event, NoEvent, CreateProcessEvent, CreateThreadEvent, ExitProcessEvent, ExitThreadEvent, LoadDLLEvent, UnloadDLLEvent, OutputDebugStringEvent, RIPEvent, ExceptionEvent
- @group Warnings:
EventCallbackWarning
- class winappdbg.event.CreateProcessEvent(debug, raw)
Process creation event.
- get_debug_info()
- Return type:
str
- Returns:
Debugging information.
- get_file_handle()
- Return type:
FileHandleor None- Returns:
File handle to the main module, received from the system. Returns
Noneif the handle is not available.
- get_filename()
- Return type:
str, None
- Returns:
This method does it’s best to retrieve the filename to the main module of the process. However, sometimes that’s not possible, and
Noneis returned instead.
- get_image_base()
- Return type:
int
- Returns:
Base address of the main module.
Warning
This value is taken from the PE file and may be incorrect because of ASLR!
- get_module()
- Return type:
Module- Returns:
Main module of the process.
- get_module_base()
- Return type:
int
- Returns:
Base address of the main module.
- get_process_handle()
- Return type:
ProcessHandle- Returns:
Process handle received from the system. Returns
Noneif the handle is not available.
- get_start_address()
- Return type:
int
- Returns:
Pointer to the first instruction to execute in this process.
Returns
NULLwhen the debugger attaches to a process.See http://msdn.microsoft.com/en-us/library/ms679295(VS.85).aspx
- get_teb()
- Return type:
int
- Returns:
Pointer to the TEB.
- get_thread_handle()
- Return type:
ThreadHandle- Returns:
Thread handle received from the system. Returns
Noneif the handle is not available.
- class winappdbg.event.CreateThreadEvent(debug, raw)
Thread creation event.
- get_start_address()
- Return type:
int
- Returns:
Pointer to the first instruction to execute in this thread.
Returns
NULLwhen the debugger attached to a process and the thread already existed.See http://msdn.microsoft.com/en-us/library/ms679295(VS.85).aspx
- get_teb()
- Return type:
int
- Returns:
Pointer to the TEB.
- get_thread_handle()
- Return type:
ThreadHandle- Returns:
Thread handle received from the system. Returns
Noneif the handle is not available.
- class winappdbg.event.Event(debug, raw)
Event object.
- Variables:
eventMethod (str) – Method name to call when using
EventHandlersubclasses. Used internally.eventName (str) – User-friendly name of the event.
eventDescription (str) – User-friendly description of the event.
debug (Debug) –
Debugobject that received the event.raw (winappdg.win32.DEBUG_EVENT) – Raw
DEBUG_EVENTstructure as used by the Win32 API.continueStatus (int) – Continue status to pass to
win32.ContinueDebugEvent().
- generate_minidump(filename, DumpType=None, bIncludeContext=True, ExceptionParam=None, UserStreamParam=None, CallbackParam=None)
Generates a minidump file for the process where this event occurred.
This is a convenience wrapper around
Process.generate_minidump()that automatically captures the thread context if requested.- Parameters:
filename (str) – Path to the output minidump file (.dmp).
DumpType (int) – Type of information to include in the minidump. See
Process.generate_minidump()for details.bIncludeContext (bool) – If
True(default), captures and includes the context (register state) of the thread where the event occurred. Set toFalseto skip context capture.ExceptionParam (MINIDUMP_EXCEPTION_INFORMATION or None) – Optional exception information.
ExceptionEventprovides a more convenient method that automatically populates this.UserStreamParam (MINIDUMP_USER_STREAM_INFORMATION or None) – Optional user-defined information streams.
CallbackParam (MINIDUMP_CALLBACK_INFORMATION or None) – Optional callback for customizing the dump.
- Raises:
WindowsError – On error an exception is raised.
Example:
class MyEventHandler(EventHandler): def breakpoint(self, event): # Generate a minidump when hitting a breakpoint event.generate_minidump("breakpoint.dmp") def load_dll(self, event): # Generate a dump without context for DLL load events event.generate_minidump("dll_load.dmp", bIncludeContext=False)
- get_event_code()
- Return type:
int
- Returns:
Debug event code as defined in the Win32 API.
- get_event_description()
- Return type:
str
- Returns:
User-friendly description of the event.
- get_event_name()
- Return type:
str
- Returns:
User-friendly name of the event.
- get_pid()
See also
- Return type:
int
- Returns:
Process global ID where the event occured.
- get_tid()
See also
- Return type:
int
- Returns:
Thread global ID where the event occured.
- exception winappdbg.event.EventCallbackWarning
This warning is issued when an uncaught exception was raised by a user-defined event handler.
- class winappdbg.event.EventDispatcher(eventHandler=None)
Implements debug event dispatching capabilities.
- dispatch(event)
Sends event notifications to the
Debugobject and theEventHandlerobject provided by the user.The
Debugobject will forward the notifications to it’s contained snapshot objects (System,Process,ThreadandModule) when appropriate.Warning
This method is called automatically from
Debug.dispatch().See also
Debug.cont(),Debug.loop(),Debug.wait()- Parameters:
event (Event) – Event object passed to
Debug.dispatch().- Raises:
WindowsError – Raises an exception on error.
- get_event_handler()
Get the event handler.
See also
- Return type:
- Returns:
Current event handler object, or
None.
- static get_handler_method(eventHandler, event, fallback=None)
Retrieves the appropriate callback method from an
EventHandlerinstance for the givenEventobject.- Parameters:
eventHandler (EventHandler) – Event handler object whose methods we are examining.
event (Event) – Debugging event to be handled.
fallback (callable) – (Optional) If no suitable method is found in the
EventHandlerinstance, return this value.
- Return type:
callable
- Returns:
Bound method that will handle the debugging event. Returns
Noneif no such method is defined.
- set_event_handler(eventHandler)
Set the event handler.
Warning
This is normally not needed. Use with care!
- Parameters:
eventHandler (EventHandler) – New event handler object, or
None.- Return type:
- Returns:
Previous event handler object, or
None.- Raises:
TypeError – The event handler is of an incorrect type.
Note
The
eventHandlerparameter may be any callable Python object (for example a function, or an instance method). However you’ll probably find it more convenient to use an instance of a subclass ofEventHandlerhere.
- class winappdbg.event.EventHandler
Base class for debug event handlers.
Your program should subclass it to implement it’s own event handling.
The constructor can be overriden as long as you call the superclass constructor. The special method
__call__MUST NOT be overriden.The signature for event handlers is the following:
def event_handler(self, event):
Where event is an
Eventobject.Each event handler is named after the event they handle. This is the list of all valid event handler names:
event
Receives an
Eventobject or an object of any of it’s subclasses, and handles any event for which no handler was defined.unknown_event
Receives an
Eventobject or an object of any of it’s subclasses, and handles any event unknown to the debugging engine. (This is not likely to happen unless the Win32 debugging API is changed in future versions of Windows).exception
Receives an
ExceptionEventobject and handles any exception for which no handler was defined. See above for exception handlers.unknown_exception
Receives an
ExceptionEventobject and handles any exception unknown to the debugging engine. This usually happens for C++ exceptions, which are not standardized and may change from one compiler to the next.Currently we have partial support for C++ exceptions thrown by Microsoft compilers.
Also see: RaiseException()
create_thread
Receives a
CreateThreadEventobject.create_process
Receives a
CreateProcessEventobject.exit_thread
Receives a
ExitThreadEventobject.exit_process
Receives a
ExitProcessEventobject.load_dll
Receives a
LoadDLLEventobject.unload_dll
Receives an
UnloadDLLEventobject.output_string
Receives an
OutputDebugStringEventobject.rip
Receives a
RIPEventobject.
This is the list of all valid exception handler names (they all receive an
ExceptionEventobject):access_violation
array_bounds_exceeded
breakpoint
control_c_exit
datatype_misalignment
debug_control_c
float_denormal_operand
float_divide_by_zero
float_inexact_result
float_invalid_operation
float_overflow
float_stack_check
float_underflow
guard_page
illegal_instruction
in_page_error
integer_divide_by_zero
integer_overflow
invalid_disposition
invalid_handle
ms_vc_exception
noncontinuable_exception
possible_deadlock
privileged_instruction
single_step
stack_overflow
wow64_breakpoint
- Variables:
apiHooks (dict(str, list(tuple(str, int)))) –
Dictionary that maps module names to lists of tuples of ( procedure name, parameter count ).
All procedures listed here will be hooked for calls from the debugee. When this happens, the corresponding event handler can be notified both when the procedure is entered and when it’s left by the debugee.
For example, let’s hook the LoadLibraryEx() API call. This would be the declaration of apiHooks:
from winappdbg import EventHandler from winappdbg.win32 import * # (...) class MyEventHandler (EventHandler): apiHook = { "kernel32.dll" : ( # Procedure name Signature ( "LoadLibraryEx", (PVOID, HANDLE, DWORD) ), # (more procedures can go here...) ), # (more libraries can go here...) } # (your method definitions go here...)
Note that all pointer types are treated like void pointers, so your callback won’t get the string or structure pointed to by it, but the remote memory address instead. This is so to prevent the ctypes library from being “too helpful” and trying to dereference the pointer. To get the actual data being pointed to, use one of the
Process.read()methods.Now, to intercept calls to LoadLibraryEx define a method like this in your event handler class:
def pre_LoadLibraryEx(self, event, ra, lpFilename, hFile, dwFlags): szFilename = event.get_process().peek_string(lpFilename) # (...)
Note that the first parameter is always the
Eventobject, and the second parameter is the return address. The third parameter and above are the values passed to the hooked function.Finally, to intercept returns from calls to LoadLibraryEx define a method like this:
def post_LoadLibraryEx(self, event, retval): # (...)
The first parameter is the
Eventobject and the second is the return value from the hooked function.
- class winappdbg.event.EventSift(cls, *argv, **argd)
Event handler that allows you to use customized event handlers for each process you’re attached to.
This makes coding the event handlers much easier, because each instance will only “know” about one process. So you can code your event handler as if only one process was being debugged, but your debugger can attach to multiple processes.
Example:
from winappdbg import Debug, EventHandler, EventSift # This class was written assuming only one process is attached. # If you used it directly it would break when attaching to another # process, or when a child process is spawned. class MyEventHandler (EventHandler): def create_process(self, event): self.first = True self.name = event.get_process().get_filename() print("Attached to %s" % self.name) def breakpoint(self, event): if self.first: self.first = False print("First breakpoint reached at %s" % self.name) def exit_process(self, event): print("Detached from %s" % self.name) # Now when debugging we use the EventSift to be able to work with # multiple processes while keeping our code simple. :) if __name__ == "__main__": handler = EventSift(MyEventHandler) #handler = MyEventHandler() # try uncommenting this line... with Debug(handler) as debug: debug.execl("calc.exe") debug.execl("notepad.exe") debug.execl("charmap.exe") debug.loop()
Subclasses of EventSift can prevent specific event types from being forwarded by simply defining a method for it. That means your subclass can handle some event types globally while letting other types be handled on per-process basis. To forward events manually you can call
self.event(event).Example:
class MySift (EventSift): # Don't forward this event. def debug_control_c(self, event): pass # Handle this event globally without forwarding it. def output_string(self, event): print("Debug string: %s" % event.get_debug_string()) # Handle this event globally and then forward it. def create_process(self, event): print("New process created, PID: %d" % event.get_pid()) return self.event(event) # All other events will be forwarded.
Note that overriding the event method would cause no events to be forwarded at all. To prevent this, call the superclass implementation.
Example:
def we_want_to_forward_this_event(event): "Use whatever logic you want here..." # (...return True or False...) class MySift (EventSift): def event(self, event): # If the event matches some custom criteria... if we_want_to_forward_this_event(event): # Forward it. return super().event(event) # Otherwise, don't.
- Variables:
cls – Event handler class. There will be one instance of this class per debugged process in the
forwarddictionary.argv – Positional arguments to pass to the constructor of
cls.argd – Keyword arguments to pass to the constructor of
cls.forward – Dictionary that maps each debugged process ID to an instance of
cls.
- event(event)
Forwards events to the corresponding instance of your event handler for this process.
If you subclass
EventSiftand reimplement this method, no event will be forwarded at all unless you call the superclass implementation.If your filtering is based on the event type, there’s a much easier way to do it: just implement a handler for it.
- class winappdbg.event.ExceptionEvent(debug, raw)
Exception event.
- Variables:
exceptionName (dict(int, str)) – Mapping of exception constants to their names.
exceptionDescription (dict(int, str)) – Mapping of exception constants to user-friendly strings.
breakpoint (Breakpoint) – If the exception was caused by one of our breakpoints, this member contains a reference to the breakpoint object. Otherwise it’s not defined. It should only be used from the condition or action callback routines, instead of the event handler.
hook (Hook) – If the exception was caused by a function hook, this member contains a reference to the hook object. Otherwise it’s not defined. It should only be used from the hook callback routines, instead of the event handler.
- property eventMethod
str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.
- generate_minidump(filename, DumpType=None, bIncludeContext=True, bIncludeException=True, UserStreamParam=None, CallbackParam=None)
Generates a minidump file for the exception, including exception information.
This is an enhanced version of
Event.generate_minidump()that automatically captures the exception information for crash dumps.- Parameters:
filename (str) – Path to the output minidump file (.dmp).
DumpType (int) – Type of information to include in the minidump. See
Process.generate_minidump()for details.bIncludeContext (bool) – If
True(default), captures and includes the context (register state) of the thread where the exception occurred.bIncludeException (bool) – If
True(default), captures and includes the exception information in the minidump. This provides crash analysis tools with the exception record.UserStreamParam (MINIDUMP_USER_STREAM_INFORMATION or None) – Optional user-defined information streams.
CallbackParam (MINIDUMP_CALLBACK_INFORMATION or None) – Optional callback for customizing the dump.
- Raises:
WindowsError – On error an exception is raised.
Example:
class MyEventHandler(EventHandler): def access_violation(self, event): # Automatically capture exception and context event.generate_minidump("crash.dmp") def breakpoint(self, event): # Just capture state without exception record event.generate_minidump("debug.dmp", bIncludeException=False)
- get_exception_address()
- Return type:
int
- Returns:
Memory address where the exception occured.
- get_exception_code()
- Return type:
int
- Returns:
Exception code as defined by the Win32 API.
- get_exception_description()
- Return type:
str
- Returns:
User-friendly name of the exception.
- get_exception_information(index)
- Parameters:
index (int) – Index into the exception information block.
- Return type:
int
- Returns:
Exception information DWORD.
- get_exception_information_as_list()
- Return type:
list( int )
- Returns:
Exception information block.
- get_exception_name()
- Return type:
str
- Returns:
Name of the exception as defined by the Win32 API.
- get_fault_address()
- Return type:
int
- Returns:
Access violation memory address.
Note
This method is only meaningful for access violation exceptions, in-page memory error exceptions and guard page exceptions.
- Raises:
NotImplementedError – Wrong kind of exception.
- get_fault_type()
- Return type:
int
- Returns:
Access violation type. Should be one of the following constants:
win32.EXCEPTION_READ_FAULTwin32.EXCEPTION_WRITE_FAULTwin32.EXCEPTION_EXECUTE_FAULT
Note
This method is only meaningful for access violation exceptions, in-page memory error exceptions and guard page exceptions.
- Raises:
NotImplementedError – Wrong kind of exception.
- get_nested_exceptions()
Traverses the exception record linked list and builds a Python list.
Nested exception records are received for nested exceptions. This happens when an exception is raised in the debugee while trying to handle a previous exception.
- Return type:
list( ExceptionEvent )
- Returns:
List of ExceptionEvent objects representing each exception record found in this event.
There is always at least one exception record, so the list is never empty. All other methods of this class read from the first exception record only, that is, the most recent exception.
- get_ntstatus_code()
- Return type:
int
- Returns:
NTSTATUS status code that caused the exception.
Note
This method is only meaningful for in-page memory error exceptions.
- Raises:
NotImplementedError – Not an in-page memory error.
- get_raw_exception_record_list()
Traverses the exception record linked list and builds a Python list.
Nested exception records are received for nested exceptions. This happens when an exception is raised in the debugee while trying to handle a previous exception.
- Return type:
list( win32.EXCEPTION_RECORD )
- Returns:
List of raw exception record structures as used by the Win32 API.
There is always at least one exception record, so the list is never empty. All other methods of this class read from the first exception record only, that is, the most recent exception.
- is_continuable()
- Return type:
bool
- Returns:
The opposite of
is_noncontinuable().
- is_first_chance()
- Return type:
bool
- Returns:
Truefor first chance exceptions,Falsefor last chance.
- is_last_chance()
- Return type:
bool
- Returns:
The opposite of
is_first_chance().
- is_nested()
- Return type:
bool
- Returns:
Returns
Trueif there are additional exception records associated with this exception. This would mean the exception is nested, that is, it was triggered while trying to handle at least one previous exception.
- is_noncontinuable()
-
- Return type:
bool
- Returns:
Trueif the exception is noncontinuable,Falseotherwise.Attempting to continue a noncontinuable exception results in an
EXCEPTION_NONCONTINUABLE_EXCEPTIONexception to be raised.
- is_system_defined_exception()
- Return type:
bool
- Returns:
The opposite of
is_user_defined_exception().
- is_user_defined_exception()
Determines if this is an user-defined exception. User-defined exceptions may contain any exception code that is not system reserved.
Often the exception code is also a valid Win32 error code, but that’s up to the debugged application.
- Return type:
bool
- Returns:
Trueif the exception is user-defined,Falseotherwise.
- class winappdbg.event.ExitProcessEvent(debug, raw)
Process termination event.
- get_exit_code()
- Return type:
int
- Returns:
Exit code of the process.
- get_filename()
- Return type:
None or str
- Returns:
Filename of the main module.
Noneif the filename is unknown.
- get_image_base()
- Return type:
int
- Returns:
Base address of the main module.
- get_module()
- Return type:
Module- Returns:
Main module of the process.
- get_module_base()
- Return type:
int
- Returns:
Base address of the main module.
- class winappdbg.event.ExitThreadEvent(debug, raw)
Thread termination event.
- get_exit_code()
- Return type:
int
- Returns:
Exit code of the thread.
- class winappdbg.event.LoadDLLEvent(debug, raw)
Module load event.
- get_file_handle()
- Return type:
FileHandleor None- Returns:
File handle to the newly loaded DLL received from the system. Returns
Noneif the handle is not available.
- get_filename()
- Return type:
str, None
- Returns:
This method does it’s best to retrieve the filename to the newly loaded module. However, sometimes that’s not possible, and
Noneis returned instead.
- get_module()
- Return type:
Module- Returns:
Module object for the newly loaded DLL.
- get_module_base()
- Return type:
int
- Returns:
Base address for the newly loaded DLL.
- class winappdbg.event.NoEvent(debug, raw=None)
No event.
Dummy
Eventobject that can be used as a placeholder when no debug event has occured yet. It’s never returned by theEventFactory.- get_event_code()
- Return type:
int
- Returns:
Debug event code as defined in the Win32 API.
- get_pid()
See also
- Return type:
int
- Returns:
Process global ID where the event occured.
- get_tid()
See also
- Return type:
int
- Returns:
Thread global ID where the event occured.
- class winappdbg.event.OutputDebugStringEvent(debug, raw)
Debug string output event.
- get_debug_string()
- Return type:
bytes or str
- Returns:
String sent by the debugee. It may be ANSI or Unicode and may end with a null character.
- class winappdbg.event.RIPEvent(debug, raw)
RIP event.
- get_rip_error()
- Return type:
int
- Returns:
RIP error code as defined by the Win32 API.
- get_rip_type()
- Return type:
int
- Returns:
RIP type code as defined by the Win32 API. May be
0or one of the following:winappdbg.win32.SLE_ERRORwinappdbg.win32.SLE_MINORERRORwinappdbg.win32.SLE_WARNING
- class winappdbg.event.UnloadDLLEvent(debug, raw)
Module unload event.
- get_file_handle()
- Return type:
None or
FileHandle- Returns:
File handle to the recently unloaded DLL. Returns
Noneif the handle is not available.
- get_filename()
- Return type:
None or str
- Returns:
Filename of the recently unloaded DLL.
Noneif the filename is unknown.
- get_module()
- Return type:
Module- Returns:
Module object for the recently unloaded DLL.
- get_module_base()
- Return type:
int
- Returns:
Base address for the recently unloaded DLL.