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

Source Code for Module winappdbg.debug

  1  # Copyright (c) 2009, Mario Vilas 
  2  # All rights reserved. 
  3  # 
  4  # Redistribution and use in source and binary forms, with or without 
  5  # modification, are permitted provided that the following conditions are met: 
  6  # 
  7  #     * Redistributions of source code must retain the above copyright notice, 
  8  #       this list of conditions and the following disclaimer. 
  9  #     * Redistributions in binary form must reproduce the above copyright 
 10  #       notice,this list of conditions and the following disclaimer in the 
 11  #       documentation and/or other materials provided with the distribution. 
 12  #     * Neither the name of the copyright holder nor the names of its 
 13  #       contributors may be used to endorse or promote products derived from 
 14  #       this software without specific prior written permission. 
 15  # 
 16  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 17  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 18  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 19  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 20  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 21  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 22  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 23  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 24  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 25  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 26  # POSSIBILITY OF SUCH DAMAGE. 
 27   
 28  """ 
 29  Debugging module. 
 30   
 31  @see: U{http://apps.sourceforge.net/trac/winappdbg/wiki/wiki/Debugging} 
 32   
 33  @group Instrumentation: System, Process, Thread, Module 
 34  @group Debugging: Debug, EventHandler 
 35  """ 
 36   
 37  __revision__ = "$Id: debug.py 452 2009-11-24 21:34:08Z qvasimodo $" 
 38   
 39  __all__ =   [ 
 40                  # the main debugger class 
 41                  'Debug', 
 42              ] 
 43   
 44  import win32 
 45  from system import System, Process, Thread, Module 
 46  from breakpoint import BreakpointContainer, CodeBreakpoint 
 47  from event import EventHandler, EventDispatcher, EventFactory, ExitProcessEvent 
 48   
 49  import sys 
 50  import ctypes 
 51  ##import traceback 
 52   
 53  #============================================================================== 
 54   
 55  # TODO 
 56  # * Add memory read and write operations, similar to those in the Process 
 57  #   class, but hiding the presence of the code breakpoints. 
 58  # * Add a method to get the memory map of a process, but hiding the presence 
 59  #   of the page breakpoints. 
 60  # * Maybe the previous two features should be implemented at the Process class 
 61  #   instead, but how to communicate with the Debug object without creating 
 62  #   circular references? Perhaps the "overrides" could be set using private 
 63  #   members (so users won't see them), but then there's the problem of the 
 64  #   users being able to access the snapshot (i.e. clear it), which is why it's 
 65  #   not such a great idea to use the snapshot to store data that really belongs 
 66  #   to the Debug class. 
 67   
68 -class Debug (EventDispatcher, BreakpointContainer):
69 """ 70 The main debugger class. 71 72 @see: U{http://apps.sourceforge.net/trac/winappdbg/wiki/wiki/Debugging} 73 74 @group Debugging: 75 attach, detach, detach_from_all, execv, execl, clear, 76 get_debugee_count, get_debugee_pids, 77 is_debugee, is_debugee_attached, is_debugee_started 78 79 @group Debugging loop: 80 loop, next, wait, dispatch, cont, stop 81 82 @group Event notifications (private): 83 notify_create_process, 84 notify_create_thread, 85 notify_load_dll, 86 notify_unload_dll, 87 notify_rip, 88 notify_debug_control_c, 89 notify_ms_vc_exception 90 91 @type system: L{System} 92 @ivar system: A System snapshot that is automatically updated for 93 processes being debugged. Processes not being debugged in this snapshot 94 may be outdated. 95 """ 96
97 - def __init__(self, eventHandler = None, bKillOnExit = False, 98 bHostileCode = False):
99 """ 100 Debugger object. 101 102 @type eventHandler: L{EventHandler} 103 @param eventHandler: 104 (Optional, recommended) Custom event handler object. 105 106 @type bKillOnExit: bool 107 @param bKillOnExit: (Optional) Global kill on exit mode. 108 C{True} to kill the process on exit, C{False} to detach. 109 Ignored under Windows 2000 and below. 110 111 @type bHostileCode: bool 112 @param bHostileCode: (Optional) Hostile code mode. 113 Set to C{True} to take some basic precautions against anti-debug 114 tricks. Disabled by default. 115 116 @note: The L{eventHandler} parameter may be any callable Python object 117 (for example a function, or an instance method). 118 However you'll probably find it more convenient to use an instance 119 of a subclass of L{EventHandler} here. 120 121 @raise WindowsError: Raises an exception on error. 122 """ 123 EventDispatcher.__init__(self, eventHandler) 124 BreakpointContainer.__init__(self) 125 126 self.system = System() 127 self.__bKillOnExit = bKillOnExit 128 self.__bHostileCode = bHostileCode 129 self.__attachedDebugees = set() 130 self.__startedDebugees = set() 131 132 ## self.system.request_debug_privileges(bIgnoreExceptions = True) 133 self.system.request_debug_privileges()
134 135 ## # It's not hard to create circular references, 136 ## # and since we have a destructor, we end up leaking everything. 137 ## # It's best to code the debugging loop properly to always 138 ## # stop the debugger before going out of scope. 139 ## def __del__(self): 140 ## try: 141 ## self.stop() 142 ## except Exception, e: 143 ## pass 144 #### traceback.print_exc() 145 #### print 146
147 - def __len__(self):
148 """ 149 @rtype: int 150 @return: Number of processes being debugged. 151 """ 152 return self.get_debugee_count()
153 154 #------------------------------------------------------------------------------ 155
156 - def attach(self, dwProcessId):
157 """ 158 Attaches to an existing process for debugging. 159 160 @see: L{detach}, L{execv}, L{execl} 161 162 @type dwProcessId: int 163 @param dwProcessId: Global ID of a process to attach to. 164 165 @rtype: L{Process} 166 @return: A new Process object. 167 168 @raise WindowsError: Raises an exception on error. 169 """ 170 win32.DebugActiveProcess(dwProcessId) 171 self.__attachedDebugees.add(dwProcessId) 172 173 # We can only set the kill on exit mode after having 174 # established at least one debugging connection. 175 self.system.set_kill_on_exit_mode(self.__bKillOnExit) 176 177 # The process has to be registered with the debugger, 178 # otherwise the list of processes may be empty, and the 179 # debugger loop will quit too soon. When the create process 180 # event arrives, the process handle is replaced. 181 if not self.system.has_process(dwProcessId): 182 aProcess = Process(dwProcessId) 183 self.system._ProcessContainer__add_process(aProcess) 184 else: 185 aProcess = self.system.get_process(dwProcessId) 186 187 # XXX 188 # Scan the process threads and loaded modules. 189 # This is prefered because the thread and library events do not 190 # properly give some information, like the filename for each module. 191 aProcess.scan_threads() 192 aProcess.scan_modules() 193 194 return aProcess
195
196 - def detach(self, dwProcessId, bIgnoreExceptions = False):
197 """ 198 Detaches from a process currently being debugged. 199 200 @see: L{attach}, L{detach_from_all} 201 202 @type dwProcessId: int 203 @param dwProcessId: Global ID of a process to detach from. 204 205 @type bIgnoreExceptions: bool 206 @param bIgnoreExceptions: C{True} to ignore any exceptions that may be 207 raised when detaching. 208 209 @raise WindowsError: Raises an exception on error, unless 210 C{bIgnoreExceptions} is C{True}. 211 """ 212 213 # Disable all breakpoints in the process. 214 # XXX maybe they should be erased? 215 try: 216 self.disable_process_breakpoints(dwProcessId) 217 except Exception: 218 if not bIgnoreExceptions: 219 raise 220 ## traceback.print_exc() 221 ## print 222 223 # Stop tracing all threads in the process. 224 try: 225 self.stop_tracing_process(dwProcessId) 226 except Exception: 227 if not bIgnoreExceptions: 228 raise 229 ## traceback.print_exc() 230 ## print 231 232 # The process is no longer a debugee. 233 try: 234 if dwProcessId in self.__attachedDebugees: 235 self.__attachedDebugees.remove(dwProcessId) 236 if dwProcessId in self.__startedDebugees: 237 self.__startedDebugees.remove(dwProcessId) 238 except Exception: 239 if not bIgnoreExceptions: 240 raise 241 ## traceback.print_exc() 242 ## print 243 244 # Detach from the process. 245 try: 246 win32.DebugActiveProcessStop(dwProcessId) 247 except Exception: 248 if not bIgnoreExceptions: 249 raise
250 ## traceback.print_exc() 251 ## print 252
253 - def detach_from_all(self, bIgnoreExceptions = False):
254 """ 255 Detaches from all processes currently being debugged. 256 257 @note: To better handle last debugging event, call L{stop} instead. 258 259 @type bIgnoreExceptions: bool 260 @param bIgnoreExceptions: C{True} to ignore any exceptions that may be 261 raised when detaching. 262 263 @raise WindowsError: Raises an exception on error, unless 264 C{bIgnoreExceptions} is C{True}. 265 """ 266 for pid in self.get_debugee_pids(): 267 self.detach(pid, bIgnoreExceptions = bIgnoreExceptions)
268
269 - def execv(self, argv, bConsole = False, 270 bFollow = False, 271 bSuspended = False, 272 bInheritHandles = False, 273 dwParentProcessId = None):
274 """ 275 Starts a new process for debugging. 276 277 This method uses a list of arguments. To use a command line string 278 instead, use L{execl}. 279 280 @see: L{attach}, L{detach} 281 282 @type argv: list( str... ) 283 @param argv: List of command line arguments to pass to the debugee. 284 The first element must be the debugee executable filename. 285 286 @type bConsole: bool 287 @param bConsole: True to inherit the console of the debugger. 288 Defaults to C{False}. 289 290 @type bFollow: bool 291 @param bFollow: C{True} to automatically attach to child processes. 292 Defaults to C{False}. 293 294 @type bSuspended: bool 295 @param bSuspended: C{True} to suspend the main thread before any code 296 is executed in the debugee. Defaults to C{False}. 297 298 @type bInheritHandles: bool 299 @param bInheritHandles: C{True} if the new process should inherit it's 300 parent process' handles. Defaults to C{False}. 301 302 @type dwParentProcessId: int or None 303 @param dwParentProcessId: C{None} if the debugger process should be the 304 parent process (default), or a process ID to forcefully set as the 305 debuguee's parent (only available for Windows Vista and above). 306 307 @rtype: L{Process} 308 @return: A new Process object. 309 310 @raise WindowsError: Raises an exception on error. 311 """ 312 lpCmdLine = self.system.argv_to_cmdline(argv) 313 return self.execl(lpCmdLine, bConsole = bConsole, 314 bFollow = bFollow, 315 bSuspended = bSuspended, 316 bInheritHandles = bInheritHandles, 317 dwParentProcessId = dwParentProcessId)
318
319 - def execl(self, lpCmdLine, bConsole = False, 320 bFollow = False, 321 bSuspended = False, 322 bInheritHandles = False, 323 dwParentProcessId = None):
324 """ 325 Starts a new process for debugging. 326 327 This method uses a command line string. To use a list of arguments 328 instead, use L{execv}. 329 330 @see: L{attach}, L{detach} 331 332 @type lpCmdLine: str 333 @param lpCmdLine: Command line string to execute. 334 The first token must be the debugee executable filename. 335 Tokens with spaces must be enclosed in double quotes. 336 Tokens including double quote characters must be escaped with a 337 backslash. 338 339 @type bConsole: bool 340 @param bConsole: C{True} to inherit the console of the debugger. 341 Defaults to C{False}. 342 343 @type bFollow: bool 344 @param bFollow: C{True} to automatically attach to child processes. 345 Defaults to C{False}. 346 347 @type bSuspended: bool 348 @param bSuspended: C{True} to suspend the main thread before any code 349 is executed in the debugee. Defaults to C{False}. 350 351 @type bInheritHandles: bool 352 @param bInheritHandles: C{True} if the new process should inherit it's 353 parent process' handles. Defaults to C{False}. 354 355 @type dwParentProcessId: int or None 356 @param dwParentProcessId: C{None} if the debugger process should be the 357 parent process (default), or a process ID to forcefully set as the 358 debuguee's parent (only available for Windows Vista and above). 359 360 @rtype: L{Process} 361 @return: A new Process object. 362 363 @raise WindowsError: Raises an exception on error. 364 """ 365 aProcess = self.system.start_process(lpCmdLine, 366 bConsole = bConsole, 367 bDebug = True, 368 bFollow = bFollow, 369 bSuspended = bSuspended, 370 bInheritHandles = bInheritHandles, 371 dwParentProcessId = dwParentProcessId, 372 ) 373 374 self.__startedDebugees.add( aProcess.get_pid() ) 375 376 # We can only set the kill on exit mode after having 377 # established at least one debugging connection. 378 self.system.set_kill_on_exit_mode(self.__bKillOnExit) 379 380 return aProcess
381 382 #------------------------------------------------------------------------------ 383
384 - def wait(self, dwMilliseconds = None):
385 """ 386 Waits for the next debug event and returns an L{Event} object. 387 388 @see: L{cont}, L{dispatch}, L{loop} 389 390 @type dwMilliseconds: int 391 @param dwMilliseconds: (Optional) Timeout in milliseconds. 392 Use C{INFINITE} or C{None} for no timeout. 393 394 @rtype: L{Event} 395 @return: An event that occured in one of the debugees. 396 397 @raise WindowsError: Raises an exception on error. 398 """ 399 400 # Return the next debug event. 401 raw = win32.WaitForDebugEvent(dwMilliseconds) 402 event = EventFactory.get(self, raw) 403 return event
404
405 - def dispatch(self, event):
406 """ 407 Calls the debug event notify callbacks. 408 409 @see: L{cont}, L{loop}, L{wait} 410 411 @type event: L{Event} 412 @param event: Event object returned by L{wait}. 413 414 @raise WindowsError: Raises an exception on error. 415 """ 416 417 # Ignore dummy events. 418 if not event: 419 return 420 421 # By default, exceptions are handled by the debugee. 422 if event.get_event_code() == win32.EXCEPTION_DEBUG_EVENT: 423 event.continueStatus = win32.DBG_EXCEPTION_NOT_HANDLED 424 else: 425 # Other events need this continue code. 426 # Sometimes other codes can be used and are ignored, sometimes not. 427 # For example, when using the DBG_EXCEPTION_NOT_HANDLED code, 428 # debug strings are sent twice (!) 429 event.continueStatus = win32.DBG_CONTINUE 430 431 # Dispatch the debug event. 432 return EventDispatcher.dispatch(self, event)
433
434 - def cont(self, event):
435 """ 436 Resumes execution after processing a debug event. 437 438 @see: dispatch(), loop(), wait() 439 440 @type event: L{Event} 441 @param event: Event object returned by L{wait}. 442 443 @raise WindowsError: Raises an exception on error. 444 """ 445 446 # Ignore dummy events. 447 if not event: 448 return 449 450 # Get the event continue status information. 451 dwProcessId = event.get_pid() 452 dwThreadId = event.get_tid() 453 dwContinueStatus = event.continueStatus 454 455 # Try to flush the instruction cache. 456 try: 457 if self.system.has_process(dwProcessId): 458 aProcess = self.system.get_process(dwProcessId) 459 else: 460 aProcess = Process(dwProcessId) 461 aProcess.flush_instruction_cache() 462 except WindowsError: 463 pass 464 465 # Continue execution of the debugee. 466 win32.ContinueDebugEvent(dwProcessId, dwThreadId, dwContinueStatus)
467
468 - def stop(self, event = None, bIgnoreExceptions = True):
469 """ 470 Stops debugging all processes. 471 472 If C{bKillOnExit} was set to C{True} when instancing the C{Debug} 473 object, all debugees are terminated. Otherwise, the debugger detaches 474 from all debugees. 475 476 @note: This method is better than L{detach_from_all} because it can 477 gracefully handle the last debugging event before detaching. 478 479 @type event: L{Event} 480 @param event: (Optional) Event object returned by L{wait}. 481 By passing this parameter, the last debugging event may be 482 continued gracefully. 483 484 @type bIgnoreExceptions: bool 485 @param bIgnoreExceptions: C{True} to ignore any exceptions that may be 486 raised when detaching. 487 """ 488 # All these try / except / finally blocks may be masking some errors, 489 # but this way we get a better cleanup. Like that battery-powered 490 # rabbit, it just keeps going, and going, and going. 491 try: 492 if self.__bKillOnExit: 493 for pid in self.get_debugee_pids(): 494 try: 495 self.system.get_process(pid).kill() 496 except Exception: 497 if not bIgnoreExceptions: 498 raise 499 try: 500 if event: 501 try: 502 try: 503 pid = event.get_pid() 504 self.disable_process_breakpoints(pid) 505 finally: 506 self.cont(event) 507 except Exception: 508 if not bIgnoreExceptions: 509 raise 510 finally: 511 self.detach_from_all(bIgnoreExceptions) 512 except Exception: 513 if not bIgnoreExceptions: 514 raise
515
516 - def next(self):
517 """ 518 Handles the next debug event. 519 520 @see: L{cont}, L{dispatch}, L{wait}, L{stop} 521 522 @rtype: L{Event} 523 @return: Handled debug event. 524 525 @raise WindowsError: Raises an exception on error. 526 527 If the wait operation causes an error, debugging is stopped 528 (meaning all debugees are either killed or detached from). 529 530 If the event dispatching causes an error, the event is still 531 continued before returning. This may happen, for example, if the 532 event handler raises an exception nobody catches. 533 """ 534 try: 535 event = self.wait() 536 except Exception: 537 self.stop() 538 try: 539 self.dispatch(event) 540 finally: 541 self.cont(event) 542 return event
543
544 - def loop(self):
545 """ 546 Simple debugging loop. 547 548 This debugging loop is meant to be useful for most simple scripts. 549 It iterates as long as there is at least one debuguee, or an exception 550 is raised. Multiple calls are allowed. 551 552 This is a trivial example script:: 553 554 import sys 555 debug = Debug() 556 debug.execv( sys.argv [ 1 : ] ) 557 try: 558 debug.loop() 559 finally: 560 debug.stop() 561 562 @see: L{next}, L{stop} 563 564 U{http://msdn.microsoft.com/en-us/library/ms681675(VS.85).aspx} 565 566 @raise WindowsError: Raises an exception on error. 567 568 If the wait operation causes an error, debugging is stopped 569 (meaning all debugees are either killed or detached from). 570 571 If the event dispatching causes an error, the event is still 572 continued before returning. This may happen, for example, if the 573 event handler raises an exception nobody catches. 574 """ 575 while self.get_debugee_count() > 0: 576 self.next()
577
578 - def get_debugee_count(self):
579 """ 580 @rtype: int 581 @return: Number of processes being debugged. 582 """ 583 return len(self.__attachedDebugees) + len(self.__startedDebugees)
584
585 - def get_debugee_pids(self):
586 """ 587 @rtype: list( int... ) 588 @return: Global IDs of processes being debugged. 589 """ 590 return list(self.__attachedDebugees) + list(self.__startedDebugees)
591
592 - def is_debugee(self, dwProcessId):
593 """ 594 @type dwProcessId: int 595 @param dwProcessId: Process global ID. 596 597 @rtype: bool 598 @return: C{True} if the given process is being debugged 599 by this L{Debug} instance. 600 """ 601 return self.is_debugee_attached(dwProcessId) or \ 602 self.is_debugee_started(dwProcessId)
603
604 - def is_debugee_started(self, dwProcessId):
605 """ 606 @type dwProcessId: int 607 @param dwProcessId: Process global ID. 608 609 @rtype: bool 610 @return: C{True} if the given process was started for debugging by this 611 L{Debug} instance. 612 """ 613 return dwProcessId in self.__startedDebugees
614
615 - def is_debugee_attached(self, dwProcessId):
616 """ 617 @type dwProcessId: int 618 @param dwProcessId: Process global ID. 619 620 @rtype: bool 621 @return: C{True} if the given process is attached to this 622 L{Debug} instance. 623 """ 624 return dwProcessId in self.__attachedDebugees
625 626 #------------------------------------------------------------------------------ 627
628 - def clear(self):
629 """ 630 Detach from all processes and clean up internal structures. 631 632 @see: L{System} 633 634 @raise WindowsError: Raises an exception on error. 635 """ 636 self.erase_all_breakpoints() 637 self.detach_from_all() 638 self.system.clear()
639 640 #------------------------------------------------------------------------------ 641
642 - def notify_create_process(self, event):
643 """ 644 Notify the creation of a new process. 645 646 @warning: This method is meant to be used internally by the debugger. 647 648 @type event: L{ExitProcessEvent} 649 @param event: Exit process event. 650 651 @rtype: bool 652 @return: C{True} to call the user-defined handle, C{False} otherwise. 653 """ 654 dwProcessId = event.get_pid() 655 if dwProcessId not in self.__attachedDebugees: 656 if dwProcessId not in self.__startedDebugees: 657 self.__startedDebugees.add(dwProcessId) 658 659 retval = self.system.notify_create_process(event) 660 661 # Defeat isDebuggerPresent by patching PEB->BeingDebugged. 662 # When we do this, some debugging APIs cease to work as expected. 663 # For example, the system breakpoint isn't hit when we attach. 664 # For that reason we need to define a code breakpoint at the 665 # code location where a new thread is spawned by the debugging 666 # APIs, ntdll!DbgUiRemoteBreakin. 667 if self.__bHostileCode: 668 aProcess = self.system.get_process(dwProcessId) 669 try: 670 pbi = win32.NtQueryInformationProcess(aProcess.get_handle(), 671 win32.ProcessBasicInformation) 672 ptr = pbi.PebBaseAddress + 2 673 if aProcess.peek(ptr, 1) == '\x01': 674 aProcess.poke(ptr, '\x00') 675 except WindowsError: 676 pass 677 678 return retval
679
680 - def notify_create_thread(self, event):
681 """ 682 Notify the creation of a new thread. 683 684 @warning: This method is meant to be used internally by the debugger. 685 686 @type event: L{CreateThreadEvent} 687 @param event: Create thread event. 688 689 @rtype: bool 690 @return: C{True} to call the user-defined handle, C{False} otherwise. 691 """ 692 return event.get_process().notify_create_thread(event)
693
694 - def notify_load_dll(self, event):
695 """ 696 Notify the load of a new module. 697 698 @warning: This method is meant to be used internally by the debugger. 699 700 @type event: L{LoadDLLEvent} 701 @param event: Load DLL event. 702 703 @rtype: bool 704 @return: C{True} to call the user-defined handle, C{False} otherwise. 705 """ 706 707 # Get the process where the DLL was loaded. 708 aProcess = event.get_process() 709 710 # Pass the event to the process. 711 retval = aProcess.notify_load_dll(event) 712 713 # Anti-anti-debugging tricks on ntdll.dll. 714 if self.__bHostileCode: 715 aModule = event.get_module() 716 if aModule.match_name('ntdll.dll'): 717 718 ## # Check the int3 instruction where 719 ## # the system breakpoint should be. 720 ## # If missing, restore it. This defeats 721 ## # a simple anti-debugging trick. 722 #### address = aModule.resolve('DbgBreakPoint') 723 #### address = aModule.resolve('DbgUserBreakPoint') 724 ## address = aProcess.get_system_breakpoint() 725 ## if address is not None: 726 ## aProcess.poke(address, CodeBreakpoint.int3) 727 ## address = aProcess.get_user_breakpoint() 728 ## if address is not None: 729 ## aProcess.poke(address, CodeBreakpoint.int3) 730 731 # Since we've overwritten the PEB to hide 732 # ourselves, we no longer have the system 733 # breakpoint when attaching to the process. 734 # Set a breakpoint at ntdll!DbgUiRemoteBreakin 735 # instead (that's where the debug API spawns 736 # it's auxiliary threads). This also defeats 737 # a simple anti-debugging trick: the hostile 738 # process could have overwritten the int3 739 # instruction at the system breakpoint. 740 DbgUiRemoteBreakin = 'ntdll!DbgUiRemoteBreakin' 741 DbgUiRemoteBreakin = aProcess.resolve_label(DbgUiRemoteBreakin) 742 self.break_at(aProcess.get_pid(), DbgUiRemoteBreakin) 743 744 return retval
745
746 - def notify_exit_process(self, event):
747 """ 748 Notify the termination of a process. 749 750 @warning: This method is meant to be used internally by the debugger. 751 752 @type event: L{ExitProcessEvent} 753 @param event: Exit process event. 754 755 @rtype: bool 756 @return: C{True} to call the user-defined handle, C{False} otherwise. 757 """ 758 dwProcessId = event.get_pid() 759 if dwProcessId in self.__attachedDebugees: 760 self.__attachedDebugees.remove(dwProcessId) 761 if dwProcessId in self.__startedDebugees: 762 self.__startedDebugees.remove(dwProcessId) 763 764 bCallHandler = BreakpointContainer.notify_exit_process(self, event) 765 bCallHandler = bCallHandler and self.system.notify_exit_process(event) 766 return bCallHandler
767
768 - def notify_exit_thread(self, event):
769 """ 770 Notify the termination of a thread. 771 772 @warning: This method is meant to be used internally by the debugger. 773 774 @type event: L{ExitThreadEvent} 775 @param event: Exit thread event. 776 777 @rtype: bool 778 @return: C{True} to call the user-defined handle, C{False} otherwise. 779 """ 780 bCallHandler = BreakpointContainer.notify_exit_thread(self, event) 781 bCallHandler = bCallHandler and \ 782 event.get_process().notify_exit_thread(event) 783 return bCallHandler
784
785 - def notify_unload_dll(self, event):
786 """ 787 Notify the unload of a module. 788 789 @warning: This method is meant to be used internally by the debugger. 790 791 @type event: L{UnloadDLLEvent} 792 @param event: Unload DLL event. 793 794 @rtype: bool 795 @return: C{True} to call the user-defined handle, C{False} otherwise. 796 """ 797 bCallHandler = BreakpointContainer.notify_unload_dll(self, event) 798 bCallHandler = bCallHandler and \ 799 event.get_process().notify_unload_dll(event)
800
801 - def notify_rip(self, event):
802 """ 803 Notify of a RIP event. 804 805 @warning: This method is meant to be used internally by the debugger. 806 807 @type event: L{RIPEvent} 808 @param event: RIP event. 809 810 @rtype: bool 811 @return: C{True} to call the user-defined handle, C{False} otherwise. 812 """ 813 event.debug.detach( event.get_pid() ) 814 return True
815 816 ## def notify_breakpoint(self, event): 817 ## """ 818 ## Notify the debugger of a breakpoint exception event. 819 ## 820 ## @type event: L{ExceptionEvent} 821 ## @param event: Breakpoint exception event. 822 ## """ 823 ## # Defeat isDebuggerPresent by patching PEB->BeingDebugged. 824 ## if self.__bHostileCode: 825 ## address = event.get_exception_address() 826 ## if event.get_process().get_system_breakpoint() == address: 827 ## aProcess = self.system.get_process(dwProcessId) 828 ## try: 829 ## pbi = win32.NtQueryInformationProcess(aProcess.get_handle(), 830 ## win32.ProcessBasicInformation) 831 ## ptr = pbi.PebBaseAddress + 2 832 ## if aProcess.peek(ptr, 1) == '\x01': 833 ## aProcess.poke(ptr, '\x00') 834 ## except WindowsError: 835 ## pass 836 ## return BreakpointContainer.notify_breakpoint(self, event) 837
838 - def notify_debug_control_c(self, event):
839 """ 840 Notify of a Debug Ctrl-C exception. 841 842 @warning: This method is meant to be used internally by the debugger. 843 844 @note: This exception is only raised when a debugger is attached, and 845 applications are not supposed to handle it, so we need to handle it 846 ourselves or the application may crash. 847 848 @see: U{http://msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx} 849 850 @type event: L{ExceptionEvent} 851 @param event: Debug Ctrl-C exception event. 852 853 @rtype: bool 854 @return: C{True} to call the user-defined handle, C{False} otherwise. 855 """ 856 if event.is_first_chance(): 857 event.continueStatus = win32.DBG_EXCEPTION_HANDLED 858 return True
859
860 - def notify_ms_vc_exception(self, event):
861 """ 862 Notify of a Microsoft Visual C exception. 863 864 @warning: This method is meant to be used internally by the debugger. 865 866 @note: This allows the debugger to understand the 867 Microsoft Visual C thread naming convention. 868 869 @see: U{http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx} 870 871 @type event: L{ExceptionEvent} 872 @param event: Microsoft Visual C exception event. 873 874 @rtype: bool 875 @return: C{True} to call the user-defined handle, C{False} otherwise. 876 """ 877 dwType = event.get_exception_information(0) 878 if dwType == 0x1000: 879 pszName = event.get_exception_information(1) 880 dwThreadId = event.get_exception_information(2) 881 dwFlags = event.get_exception_information(3) 882 883 aProcess = event.get_process() 884 szName = aProcess.peek_string(pszName, fUnicode = False) 885 if szName: 886 887 if dwThreadId == -1: 888 dwThreadId = event.get_tid() 889 890 if aProcess.has_thread(dwThreadId): 891 aThread = aProcess.get_thread(dwThreadId) 892 else: 893 aThread = Thread(dwThreadId) 894 aProcess._ThreadContainer__add_thread(aThread) 895 896 ## if aThread.get_name() is None: 897 ## aThread.set_name(szName) 898 aThread.set_name(szName) 899 900 return True
901