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 @group Debugging:
32 Debug
33 """
34
35 __revision__ = "$Id: debug.py 648 2010-03-05 21:26:13Z qvasimodo $"
36
37 __all__ = [
38
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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()
126 self.__startedDebugees = set()
127
128 self.system.request_debug_privileges(bIgnoreExceptions = False)
129
130
131
132
133
134
135
136
137
138
139
140
141
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
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):
205
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
225 try:
226 self.erase_process_breakpoints(dwProcessId)
227 except Exception:
228 if not bIgnoreExceptions:
229 raise
230
231
232
233
234 try:
235 self.stop_tracing_process(dwProcessId)
236 except Exception:
237 if not bIgnoreExceptions:
238 raise
239
240
241
242
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
252
253
254
255
256
257 try:
258 self.system.get_process(dwProcessId).clear()
259 except Exception:
260 if not bIgnoreExceptions:
261 raise
262 try:
263
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
287
288
289
290
291 aProcess = self.system.get_process(dwProcessId)
292
293
294 self.__cleanup_process(dwProcessId)
295
296
297 try:
298 aProcess.kill()
299 except Exception:
300 if not bIgnoreExceptions:
301 raise
302
303
304
305
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
328
329
330
331
332 aProcess = self.system.get_process(dwProcessId)
333
334
335 self.__cleanup_process(dwProcessId)
336
337
338
339 try:
340 win32.DebugActiveProcessStop(dwProcessId)
341 except AttributeError:
342 try:
343 aProcess.kill()
344 except Exception:
345 if not bIgnoreExceptions:
346 raise
347
348
349 except Exception:
350 if not bIgnoreExceptions:
351 raise
352
353
354
355
356 aProcess.clear()
357
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
482
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
506 raw = win32.WaitForDebugEvent(dwMilliseconds)
507 event = EventFactory.get(self, raw)
508 return event
509
538
539 - def cont(self, event):
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
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
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
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
713 """
714 @rtype: int
715 @return: Number of processes being debugged.
716 """
717 return len(self.__attachedDebugees) + len(self.__startedDebugees)
718
720 """
721 @rtype: list( int... )
722 @return: Global IDs of processes being debugged.
723 """
724 return list(self.__attachedDebugees) + list(self.__startedDebugees)
725
737
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
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
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
813
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
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
842 aProcess = event.get_process()
843
844
845 retval = aProcess.notify_load_dll(event)
846
847
848 if self.__bHostileCode:
849 aModule = event.get_module()
850 if aModule.match_name('ntdll.dll'):
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874 DbgUiRemoteBreakin = 'ntdll!DbgUiRemoteBreakin'
875 DbgUiRemoteBreakin = aProcess.resolve_label(DbgUiRemoteBreakin)
876 self.break_at(aProcess.get_pid(), DbgUiRemoteBreakin)
877
878 return retval
879
901
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
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
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
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
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
1035