1#!~/.wine/drive_c/Python25/python.exe 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2009-2014, Mario Vilas 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions are met: 9# 10# * Redistributions of source code must retain the above copyright notice, 11# this list of conditions and the following disclaimer. 12# * Redistributions in binary form must reproduce the above copyright 13# notice,this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# * Neither the name of the copyright holder nor the names of its 16# contributors may be used to endorse or promote products derived from 17# this software without specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29# POSSIBILITY OF SUCH DAMAGE. 30 31""" 32Event handling module. 33 34@see: U{http://apps.sourceforge.net/trac/winappdbg/wiki/Debugging} 35 36@group Debugging: 37 EventHandler, EventSift 38 39@group Debug events: 40 EventFactory, 41 EventDispatcher, 42 Event, 43 NoEvent, 44 CreateProcessEvent, 45 CreateThreadEvent, 46 ExitProcessEvent, 47 ExitThreadEvent, 48 LoadDLLEvent, 49 UnloadDLLEvent, 50 OutputDebugStringEvent, 51 RIPEvent, 52 ExceptionEvent 53 54@group Warnings: 55 EventCallbackWarning 56""" 57 58__revision__ = "$Id$" 59 60__all__ = [ 61 # Factory of Event objects and all of it's subclasses. 62 # Users should not need to instance Event objects directly. 63 'EventFactory', 64 65 # Event dispatcher used internally by the Debug class. 66 'EventDispatcher', 67 68 # Base classes for user-defined event handlers. 69 'EventHandler', 70 'EventSift', 71 72 # Warning for uncaught exceptions on event callbacks. 73 'EventCallbackWarning', 74 75 # Dummy event object that can be used as a placeholder. 76 # It's never returned by the EventFactory. 77 'NoEvent', 78 79 # Base class for event objects. 80 'Event', 81 82 # Event objects. 83 'CreateProcessEvent', 84 'CreateThreadEvent', 85 'ExitProcessEvent', 86 'ExitThreadEvent', 87 'LoadDLLEvent', 88 'UnloadDLLEvent', 89 'OutputDebugStringEvent', 90 'RIPEvent', 91 'ExceptionEvent' 92 ] 93 94from winappdbg import win32 95from winappdbg import compat 96from winappdbg.win32 import FileHandle, ProcessHandle, ThreadHandle 97from winappdbg.breakpoint import ApiHook 98from winappdbg.module import Module 99from winappdbg.thread import Thread 100from winappdbg.process import Process 101from winappdbg.textio import HexDump 102from winappdbg.util import StaticClass, PathOperations 103 104import sys 105import ctypes 106import warnings 107import traceback 108 109#============================================================================== 110 111class EventCallbackWarning (RuntimeWarning): 112 """ 113 This warning is issued when an uncaught exception was raised by a 114 user-defined event handler. 115 """ 116 117#============================================================================== 118 119class Event (object): 120 """ 121 Event object. 122 123 @type eventMethod: str 124 @cvar eventMethod: 125 Method name to call when using L{EventHandler} subclasses. 126 Used internally. 127 128 @type eventName: str 129 @cvar eventName: 130 User-friendly name of the event. 131 132 @type eventDescription: str 133 @cvar eventDescription: 134 User-friendly description of the event. 135 136 @type debug: L{Debug} 137 @ivar debug: 138 Debug object that received the event. 139 140 @type raw: L{DEBUG_EVENT} 141 @ivar raw: 142 Raw DEBUG_EVENT structure as used by the Win32 API. 143 144 @type continueStatus: int 145 @ivar continueStatus: 146 Continue status to pass to L{win32.ContinueDebugEvent}. 147 """ 148 149 eventMethod = 'unknown_event' 150 eventName = 'Unknown event' 151 eventDescription = 'A debug event of an unknown type has occured.' 152 153 def __init__(self, debug, raw): 154 """ 155 @type debug: L{Debug} 156 @param debug: Debug object that received the event. 157 158 @type raw: L{DEBUG_EVENT} 159 @param raw: Raw DEBUG_EVENT structure as used by the Win32 API. 160 """ 161 self.debug = debug 162 self.raw = raw 163 self.continueStatus = win32.DBG_EXCEPTION_NOT_HANDLED 164 165## @property 166## def debug(self): 167## """ 168## @rtype debug: L{Debug} 169## @return debug: 170## Debug object that received the event. 171## """ 172## return self.__debug() 173 174 def get_event_name(self): 175 """ 176 @rtype: str 177 @return: User-friendly name of the event. 178 """ 179 return self.eventName 180 181 def get_event_description(self): 182 """ 183 @rtype: str 184 @return: User-friendly description of the event. 185 """ 186 return self.eventDescription 187 188 def get_event_code(self): 189 """ 190 @rtype: int 191 @return: Debug event code as defined in the Win32 API. 192 """ 193 return self.raw.dwDebugEventCode 194 195## # Compatibility with version 1.0 196## # XXX to be removed in version 1.4 197## def get_code(self): 198## """ 199## Alias of L{get_event_code} for backwards compatibility 200## with WinAppDbg version 1.0. 201## Will be phased out in the next version. 202## 203## @rtype: int 204## @return: Debug event code as defined in the Win32 API. 205## """ 206## return self.get_event_code() 207 208 def get_pid(self): 209 """ 210 @see: L{get_process} 211 212 @rtype: int 213 @return: Process global ID where the event occured. 214 """ 215 return self.raw.dwProcessId 216 217 def get_tid(self): 218 """ 219 @see: L{get_thread} 220 221 @rtype: int 222 @return: Thread global ID where the event occured. 223 """ 224 return self.raw.dwThreadId 225 226 def get_process(self): 227 """ 228 @see: L{get_pid} 229 230 @rtype: L{Process} 231 @return: Process where the event occured. 232 """ 233 pid = self.get_pid() 234 system = self.debug.system 235 if system.has_process(pid): 236 process = system.get_process(pid) 237 else: 238 # XXX HACK 239 # The process object was missing for some reason, so make a new one. 240 process = Process(pid) 241 system._add_process(process) 242## process.scan_threads() # not needed 243 process.scan_modules() 244 return process 245 246 def get_thread(self): 247 """ 248 @see: L{get_tid} 249 250 @rtype: L{Thread} 251 @return: Thread where the event occured. 252 """ 253 tid = self.get_tid() 254 process = self.get_process() 255 if process.has_thread(tid): 256 thread = process.get_thread(tid) 257 else: 258 # XXX HACK 259 # The thread object was missing for some reason, so make a new one. 260 thread = Thread(tid) 261 process._add_thread(thread) 262 return thread 263 264#============================================================================== 265 266class NoEvent (Event): 267 """ 268 No event. 269 270 Dummy L{Event} object that can be used as a placeholder when no debug 271 event has occured yet. It's never returned by the L{EventFactory}. 272 """ 273 274 eventMethod = 'no_event' 275 eventName = 'No event' 276 eventDescription = 'No debug event has occured.' 277 278 def __init__(self, debug, raw = None): 279 Event.__init__(self, debug, raw) 280 281 def __len__(self): 282 """ 283 Always returns C{0}, so when evaluating the object as a boolean it's 284 always C{False}. This prevents L{Debug.cont} from trying to continue 285 a dummy event. 286 """ 287 return 0 288 289 def get_event_code(self): 290 return -1 291 292 def get_pid(self): 293 return -1 294 295 def get_tid(self): 296 return -1 297 298 def get_process(self): 299 return Process(self.get_pid()) 300 301 def get_thread(self): 302 return Thread(self.get_tid()) 303 304#============================================================================== 305 306class ExceptionEvent (Event): 307 """ 308 Exception event. 309 310 @type exceptionName: dict( int S{->} str ) 311 @cvar exceptionName: 312 Mapping of exception constants to their names. 313 314 @type exceptionDescription: dict( int S{->} str ) 315 @cvar exceptionDescription: 316 Mapping of exception constants to user-friendly strings. 317 318 @type breakpoint: L{Breakpoint} 319 @ivar breakpoint: 320 If the exception was caused by one of our breakpoints, this member 321 contains a reference to the breakpoint object. Otherwise it's not 322 defined. It should only be used from the condition or action callback 323 routines, instead of the event handler. 324 325 @type hook: L{Hook} 326 @ivar hook: 327 If the exception was caused by a function hook, this member contains a 328 reference to the hook object. Otherwise it's not defined. It should 329 only be used from the hook callback routines, instead of the event 330 handler. 331 """ 332 333 eventName = 'Exception event' 334 eventDescription = 'An exception was raised by the debugee.' 335 336 __exceptionMethod = { 337 win32.EXCEPTION_ACCESS_VIOLATION : 'access_violation', 338 win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED : 'array_bounds_exceeded', 339 win32.EXCEPTION_BREAKPOINT : 'breakpoint', 340 win32.EXCEPTION_DATATYPE_MISALIGNMENT : 'datatype_misalignment', 341 win32.EXCEPTION_FLT_DENORMAL_OPERAND : 'float_denormal_operand', 342 win32.EXCEPTION_FLT_DIVIDE_BY_ZERO : 'float_divide_by_zero', 343 win32.EXCEPTION_FLT_INEXACT_RESULT : 'float_inexact_result', 344 win32.EXCEPTION_FLT_INVALID_OPERATION : 'float_invalid_operation', 345 win32.EXCEPTION_FLT_OVERFLOW : 'float_overflow', 346 win32.EXCEPTION_FLT_STACK_CHECK : 'float_stack_check', 347 win32.EXCEPTION_FLT_UNDERFLOW : 'float_underflow', 348 win32.EXCEPTION_ILLEGAL_INSTRUCTION : 'illegal_instruction', 349 win32.EXCEPTION_IN_PAGE_ERROR : 'in_page_error', 350 win32.EXCEPTION_INT_DIVIDE_BY_ZERO : 'integer_divide_by_zero', 351 win32.EXCEPTION_INT_OVERFLOW : 'integer_overflow', 352 win32.EXCEPTION_INVALID_DISPOSITION : 'invalid_disposition', 353 win32.EXCEPTION_NONCONTINUABLE_EXCEPTION : 'noncontinuable_exception', 354 win32.EXCEPTION_PRIV_INSTRUCTION : 'privileged_instruction', 355 win32.EXCEPTION_SINGLE_STEP : 'single_step', 356 win32.EXCEPTION_STACK_OVERFLOW : 'stack_overflow', 357 win32.EXCEPTION_GUARD_PAGE : 'guard_page', 358 win32.EXCEPTION_INVALID_HANDLE : 'invalid_handle', 359 win32.EXCEPTION_POSSIBLE_DEADLOCK : 'possible_deadlock', 360 win32.EXCEPTION_WX86_BREAKPOINT : 'wow64_breakpoint', 361 win32.CONTROL_C_EXIT : 'control_c_exit', 362 win32.DBG_CONTROL_C : 'debug_control_c', 363 win32.MS_VC_EXCEPTION : 'ms_vc_exception', 364 } 365 366 __exceptionName = { 367 win32.EXCEPTION_ACCESS_VIOLATION : 'EXCEPTION_ACCESS_VIOLATION', 368 win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED : 'EXCEPTION_ARRAY_BOUNDS_EXCEEDED', 369 win32.EXCEPTION_BREAKPOINT : 'EXCEPTION_BREAKPOINT', 370 win32.EXCEPTION_DATATYPE_MISALIGNMENT : 'EXCEPTION_DATATYPE_MISALIGNMENT', 371 win32.EXCEPTION_FLT_DENORMAL_OPERAND : 'EXCEPTION_FLT_DENORMAL_OPERAND', 372 win32.EXCEPTION_FLT_DIVIDE_BY_ZERO : 'EXCEPTION_FLT_DIVIDE_BY_ZERO', 373 win32.EXCEPTION_FLT_INEXACT_RESULT : 'EXCEPTION_FLT_INEXACT_RESULT', 374 win32.EXCEPTION_FLT_INVALID_OPERATION : 'EXCEPTION_FLT_INVALID_OPERATION', 375 win32.EXCEPTION_FLT_OVERFLOW : 'EXCEPTION_FLT_OVERFLOW', 376 win32.EXCEPTION_FLT_STACK_CHECK : 'EXCEPTION_FLT_STACK_CHECK', 377 win32.EXCEPTION_FLT_UNDERFLOW : 'EXCEPTION_FLT_UNDERFLOW', 378 win32.EXCEPTION_ILLEGAL_INSTRUCTION : 'EXCEPTION_ILLEGAL_INSTRUCTION', 379 win32.EXCEPTION_IN_PAGE_ERROR : 'EXCEPTION_IN_PAGE_ERROR', 380 win32.EXCEPTION_INT_DIVIDE_BY_ZERO : 'EXCEPTION_INT_DIVIDE_BY_ZERO', 381 win32.EXCEPTION_INT_OVERFLOW : 'EXCEPTION_INT_OVERFLOW', 382 win32.EXCEPTION_INVALID_DISPOSITION : 'EXCEPTION_INVALID_DISPOSITION', 383 win32.EXCEPTION_NONCONTINUABLE_EXCEPTION : 'EXCEPTION_NONCONTINUABLE_EXCEPTION', 384 win32.EXCEPTION_PRIV_INSTRUCTION : 'EXCEPTION_PRIV_INSTRUCTION', 385 win32.EXCEPTION_SINGLE_STEP : 'EXCEPTION_SINGLE_STEP', 386 win32.EXCEPTION_STACK_OVERFLOW : 'EXCEPTION_STACK_OVERFLOW', 387 win32.EXCEPTION_GUARD_PAGE : 'EXCEPTION_GUARD_PAGE', 388 win32.EXCEPTION_INVALID_HANDLE : 'EXCEPTION_INVALID_HANDLE', 389 win32.EXCEPTION_POSSIBLE_DEADLOCK : 'EXCEPTION_POSSIBLE_DEADLOCK', 390 win32.EXCEPTION_WX86_BREAKPOINT : 'EXCEPTION_WX86_BREAKPOINT', 391 win32.CONTROL_C_EXIT : 'CONTROL_C_EXIT', 392 win32.DBG_CONTROL_C : 'DBG_CONTROL_C', 393 win32.MS_VC_EXCEPTION : 'MS_VC_EXCEPTION', 394 } 395 396 __exceptionDescription = { 397 win32.EXCEPTION_ACCESS_VIOLATION : 'Access violation', 398 win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED : 'Array bounds exceeded', 399 win32.EXCEPTION_BREAKPOINT : 'Breakpoint', 400 win32.EXCEPTION_DATATYPE_MISALIGNMENT : 'Datatype misalignment', 401 win32.EXCEPTION_FLT_DENORMAL_OPERAND : 'Float denormal operand', 402 win32.EXCEPTION_FLT_DIVIDE_BY_ZERO : 'Float divide by zero', 403 win32.EXCEPTION_FLT_INEXACT_RESULT : 'Float inexact result', 404 win32.EXCEPTION_FLT_INVALID_OPERATION : 'Float invalid operation', 405 win32.EXCEPTION_FLT_OVERFLOW : 'Float overflow', 406 win32.EXCEPTION_FLT_STACK_CHECK : 'Float stack check', 407 win32.EXCEPTION_FLT_UNDERFLOW : 'Float underflow', 408 win32.EXCEPTION_ILLEGAL_INSTRUCTION : 'Illegal instruction', 409 win32.EXCEPTION_IN_PAGE_ERROR : 'In-page error', 410 win32.EXCEPTION_INT_DIVIDE_BY_ZERO : 'Integer divide by zero', 411 win32.EXCEPTION_INT_OVERFLOW : 'Integer overflow', 412 win32.EXCEPTION_INVALID_DISPOSITION : 'Invalid disposition', 413 win32.EXCEPTION_NONCONTINUABLE_EXCEPTION : 'Noncontinuable exception', 414 win32.EXCEPTION_PRIV_INSTRUCTION : 'Privileged instruction', 415 win32.EXCEPTION_SINGLE_STEP : 'Single step event', 416 win32.EXCEPTION_STACK_OVERFLOW : 'Stack limits overflow', 417 win32.EXCEPTION_GUARD_PAGE : 'Guard page hit', 418 win32.EXCEPTION_INVALID_HANDLE : 'Invalid handle', 419 win32.EXCEPTION_POSSIBLE_DEADLOCK : 'Possible deadlock', 420 win32.EXCEPTION_WX86_BREAKPOINT : 'WOW64 breakpoint', 421 win32.CONTROL_C_EXIT : 'Control-C exit', 422 win32.DBG_CONTROL_C : 'Debug Control-C', 423 win32.MS_VC_EXCEPTION : 'Microsoft Visual C++ exception', 424 } 425 426 @property 427 def eventMethod(self): 428 return self.__exceptionMethod.get( 429 self.get_exception_code(), 'unknown_exception') 430 431 def get_exception_name(self): 432 """ 433 @rtype: str 434 @return: Name of the exception as defined by the Win32 API. 435 """ 436 code = self.get_exception_code() 437 unk = HexDump.integer(code) 438 return self.__exceptionName.get(code, unk) 439 440 def get_exception_description(self): 441 """ 442 @rtype: str 443 @return: User-friendly name of the exception. 444 """ 445 code = self.get_exception_code() 446 description = self.__exceptionDescription.get(code, None) 447 if description is None: 448 try: 449 description = 'Exception code %s (%s)' 450 description = description % (HexDump.integer(code), 451 ctypes.FormatError(code)) 452 except OverflowError: 453 description = 'Exception code %s' % HexDump.integer(code) 454 return description 455 456 def is_first_chance(self): 457 """ 458 @rtype: bool 459 @return: C{True} for first chance exceptions, C{False} for last chance. 460 """ 461 return self.raw.u.Exception.dwFirstChance != 0 462 463 def is_last_chance(self): 464 """ 465 @rtype: bool 466 @return: The opposite of L{is_first_chance}. 467 """ 468 return not self.is_first_chance() 469 470 def is_noncontinuable(self): 471 """ 472 @see: U{http://msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx} 473 474 @rtype: bool 475 @return: C{True} if the exception is noncontinuable, 476 C{False} otherwise. 477 478 Attempting to continue a noncontinuable exception results in an 479 EXCEPTION_NONCONTINUABLE_EXCEPTION exception to be raised. 480 """ 481 return bool( self.raw.u.Exception.ExceptionRecord.ExceptionFlags & \ 482 win32.EXCEPTION_NONCONTINUABLE ) 483 484 def is_continuable(self): 485 """ 486 @rtype: bool 487 @return: The opposite of L{is_noncontinuable}. 488 """ 489 return not self.is_noncontinuable() 490 491 def is_user_defined_exception(self): 492 """ 493 Determines if this is an user-defined exception. User-defined 494 exceptions may contain any exception code that is not system reserved. 495 496 Often the exception code is also a valid Win32 error code, but that's 497 up to the debugged application. 498 499 @rtype: bool 500 @return: C{True} if the exception is user-defined, C{False} otherwise. 501 """ 502 return self.get_exception_code() & 0x10000000 == 0 503 504 def is_system_defined_exception(self): 505 """ 506 @rtype: bool 507 @return: The opposite of L{is_user_defined_exception}. 508 """ 509 return not self.is_user_defined_exception() 510 511 def get_exception_code(self): 512 """ 513 @rtype: int 514 @return: Exception code as defined by the Win32 API. 515 """ 516 return self.raw.u.Exception.ExceptionRecord.ExceptionCode 517 518 def get_exception_address(self): 519 """ 520 @rtype: int 521 @return: Memory address where the exception occured. 522 """ 523 address = self.raw.u.Exception.ExceptionRecord.ExceptionAddress 524 if address is None: 525 address = 0 526 return address 527 528 def get_exception_information(self, index): 529 """ 530 @type index: int 531 @param index: Index into the exception information block. 532 533 @rtype: int 534 @return: Exception information DWORD. 535 """ 536 if index < 0 or index > win32.EXCEPTION_MAXIMUM_PARAMETERS: 537 raise IndexError("Array index out of range: %s" % repr(index)) 538 info = self.raw.u.Exception.ExceptionRecord.ExceptionInformation 539 value = info[index] 540 if value is None: 541 value = 0 542 return value 543 544 def get_exception_information_as_list(self): 545 """ 546 @rtype: list( int ) 547 @return: Exception information block. 548 """ 549 info = self.raw.u.Exception.ExceptionRecord.ExceptionInformation 550 data = list() 551 for index in compat.xrange(0, win32.EXCEPTION_MAXIMUM_PARAMETERS): 552 value = info[index] 553 if value is None: 554 value = 0 555 data.append(value) 556 return data 557 558 def get_fault_type(self): 559 """ 560 @rtype: int 561 @return: Access violation type. 562 Should be one of the following constants: 563 564 - L{win32.EXCEPTION_READ_FAULT} 565 - L{win32.EXCEPTION_WRITE_FAULT} 566 - L{win32.EXCEPTION_EXECUTE_FAULT} 567 568 @note: This method is only meaningful for access violation exceptions, 569 in-page memory error exceptions and guard page exceptions. 570 571 @raise NotImplementedError: Wrong kind of exception. 572 """ 573 if self.get_exception_code() not in (win32.EXCEPTION_ACCESS_VIOLATION, 574 win32.EXCEPTION_IN_PAGE_ERROR, win32.EXCEPTION_GUARD_PAGE): 575 msg = "This method is not meaningful for %s." 576 raise NotImplementedError(msg % self.get_exception_name()) 577 return self.get_exception_information(0) 578 579 def get_fault_address(self): 580 """ 581 @rtype: int 582 @return: Access violation memory address. 583 584 @note: This method is only meaningful for access violation exceptions, 585 in-page memory error exceptions and guard page exceptions. 586 587 @raise NotImplementedError: Wrong kind of exception. 588 """ 589 if self.get_exception_code() not in (win32.EXCEPTION_ACCESS_VIOLATION, 590 win32.EXCEPTION_IN_PAGE_ERROR, win32.EXCEPTION_GUARD_PAGE): 591 msg = "This method is not meaningful for %s." 592 raise NotImplementedError(msg % self.get_exception_name()) 593 return self.get_exception_information(1) 594 595 def get_ntstatus_code(self): 596 """ 597 @rtype: int 598 @return: NTSTATUS status code that caused the exception. 599 600 @note: This method is only meaningful for in-page memory error 601 exceptions. 602 603 @raise NotImplementedError: Not an in-page memory error. 604 """ 605 if self.get_exception_code() != win32.EXCEPTION_IN_PAGE_ERROR: 606 msg = "This method is only meaningful "\ 607 "for in-page memory error exceptions." 608 raise NotImplementedError(msg) 609 return self.get_exception_information(2) 610 611 def is_nested(self): 612 """ 613 @rtype: bool 614 @return: Returns C{True} if there are additional exception records 615 associated with this exception. This would mean the exception 616 is nested, that is, it was triggered while trying to handle 617 at least one previous exception. 618 """ 619 return bool(self.raw.u.Exception.ExceptionRecord.ExceptionRecord) 620 621 def get_raw_exception_record_list(self): 622 """ 623 Traverses the exception record linked list and builds a Python list. 624 625 Nested exception records are received for nested exceptions. This 626 happens when an exception is raised in the debugee while trying to 627 handle a previous exception. 628 629 @rtype: list( L{win32.EXCEPTION_RECORD} ) 630 @return: 631 List of raw exception record structures as used by the Win32 API. 632 633 There is always at least one exception record, so the list is 634 never empty. All other methods of this class read from the first 635 exception record only, that is, the most recent exception. 636 """ 637 # The first EXCEPTION_RECORD is contained in EXCEPTION_DEBUG_INFO. 638 # The remaining EXCEPTION_RECORD structures are linked by pointers. 639 nested = list() 640 record = self.raw.u.Exception 641 while True: 642 record = record.ExceptionRecord 643 if not record: 644 break 645 nested.append(record) 646 return nested 647 648 def get_nested_exceptions(self): 649 """ 650 Traverses the exception record linked list and builds a Python list. 651 652 Nested exception records are received for nested exceptions. This 653 happens when an exception is raised in the debugee while trying to 654 handle a previous exception. 655 656 @rtype: list( L{ExceptionEvent} ) 657 @return: 658 List of ExceptionEvent objects representing each exception record 659 found in this event. 660 661 There is always at least one exception record, so the list is 662 never empty. All other methods of this class read from the first 663 exception record only, that is, the most recent exception. 664 """ 665 # The list always begins with ourselves. 666 # Just put a reference to "self" as the first element, 667 # and start looping from the second exception record. 668 nested = [ self ] 669 raw = self.raw 670 dwDebugEventCode = raw.dwDebugEventCode 671 dwProcessId = raw.dwProcessId 672 dwThreadId = raw.dwThreadId 673 dwFirstChance = raw.u.Exception.dwFirstChance 674 record = raw.u.Exception.ExceptionRecord 675 while True: 676 record = record.ExceptionRecord 677 if not record: 678 break 679 raw = win32.DEBUG_EVENT() 680 raw.dwDebugEventCode = dwDebugEventCode 681 raw.dwProcessId = dwProcessId 682 raw.dwThreadId = dwThreadId 683 raw.u.Exception.ExceptionRecord = record 684 raw.u.Exception.dwFirstChance = dwFirstChance 685 event = EventFactory.get(self.debug, raw) 686 nested.append(event) 687 return nested 688 689#============================================================================== 690 691class CreateThreadEvent (Event): 692 """ 693 Thread creation event. 694 """ 695 696 eventMethod = 'create_thread' 697 eventName = 'Thread creation event' 698 eventDescription = 'A new thread has started.' 699 700 def get_thread_handle(self): 701 """ 702 @rtype: L{ThreadHandle} 703 @return: Thread handle received from the system. 704 Returns C{None} if the handle is not available. 705 """ 706 # The handle doesn't need to be closed. 707 # See http://msdn.microsoft.com/en-us/library/ms681423(VS.85).aspx 708 hThread = self.raw.u.CreateThread.hThread 709 if hThread in (0, win32.NULL, win32.INVALID_HANDLE_VALUE): 710 hThread = None 711 else: 712 hThread = ThreadHandle(hThread, False, win32.THREAD_ALL_ACCESS) 713 return hThread 714 715 def get_teb(self): 716 """ 717 @rtype: int 718 @return: Pointer to the TEB. 719 """ 720 return self.raw.u.CreateThread.lpThreadLocalBase 721 722 def get_start_address(self): 723 """ 724 @rtype: int 725 @return: Pointer to the first instruction to execute in this thread. 726 727 Returns C{NULL} when the debugger attached to a process 728 and the thread already existed. 729 730 See U{http://msdn.microsoft.com/en-us/library/ms679295(VS.85).aspx} 731 """ 732 return self.raw.u.CreateThread.lpStartAddress 733 734#============================================================================== 735 736class CreateProcessEvent (Event): 737 """ 738 Process creation event. 739 """ 740 741 eventMethod = 'create_process' 742 eventName = 'Process creation event' 743 eventDescription = 'A new process has started.' 744 745 def get_file_handle(self): 746 """ 747 @rtype: L{FileHandle} or None 748 @return: File handle to the main module, received from the system. 749 Returns C{None} if the handle is not available. 750 """ 751 # This handle DOES need to be closed. 752 # Therefore we must cache it so it doesn't 753 # get closed after the first call. 754 try: 755 hFile = self.__hFile 756 except AttributeError: 757 hFile = self.raw.u.CreateProcessInfo.hFile 758 if hFile in (0, win32.NULL, win32.INVALID_HANDLE_VALUE): 759 hFile = None 760 else: 761 hFile = FileHandle(hFile, True) 762 self.__hFile = hFile 763 return hFile 764 765 def get_process_handle(self): 766 """ 767 @rtype: L{ProcessHandle} 768 @return: Process handle received from the system. 769 Returns C{None} if the handle is not available. 770 """ 771 # The handle doesn't need to be closed. 772 # See http://msdn.microsoft.com/en-us/library/ms681423(VS.85).aspx 773 hProcess = self.raw.u.CreateProcessInfo.hProcess 774 if hProcess in (0, win32.NULL, win32.INVALID_HANDLE_VALUE): 775 hProcess = None 776 else: 777 hProcess = ProcessHandle(hProcess, False, win32.PROCESS_ALL_ACCESS) 778 return hProcess 779 780 def get_thread_handle(self): 781 """ 782 @rtype: L{ThreadHandle} 783 @return: Thread handle received from the system. 784 Returns C{None} if the handle is not available. 785 """ 786 # The handle doesn't need to be closed. 787 # See http://msdn.microsoft.com/en-us/library/ms681423(VS.85).aspx 788 hThread = self.raw.u.CreateProcessInfo.hThread 789 if hThread in (0, win32.NULL, win32.INVALID_HANDLE_VALUE): 790 hThread = None 791 else: 792 hThread = ThreadHandle(hThread, False, win32.THREAD_ALL_ACCESS) 793 return hThread 794 795 def get_start_address(self): 796 """ 797 @rtype: int 798 @return: Pointer to the first instruction to execute in this process. 799 800 Returns C{NULL} when the debugger attaches to a process. 801 802 See U{http://msdn.microsoft.com/en-us/library/ms679295(VS.85).aspx} 803 """ 804 return self.raw.u.CreateProcessInfo.lpStartAddress 805 806 def get_image_base(self): 807 """ 808 @rtype: int 809 @return: Base address of the main module. 810 @warn: This value is taken from the PE file 811 and may be incorrect because of ASLR! 812 """ 813 # TODO try to calculate the real value when ASLR is active. 814 return self.raw.u.CreateProcessInfo.lpBaseOfImage 815 816 def get_teb(self): 817 """ 818 @rtype: int 819 @return: Pointer to the TEB. 820 """ 821 return self.raw.u.CreateProcessInfo.lpThreadLocalBase 822 823 def get_debug_info(self): 824 """ 825 @rtype: str 826 @return: Debugging information. 827 """ 828 raw = self.raw.u.CreateProcessInfo 829 ptr = raw.lpBaseOfImage + raw.dwDebugInfoFileOffset 830 size = raw.nDebugInfoSize 831 data = self.get_process().peek(ptr, size) 832 if len(data) == size: 833 return data 834 return None 835 836 def get_filename(self): 837 """ 838 @rtype: str, None 839 @return: This method does it's best to retrieve the filename to 840 the main module of the process. However, sometimes that's not 841 possible, and C{None} is returned instead. 842 """ 843 844 # Try to get the filename from the file handle. 845 szFilename = None 846 hFile = self.get_file_handle() 847 if hFile: 848 szFilename = hFile.get_filename() 849 if not szFilename: 850 851 # Try to get it from CREATE_PROCESS_DEBUG_INFO.lpImageName 852 # It's NULL or *NULL most of the times, see MSDN: 853 # http://msdn.microsoft.com/en-us/library/ms679286(VS.85).aspx 854 aProcess = self.get_process() 855 lpRemoteFilenamePtr = self.raw.u.CreateProcessInfo.lpImageName 856 if lpRemoteFilenamePtr: 857 lpFilename = aProcess.peek_uint(lpRemoteFilenamePtr) 858 fUnicode = bool( self.raw.u.CreateProcessInfo.fUnicode ) 859 szFilename = aProcess.peek_string(lpFilename, fUnicode) 860 861 # XXX TODO 862 # Sometimes the filename is relative (ntdll.dll, kernel32.dll). 863 # It could be converted to an absolute pathname (SearchPath). 864 865 # Try to get it from Process.get_image_name(). 866 if not szFilename: 867 szFilename = aProcess.get_image_name() 868 869 # Return the filename, or None on error. 870 return szFilename 871 872 def get_module_base(self): 873 """ 874 @rtype: int 875 @return: Base address of the main module. 876 """ 877 return self.get_image_base() 878 879 def get_module(self): 880 """ 881 @rtype: L{Module} 882 @return: Main module of the process. 883 """ 884 return self.get_process().get_module( self.get_module_base() ) 885 886#============================================================================== 887 888class ExitThreadEvent (Event): 889 """ 890 Thread termination event. 891 """ 892 893 eventMethod = 'exit_thread' 894 eventName = 'Thread termination event' 895 eventDescription = 'A thread has finished executing.' 896 897 def get_exit_code(self): 898 """ 899 @rtype: int 900 @return: Exit code of the thread. 901 """ 902 return self.raw.u.ExitThread.dwExitCode 903 904#============================================================================== 905 906class ExitProcessEvent (Event): 907 """ 908 Process termination event. 909 """ 910 911 eventMethod = 'exit_process' 912 eventName = 'Process termination event' 913 eventDescription = 'A process has finished executing.' 914 915 def get_exit_code(self): 916 """ 917 @rtype: int 918 @return: Exit code of the process. 919 """ 920 return self.raw.u.ExitProcess.dwExitCode 921 922 def get_filename(self): 923 """ 924 @rtype: None or str 925 @return: Filename of the main module. 926 C{None} if the filename is unknown. 927 """ 928 return self.get_module().get_filename() 929 930 def get_image_base(self): 931 """ 932 @rtype: int 933 @return: Base address of the main module. 934 """ 935 return self.get_module_base() 936 937 def get_module_base(self): 938 """ 939 @rtype: int 940 @return: Base address of the main module. 941 """ 942 return self.get_module().get_base() 943 944 def get_module(self): 945 """ 946 @rtype: L{Module} 947 @return: Main module of the process. 948 """ 949 return self.get_process().get_main_module() 950 951#============================================================================== 952 953class LoadDLLEvent (Event): 954 """ 955 Module load event. 956 """ 957 958 eventMethod = 'load_dll' 959 eventName = 'Module load event' 960 eventDescription = 'A new DLL library was loaded by the debugee.' 961 962 def get_module_base(self): 963 """ 964 @rtype: int 965 @return: Base address for the newly loaded DLL. 966 """ 967 return self.raw.u.LoadDll.lpBaseOfDll 968 969 def get_module(self): 970 """ 971 @rtype: L{Module} 972 @return: Module object for the newly loaded DLL. 973 """ 974 lpBaseOfDll = self.get_module_base() 975 aProcess = self.get_process() 976 if aProcess.has_module(lpBaseOfDll): 977 aModule = aProcess.get_module(lpBaseOfDll) 978 else: 979 # XXX HACK 980 # For some reason the module object is missing, so make a new one. 981 aModule = Module(lpBaseOfDll, 982 hFile = self.get_file_handle(), 983 fileName = self.get_filename(), 984 process = aProcess) 985 aProcess._add_module(aModule) 986 return aModule 987 988 def get_file_handle(self): 989 """ 990 @rtype: L{FileHandle} or None 991 @return: File handle to the newly loaded DLL received from the system. 992 Returns C{None} if the handle is not available. 993 """ 994 # This handle DOES need to be closed. 995 # Therefore we must cache it so it doesn't 996 # get closed after the first call. 997 try: 998 hFile = self.__hFile 999 except AttributeError: 1000 hFile = self.raw.u.LoadDll.hFile 1001 if hFile in (0, win32.NULL, win32.INVALID_HANDLE_VALUE): 1002 hFile = None 1003 else: 1004 hFile = FileHandle(hFile, True) 1005 self.__hFile = hFile 1006 return hFile 1007 1008 def get_filename(self): 1009 """ 1010 @rtype: str, None 1011 @return: This method does it's best to retrieve the filename to 1012 the newly loaded module. However, sometimes that's not 1013 possible, and C{None} is returned instead. 1014 """ 1015 szFilename = None 1016 1017 # Try to get it from LOAD_DLL_DEBUG_INFO.lpImageName 1018 # It's NULL or *NULL most of the times, see MSDN: 1019 # http://msdn.microsoft.com/en-us/library/ms679286(VS.85).aspx 1020 aProcess = self.get_process() 1021 lpRemoteFilenamePtr = self.raw.u.LoadDll.lpImageName 1022 if lpRemoteFilenamePtr: 1023 lpFilename = aProcess.peek_uint(lpRemoteFilenamePtr) 1024 fUnicode = bool( self.raw.u.LoadDll.fUnicode ) 1025 szFilename = aProcess.peek_string(lpFilename, fUnicode) 1026 if not szFilename: 1027 szFilename = None 1028 1029 # Try to get the filename from the file handle. 1030 if not szFilename: 1031 hFile = self.get_file_handle() 1032 if hFile: 1033 szFilename = hFile.get_filename() 1034 1035 # Return the filename, or None on error. 1036 return szFilename 1037 1038#============================================================================== 1039 1040class UnloadDLLEvent (Event): 1041 """ 1042 Module unload event. 1043 """ 1044 1045 eventMethod = 'unload_dll' 1046 eventName = 'Module unload event' 1047 eventDescription = 'A DLL library was unloaded by the debugee.' 1048 1049 def get_module_base(self): 1050 """ 1051 @rtype: int 1052 @return: Base address for the recently unloaded DLL. 1053 """ 1054 return self.raw.u.UnloadDll.lpBaseOfDll 1055 1056 def get_module(self): 1057 """ 1058 @rtype: L{Module} 1059 @return: Module object for the recently unloaded DLL. 1060 """ 1061 lpBaseOfDll = self.get_module_base() 1062 aProcess = self.get_process() 1063 if aProcess.has_module(lpBaseOfDll): 1064 aModule = aProcess.get_module(lpBaseOfDll) 1065 else: 1066 aModule = Module(lpBaseOfDll, process = aProcess) 1067 aProcess._add_module(aModule) 1068 return aModule 1069 1070 def get_file_handle(self): 1071 """ 1072 @rtype: None or L{FileHandle} 1073 @return: File handle to the recently unloaded DLL. 1074 Returns C{None} if the handle is not available. 1075 """ 1076 hFile = self.get_module().hFile 1077 if hFile in (0, win32.NULL, win32.INVALID_HANDLE_VALUE): 1078 hFile = None 1079 return hFile 1080 1081 def get_filename(self): 1082 """ 1083 @rtype: None or str 1084 @return: Filename of the recently unloaded DLL. 1085 C{None} if the filename is unknown. 1086 """ 1087 return self.get_module().get_filename() 1088 1089#============================================================================== 1090 1091class OutputDebugStringEvent (Event): 1092 """ 1093 Debug string output event. 1094 """ 1095 1096 eventMethod = 'output_string' 1097 eventName = 'Debug string output event' 1098 eventDescription = 'The debugee sent a message to the debugger.' 1099 1100 def get_debug_string(self): 1101 """ 1102 @rtype: str, compat.unicode 1103 @return: String sent by the debugee. 1104 It may be ANSI or Unicode and may end with a null character. 1105 """ 1106 return self.get_process().peek_string( 1107 self.raw.u.DebugString.lpDebugStringData, 1108 bool( self.raw.u.DebugString.fUnicode ), 1109 self.raw.u.DebugString.nDebugStringLength) 1110 1111#============================================================================== 1112 1113class RIPEvent (Event): 1114 """ 1115 RIP event. 1116 """ 1117 1118 eventMethod = 'rip' 1119 eventName = 'RIP event' 1120 eventDescription = 'An error has occured and the process ' \ 1121 'can no longer be debugged.' 1122 1123 def get_rip_error(self): 1124 """ 1125 @rtype: int 1126 @return: RIP error code as defined by the Win32 API. 1127 """ 1128 return self.raw.u.RipInfo.dwError 1129 1130 def get_rip_type(self): 1131 """ 1132 @rtype: int 1133 @return: RIP type code as defined by the Win32 API. 1134 May be C{0} or one of the following: 1135 - L{win32.SLE_ERROR} 1136 - L{win32.SLE_MINORERROR} 1137 - L{win32.SLE_WARNING} 1138 """ 1139 return self.raw.u.RipInfo.dwType 1140 1141#============================================================================== 1142 1143class EventFactory (StaticClass): 1144 """ 1145 Factory of L{Event} objects. 1146 1147 @type baseEvent: L{Event} 1148 @cvar baseEvent: 1149 Base class for Event objects. 1150 It's used for unknown event codes. 1151 1152 @type eventClasses: dict( int S{->} L{Event} ) 1153 @cvar eventClasses: 1154 Dictionary that maps event codes to L{Event} subclasses. 1155 """ 1156 1157 baseEvent = Event 1158 eventClasses = { 1159 win32.EXCEPTION_DEBUG_EVENT : ExceptionEvent, # 1 1160 win32.CREATE_THREAD_DEBUG_EVENT : CreateThreadEvent, # 2 1161 win32.CREATE_PROCESS_DEBUG_EVENT : CreateProcessEvent, # 3 1162 win32.EXIT_THREAD_DEBUG_EVENT : ExitThreadEvent, # 4 1163 win32.EXIT_PROCESS_DEBUG_EVENT : ExitProcessEvent, # 5 1164 win32.LOAD_DLL_DEBUG_EVENT : LoadDLLEvent, # 6 1165 win32.UNLOAD_DLL_DEBUG_EVENT : UnloadDLLEvent, # 7 1166 win32.OUTPUT_DEBUG_STRING_EVENT : OutputDebugStringEvent, # 8 1167 win32.RIP_EVENT : RIPEvent, # 9 1168 } 1169 1170 @classmethod 1171 def get(cls, debug, raw): 1172 """ 1173 @type debug: L{Debug} 1174 @param debug: Debug object that received the event. 1175 1176 @type raw: L{DEBUG_EVENT} 1177 @param raw: Raw DEBUG_EVENT structure as used by the Win32 API. 1178 1179 @rtype: L{Event} 1180 @returns: An Event object or one of it's subclasses, 1181 depending on the event type. 1182 """ 1183 eventClass = cls.eventClasses.get(raw.dwDebugEventCode, cls.baseEvent) 1184 return eventClass(debug, raw) 1185 1186#============================================================================== 1187 1188class EventHandler (object): 1189 """ 1190 Base class for debug event handlers. 1191 1192 Your program should subclass it to implement it's own event handling. 1193 1194 The constructor can be overriden as long as you call the superclass 1195 constructor. The special method L{__call__} B{MUST NOT} be overriden. 1196 1197 The signature for event handlers is the following:: 1198 1199 def event_handler(self, event): 1200 1201 Where B{event} is an L{Event} object. 1202 1203 Each event handler is named after the event they handle. 1204 This is the list of all valid event handler names: 1205 1206 - I{event} 1207 1208 Receives an L{Event} object or an object of any of it's subclasses, 1209 and handles any event for which no handler was defined. 1210 1211 - I{unknown_event} 1212 1213 Receives an L{Event} object or an object of any of it's subclasses, 1214 and handles any event unknown to the debugging engine. (This is not 1215 likely to happen unless the Win32 debugging API is changed in future 1216 versions of Windows). 1217 1218 - I{exception} 1219 1220 Receives an L{ExceptionEvent} object and handles any exception for 1221 which no handler was defined. See above for exception handlers. 1222 1223 - I{unknown_exception} 1224 1225 Receives an L{ExceptionEvent} object and handles any exception unknown 1226 to the debugging engine. This usually happens for C++ exceptions, which 1227 are not standardized and may change from one compiler to the next. 1228 1229 Currently we have partial support for C++ exceptions thrown by Microsoft 1230 compilers. 1231 1232 Also see: U{RaiseException() 1233 <http://msdn.microsoft.com/en-us/library/ms680552(VS.85).aspx>} 1234 1235 - I{create_thread} 1236 1237 Receives a L{CreateThreadEvent} object. 1238 1239 - I{create_process} 1240 1241 Receives a L{CreateProcessEvent} object. 1242 1243 - I{exit_thread} 1244 1245 Receives a L{ExitThreadEvent} object. 1246 1247 - I{exit_process} 1248 1249 Receives a L{ExitProcessEvent} object. 1250 1251 - I{load_dll} 1252 1253 Receives a L{LoadDLLEvent} object. 1254 1255 - I{unload_dll} 1256 1257 Receives an L{UnloadDLLEvent} object. 1258 1259 - I{output_string} 1260 1261 Receives an L{OutputDebugStringEvent} object. 1262 1263 - I{rip} 1264 1265 Receives a L{RIPEvent} object. 1266 1267 This is the list of all valid exception handler names 1268 (they all receive an L{ExceptionEvent} object): 1269 1270 - I{access_violation} 1271 - I{array_bounds_exceeded} 1272 - I{breakpoint} 1273 - I{control_c_exit} 1274 - I{datatype_misalignment} 1275 - I{debug_control_c} 1276 - I{float_denormal_operand} 1277 - I{float_divide_by_zero} 1278 - I{float_inexact_result} 1279 - I{float_invalid_operation} 1280 - I{float_overflow} 1281 - I{float_stack_check} 1282 - I{float_underflow} 1283 - I{guard_page} 1284 - I{illegal_instruction} 1285 - I{in_page_error} 1286 - I{integer_divide_by_zero} 1287 - I{integer_overflow} 1288 - I{invalid_disposition} 1289 - I{invalid_handle} 1290 - I{ms_vc_exception} 1291 - I{noncontinuable_exception} 1292 - I{possible_deadlock} 1293 - I{privileged_instruction} 1294 - I{single_step} 1295 - I{stack_overflow} 1296 - I{wow64_breakpoint} 1297 1298 1299 1300 @type apiHooks: dict( str S{->} list( tuple( str, int ) ) ) 1301 @cvar apiHooks: 1302 Dictionary that maps module names to lists of 1303 tuples of ( procedure name, parameter count ). 1304 1305 All procedures listed here will be hooked for calls from the debugee. 1306 When this happens, the corresponding event handler can be notified both 1307 when the procedure is entered and when it's left by the debugee. 1308 1309 For example, let's hook the LoadLibraryEx() API call. 1310 This would be the declaration of apiHooks:: 1311 1312 from winappdbg import EventHandler 1313 from winappdbg.win32 import * 1314 1315 # (...) 1316 1317 class MyEventHandler (EventHandler): 1318 1319 apiHook = { 1320 1321 "kernel32.dll" : ( 1322 1323 # Procedure name Signature 1324 ( "LoadLibraryEx", (PVOID, HANDLE, DWORD) ), 1325 1326 # (more procedures can go here...) 1327 ), 1328 1329 # (more libraries can go here...) 1330 } 1331 1332 # (your method definitions go here...) 1333 1334 Note that all pointer types are treated like void pointers, so your 1335 callback won't get the string or structure pointed to by it, but the 1336 remote memory address instead. This is so to prevent the ctypes library 1337 from being "too helpful" and trying to dereference the pointer. To get 1338 the actual data being pointed to, use one of the L{Process.read} 1339 methods. 1340 1341 Now, to intercept calls to LoadLibraryEx define a method like this in 1342 your event handler class:: 1343 1344 def pre_LoadLibraryEx(self, event, ra, lpFilename, hFile, dwFlags): 1345 szFilename = event.get_process().peek_string(lpFilename) 1346 1347 # (...) 1348 1349 Note that the first parameter is always the L{Event} object, and the 1350 second parameter is the return address. The third parameter and above 1351 are the values passed to the hooked function. 1352 1353 Finally, to intercept returns from calls to LoadLibraryEx define a 1354 method like this:: 1355 1356 def post_LoadLibraryEx(self, event, retval): 1357 # (...) 1358 1359 The first parameter is the L{Event} object and the second is the 1360 return value from the hooked function. 1361 """ 1362 1363#------------------------------------------------------------------------------ 1364 1365 # Default (empty) API hooks dictionary. 1366 apiHooks = {} 1367 1368 def __init__(self): 1369 """ 1370 Class constructor. Don't forget to call it when subclassing! 1371 1372 Forgetting to call the superclass constructor is a common mistake when 1373 you're new to Python. :) 1374 1375 Example:: 1376 class MyEventHandler (EventHandler): 1377 1378 # Override the constructor to use an extra argument. 1379 def __init__(self, myArgument): 1380 1381 # Do something with the argument, like keeping it 1382 # as an instance variable. 1383 self.myVariable = myArgument 1384 1385 # Call the superclass constructor. 1386 super(MyEventHandler, self).__init__() 1387 1388 # The rest of your code below... 1389 """ 1390 1391 # TODO 1392 # All this does is set up the hooks. 1393 # This code should be moved to the EventDispatcher class. 1394 # Then the hooks can be set up at set_event_handler() instead, making 1395 # this class even simpler. The downside here is deciding where to store 1396 # the ApiHook objects. 1397 1398 # Convert the tuples into instances of the ApiHook class. 1399 # A new dictionary must be instanced, otherwise we could also be 1400 # affecting all other instances of the EventHandler. 1401 apiHooks = dict() 1402 for lib, hooks in compat.iteritems(self.apiHooks): 1403 hook_objs = [] 1404 for proc, args in hooks: 1405 if type(args) in (int, long): 1406 h = ApiHook(self, lib, proc, paramCount = args) 1407 else: 1408 h = ApiHook(self, lib, proc, signature = args) 1409 hook_objs.append(h) 1410 apiHooks[lib] = hook_objs 1411 self.__apiHooks = apiHooks 1412 1413 def __get_hooks_for_dll(self, event): 1414 """ 1415 Get the requested API hooks for the current DLL. 1416 1417 Used by L{__hook_dll} and L{__unhook_dll}. 1418 """ 1419 result = [] 1420 if self.__apiHooks: 1421 path = event.get_module().get_filename() 1422 if path: 1423 lib_name = PathOperations.pathname_to_filename(path).lower() 1424 for hook_lib, hook_api_list in compat.iteritems(self.__apiHooks): 1425 if hook_lib == lib_name: 1426 result.extend(hook_api_list) 1427 return result 1428 1429 def __hook_dll(self, event): 1430 """ 1431 Hook the requested API calls (in self.apiHooks). 1432 1433 This method is called automatically whenever a DLL is loaded. 1434 """ 1435 debug = event.debug 1436 pid = event.get_pid() 1437 for hook_api_stub in self.__get_hooks_for_dll(event): 1438 hook_api_stub.hook(debug, pid) 1439 1440 def __unhook_dll(self, event): 1441 """ 1442 Unhook the requested API calls (in self.apiHooks). 1443 1444 This method is called automatically whenever a DLL is unloaded. 1445 """ 1446 debug = event.debug 1447 pid = event.get_pid() 1448 for hook_api_stub in self.__get_hooks_for_dll(event): 1449 hook_api_stub.unhook(debug, pid) 1450 1451 def __call__(self, event): 1452 """ 1453 Dispatch debug events. 1454 1455 @warn: B{Don't override this method!} 1456 1457 @type event: L{Event} 1458 @param event: Event object. 1459 """ 1460 try: 1461 code = event.get_event_code() 1462 if code == win32.LOAD_DLL_DEBUG_EVENT: 1463 self.__hook_dll(event) 1464 elif code == win32.UNLOAD_DLL_DEBUG_EVENT: 1465 self.__unhook_dll(event) 1466 finally: 1467 method = EventDispatcher.get_handler_method(self, event) 1468 if method is not None: 1469 return method(event) 1470 1471#============================================================================== 1472 1473# TODO 1474# * Make it more generic by adding a few more callbacks. 1475# That way it will be possible to make a thread sifter too. 1476# * This interface feels too much like an antipattern. 1477# When apiHooks is deprecated this will have to be reviewed. 1478 1479class EventSift(EventHandler): 1480 """ 1481 Event handler that allows you to use customized event handlers for each 1482 process you're attached to. 1483 1484 This makes coding the event handlers much easier, because each instance 1485 will only "know" about one process. So you can code your event handler as 1486 if only one process was being debugged, but your debugger can attach to 1487 multiple processes. 1488 1489 Example:: 1490 from winappdbg import Debug, EventHandler, EventSift 1491 1492 # This class was written assuming only one process is attached. 1493 # If you used it directly it would break when attaching to another 1494 # process, or when a child process is spawned. 1495 class MyEventHandler (EventHandler): 1496 1497 def create_process(self, event): 1498 self.first = True 1499 self.name = event.get_process().get_filename() 1500 print "Attached to %s" % self.name 1501 1502 def breakpoint(self, event): 1503 if self.first: 1504 self.first = False 1505 print "First breakpoint reached at %s" % self.name 1506 1507 def exit_process(self, event): 1508 print "Detached from %s" % self.name 1509 1510 # Now when debugging we use the EventSift to be able to work with 1511 # multiple processes while keeping our code simple. :) 1512 if __name__ == "__main__": 1513 handler = EventSift(MyEventHandler) 1514 #handler = MyEventHandler() # try uncommenting this line... 1515 with Debug(handler) as debug: 1516 debug.execl("calc.exe") 1517 debug.execl("notepad.exe") 1518 debug.execl("charmap.exe") 1519 debug.loop() 1520 1521 Subclasses of C{EventSift} can prevent specific event types from 1522 being forwarded by simply defining a method for it. That means your 1523 subclass can handle some event types globally while letting other types 1524 be handled on per-process basis. To forward events manually you can 1525 call C{self.event(event)}. 1526 1527 Example:: 1528 class MySift (EventSift): 1529 1530 # Don't forward this event. 1531 def debug_control_c(self, event): 1532 pass 1533 1534 # Handle this event globally without forwarding it. 1535 def output_string(self, event): 1536 print "Debug string: %s" % event.get_debug_string() 1537 1538 # Handle this event globally and then forward it. 1539 def create_process(self, event): 1540 print "New process created, PID: %d" % event.get_pid() 1541 return self.event(event) 1542 1543 # All other events will be forwarded. 1544 1545 Note that overriding the C{event} method would cause no events to be 1546 forwarded at all. To prevent this, call the superclass implementation. 1547 1548 Example:: 1549 1550 def we_want_to_forward_this_event(event): 1551 "Use whatever logic you want here..." 1552 # (...return True or False...) 1553 1554 class MySift (EventSift): 1555 1556 def event(self, event): 1557 1558 # If the event matches some custom criteria... 1559 if we_want_to_forward_this_event(event): 1560 1561 # Forward it. 1562 return super(MySift, self).event(event) 1563 1564 # Otherwise, don't. 1565 1566 @type cls: class 1567 @ivar cls: 1568 Event handler class. There will be one instance of this class 1569 per debugged process in the L{forward} dictionary. 1570 1571 @type argv: list 1572 @ivar argv: 1573 Positional arguments to pass to the constructor of L{cls}. 1574 1575 @type argd: list 1576 @ivar argd: 1577 Keyword arguments to pass to the constructor of L{cls}. 1578 1579 @type forward: dict 1580 @ivar forward: 1581 Dictionary that maps each debugged process ID to an instance of L{cls}. 1582 """ 1583 1584 def __init__(self, cls, *argv, **argd): 1585 """ 1586 Maintains an instance of your event handler for each process being 1587 debugged, and forwards the events of each process to each corresponding 1588 instance. 1589 1590 @warn: If you subclass L{EventSift} and reimplement this method, 1591 don't forget to call the superclass constructor! 1592 1593 @see: L{event} 1594 1595 @type cls: class 1596 @param cls: Event handler class. This must be the class itself, not an 1597 instance! All additional arguments passed to the constructor of 1598 the event forwarder will be passed on to the constructor of this 1599 class as well. 1600 """ 1601 self.cls = cls 1602 self.argv = argv 1603 self.argd = argd 1604 self.forward = dict() 1605 super(EventSift, self).__init__() 1606 1607 # XXX HORRIBLE HACK 1608 # This makes apiHooks work in the inner handlers. 1609 def __call__(self, event): 1610 try: 1611 eventCode = event.get_event_code() 1612 if eventCode in (win32.LOAD_DLL_DEBUG_EVENT, 1613 win32.LOAD_DLL_DEBUG_EVENT): 1614 pid = event.get_pid() 1615 handler = self.forward.get(pid, None) 1616 if handler is None: 1617 handler = self.cls(*self.argv, **self.argd) 1618 self.forward[pid] = handler 1619 if isinstance(handler, EventHandler): 1620 if eventCode == win32.LOAD_DLL_DEBUG_EVENT: 1621 handler.__EventHandler_hook_dll(event) 1622 else: 1623 handler.__EventHandler_unhook_dll(event) 1624 finally: 1625 return super(EventSift, self).__call__(event) 1626 1627 def event(self, event): 1628 """ 1629 Forwards events to the corresponding instance of your event handler 1630 for this process. 1631 1632 If you subclass L{EventSift} and reimplement this method, no event 1633 will be forwarded at all unless you call the superclass implementation. 1634 1635 If your filtering is based on the event type, there's a much easier way 1636 to do it: just implement a handler for it. 1637 """ 1638 eventCode = event.get_event_code() 1639 pid = event.get_pid() 1640 handler = self.forward.get(pid, None) 1641 if handler is None: 1642 handler = self.cls(*self.argv, **self.argd) 1643 if eventCode != win32.EXIT_PROCESS_DEBUG_EVENT: 1644 self.forward[pid] = handler 1645 elif eventCode == win32.EXIT_PROCESS_DEBUG_EVENT: 1646 del self.forward[pid] 1647 return handler(event) 1648 1649#============================================================================== 1650 1651class EventDispatcher (object): 1652 """ 1653 Implements debug event dispatching capabilities. 1654 1655 @group Debugging events: 1656 get_event_handler, set_event_handler, get_handler_method 1657 """ 1658 1659 # Maps event code constants to the names of the pre-notify routines. 1660 # These routines are called BEFORE the user-defined handlers. 1661 # Unknown codes are ignored. 1662 __preEventNotifyCallbackName = { 1663 win32.CREATE_THREAD_DEBUG_EVENT : '_notify_create_thread', 1664 win32.CREATE_PROCESS_DEBUG_EVENT : '_notify_create_process', 1665 win32.LOAD_DLL_DEBUG_EVENT : '_notify_load_dll', 1666 } 1667 1668 # Maps event code constants to the names of the post-notify routines. 1669 # These routines are called AFTER the user-defined handlers. 1670 # Unknown codes are ignored. 1671 __postEventNotifyCallbackName = { 1672 win32.EXIT_THREAD_DEBUG_EVENT : '_notify_exit_thread', 1673 win32.EXIT_PROCESS_DEBUG_EVENT : '_notify_exit_process', 1674 win32.UNLOAD_DLL_DEBUG_EVENT : '_notify_unload_dll', 1675 win32.RIP_EVENT : '_notify_rip', 1676 } 1677 1678 # Maps exception code constants to the names of the pre-notify routines. 1679 # These routines are called BEFORE the user-defined handlers. 1680 # Unknown codes are ignored. 1681 __preExceptionNotifyCallbackName = { 1682 win32.EXCEPTION_BREAKPOINT : '_notify_breakpoint', 1683 win32.EXCEPTION_WX86_BREAKPOINT : '_notify_breakpoint', 1684 win32.EXCEPTION_SINGLE_STEP : '_notify_single_step', 1685 win32.EXCEPTION_GUARD_PAGE : '_notify_guard_page', 1686 win32.DBG_CONTROL_C : '_notify_debug_control_c', 1687 win32.MS_VC_EXCEPTION : '_notify_ms_vc_exception', 1688 } 1689 1690 # Maps exception code constants to the names of the post-notify routines. 1691 # These routines are called AFTER the user-defined handlers. 1692 # Unknown codes are ignored. 1693 __postExceptionNotifyCallbackName = { 1694 } 1695 1696 def __init__(self, eventHandler = None): 1697 """ 1698 Event dispatcher. 1699 1700 @type eventHandler: L{EventHandler} 1701 @param eventHandler: (Optional) User-defined event handler. 1702 1703 @raise TypeError: The event handler is of an incorrect type. 1704 1705 @note: The L{eventHandler} parameter may be any callable Python object 1706 (for example a function, or an instance method). 1707 However you'll probably find it more convenient to use an instance 1708 of a subclass of L{EventHandler} here. 1709 """ 1710 self.set_event_handler(eventHandler) 1711 1712 def get_event_handler(self): 1713 """ 1714 Get the event handler. 1715 1716 @see: L{set_event_handler} 1717 1718 @rtype: L{EventHandler} 1719 @return: Current event handler object, or C{None}. 1720 """ 1721 return self.__eventHandler 1722 1723 def set_event_handler(self, eventHandler): 1724 """ 1725 Set the event handler. 1726 1727 @warn: This is normally not needed. Use with care! 1728 1729 @type eventHandler: L{EventHandler} 1730 @param eventHandler: New event handler object, or C{None}. 1731 1732 @rtype: L{EventHandler} 1733 @return: Previous event handler object, or C{None}. 1734 1735 @raise TypeError: The event handler is of an incorrect type. 1736 1737 @note: The L{eventHandler} parameter may be any callable Python object 1738 (for example a function, or an instance method). 1739 However you'll probably find it more convenient to use an instance 1740 of a subclass of L{EventHandler} here. 1741 """ 1742 if eventHandler is not None and not callable(eventHandler): 1743 raise TypeError("Event handler must be a callable object") 1744 try: 1745 wrong_type = issubclass(eventHandler, EventHandler) 1746 except TypeError: 1747 wrong_type = False 1748 if wrong_type: 1749 classname = str(eventHandler) 1750 msg = "Event handler must be an instance of class %s" 1751 msg += "rather than the %s class itself. (Missing parens?)" 1752 msg = msg % (classname, classname) 1753 raise TypeError(msg) 1754 try: 1755 previous = self.__eventHandler 1756 except AttributeError: 1757 previous = None 1758 self.__eventHandler = eventHandler 1759 return previous 1760 1761 @staticmethod 1762 def get_handler_method(eventHandler, event, fallback=None): 1763 """ 1764 Retrieves the appropriate callback method from an L{EventHandler} 1765 instance for the given L{Event} object. 1766 1767 @type eventHandler: L{EventHandler} 1768 @param eventHandler: 1769 Event handler object whose methods we are examining. 1770 1771 @type event: L{Event} 1772 @param event: Debugging event to be handled. 1773 1774 @type fallback: callable 1775 @param fallback: (Optional) If no suitable method is found in the 1776 L{EventHandler} instance, return this value. 1777 1778 @rtype: callable 1779 @return: Bound method that will handle the debugging event. 1780 Returns C{None} if no such method is defined. 1781 """ 1782 eventCode = event.get_event_code() 1783 method = getattr(eventHandler, 'event', fallback) 1784 if eventCode == win32.EXCEPTION_DEBUG_EVENT: 1785 method = getattr(eventHandler, 'exception', method) 1786 method = getattr(eventHandler, event.eventMethod, method) 1787 return method 1788 1789 def dispatch(self, event): 1790 """ 1791 Sends event notifications to the L{Debug} object and 1792 the L{EventHandler} object provided by the user. 1793 1794 The L{Debug} object will forward the notifications to it's contained 1795 snapshot objects (L{System}, L{Process}, L{Thread} and L{Module}) when 1796 appropriate. 1797 1798 @warning: This method is called automatically from L{Debug.dispatch}. 1799 1800 @see: L{Debug.cont}, L{Debug.loop}, L{Debug.wait} 1801 1802 @type event: L{Event} 1803 @param event: Event object passed to L{Debug.dispatch}. 1804 1805 @raise WindowsError: Raises an exception on error. 1806 """ 1807 returnValue = None 1808 bCallHandler = True 1809 pre_handler = None 1810 post_handler = None 1811 eventCode = event.get_event_code() 1812 1813 # Get the pre and post notification methods for exceptions. 1814 # If not found, the following steps take care of that. 1815 if eventCode == win32.EXCEPTION_DEBUG_EVENT: 1816 exceptionCode = event.get_exception_code() 1817 pre_name = self.__preExceptionNotifyCallbackName.get( 1818 exceptionCode, None) 1819 post_name = self.__postExceptionNotifyCallbackName.get( 1820 exceptionCode, None) 1821 if pre_name is not None: 1822 pre_handler = getattr(self, pre_name, None) 1823 if post_name is not None: 1824 post_handler = getattr(self, post_name, None) 1825 1826 # Get the pre notification method for all other events. 1827 # This includes the exception event if no notify method was found 1828 # for this exception code. 1829 if pre_handler is None: 1830 pre_name = self.__preEventNotifyCallbackName.get(eventCode, None) 1831 if pre_name is not None: 1832 pre_handler = getattr(self, pre_name, pre_handler) 1833 1834 # Get the post notification method for all other events. 1835 # This includes the exception event if no notify method was found 1836 # for this exception code. 1837 if post_handler is None: 1838 post_name = self.__postEventNotifyCallbackName.get(eventCode, None) 1839 if post_name is not None: 1840 post_handler = getattr(self, post_name, post_handler) 1841 1842 # Call the pre-notify method only if it was defined. 1843 # If an exception is raised don't call the other methods. 1844 if pre_handler is not None: 1845 bCallHandler = pre_handler(event) 1846 1847 # Call the user-defined event handler only if the pre-notify 1848 # method was not defined, or was and it returned True. 1849 try: 1850 if bCallHandler and self.__eventHandler is not None: 1851 try: 1852 returnValue = self.__eventHandler(event) 1853 except Exception: 1854 e = sys.exc_info()[1] 1855 msg = ("Event handler pre-callback %r" 1856 " raised an exception: %s") 1857 msg = msg % (self.__eventHandler, traceback.format_exc(e)) 1858 warnings.warn(msg, EventCallbackWarning) 1859 returnValue = None 1860 1861 # Call the post-notify method if defined, even if an exception is 1862 # raised by the user-defined event handler. 1863 finally: 1864 if post_handler is not None: 1865 post_handler(event) 1866 1867 # Return the value from the call to the user-defined event handler. 1868 # If not defined return None. 1869 return returnValue 1870