Package winappdbg :: Module event
[hide private]
[frames] | no frames]

Source Code for Module winappdbg.event

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