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

Source Code for Module winappdbg.debug

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