1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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
133 self.system.request_debug_privileges()
134
135
136
137
138
139
140
141
142
143
144
145
146
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):
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
214
215 try:
216 self.disable_process_breakpoints(dwProcessId)
217 except Exception:
218 if not bIgnoreExceptions:
219 raise
220
221
222
223
224 try:
225 self.stop_tracing_process(dwProcessId)
226 except Exception:
227 if not bIgnoreExceptions:
228 raise
229
230
231
232
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
242
243
244
245 try:
246 win32.DebugActiveProcessStop(dwProcessId)
247 except Exception:
248 if not bIgnoreExceptions:
249 raise
250
251
252
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
377
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
401 raw = win32.WaitForDebugEvent(dwMilliseconds)
402 event = EventFactory.get(self, raw)
403 return event
404
433
434 - def cont(self, event):
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
489
490
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
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
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
579 """
580 @rtype: int
581 @return: Number of processes being debugged.
582 """
583 return len(self.__attachedDebugees) + len(self.__startedDebugees)
584
586 """
587 @rtype: list( int... )
588 @return: Global IDs of processes being debugged.
589 """
590 return list(self.__attachedDebugees) + list(self.__startedDebugees)
591
603
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
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
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
679
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
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
708 aProcess = event.get_process()
709
710
711 retval = aProcess.notify_load_dll(event)
712
713
714 if self.__bHostileCode:
715 aModule = event.get_module()
716 if aModule.match_name('ntdll.dll'):
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740 DbgUiRemoteBreakin = 'ntdll!DbgUiRemoteBreakin'
741 DbgUiRemoteBreakin = aProcess.resolve_label(DbgUiRemoteBreakin)
742 self.break_at(aProcess.get_pid(), DbgUiRemoteBreakin)
743
744 return retval
745
767
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
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
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
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
901