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

Source Code for Module winappdbg.breakpoint

   1  #!~/.wine/drive_c/Python25/python.exe 
   2  # -*- coding: utf-8 -*- 
   3   
   4  # Copyright (c) 2009-2014, Mario Vilas 
   5  # All rights reserved. 
   6  # 
   7  # Redistribution and use in source and binary forms, with or without 
   8  # modification, are permitted provided that the following conditions are met: 
   9  # 
  10  #     * Redistributions of source code must retain the above copyright notice, 
  11  #       this list of conditions and the following disclaimer. 
  12  #     * Redistributions in binary form must reproduce the above copyright 
  13  #       notice,this list of conditions and the following disclaimer in the 
  14  #       documentation and/or other materials provided with the distribution. 
  15  #     * Neither the name of the copyright holder nor the names of its 
  16  #       contributors may be used to endorse or promote products derived from 
  17  #       this software without specific prior written permission. 
  18  # 
  19  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  20  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  21  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  22  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  23  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  24  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  25  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  26  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  27  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  28  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  29  # POSSIBILITY OF SUCH DAMAGE. 
  30   
  31  """ 
  32  Breakpoints. 
  33   
  34  @group Breakpoints: 
  35      Breakpoint, CodeBreakpoint, PageBreakpoint, HardwareBreakpoint, 
  36      BufferWatch, Hook, ApiHook 
  37   
  38  @group Warnings: 
  39      BreakpointWarning, BreakpointCallbackWarning 
  40  """ 
  41   
  42  __revision__ = "$Id: breakpoint.py 1299 2013-12-20 09:30:55Z qvasimodo $" 
  43   
  44  __all__ = [ 
  45   
  46      # Base class for breakpoints 
  47      'Breakpoint', 
  48   
  49      # Breakpoint implementations 
  50      'CodeBreakpoint', 
  51      'PageBreakpoint', 
  52      'HardwareBreakpoint', 
  53   
  54      # Hooks and watches 
  55      'Hook', 
  56      'ApiHook', 
  57      'BufferWatch', 
  58   
  59      # Warnings 
  60      'BreakpointWarning', 
  61      'BreakpointCallbackWarning', 
  62   
  63      ] 
  64   
  65  import win32 
  66  from process import Process, Thread 
  67  from util import DebugRegister, MemoryAddresses 
  68  from textio import HexDump 
  69   
  70  import ctypes 
  71  import warnings 
  72  import traceback 
73 74 #============================================================================== 75 76 -class BreakpointWarning (UserWarning):
77 """ 78 This warning is issued when a non-fatal error occurs that's related to 79 breakpoints. 80 """
81
82 -class BreakpointCallbackWarning (RuntimeWarning):
83 """ 84 This warning is issued when an uncaught exception was raised by a 85 breakpoint's user-defined callback. 86 """
87
88 #============================================================================== 89 90 -class Breakpoint (object):
91 """ 92 Base class for breakpoints. 93 Here's the breakpoints state machine. 94 95 @see: L{CodeBreakpoint}, L{PageBreakpoint}, L{HardwareBreakpoint} 96 97 @group Breakpoint states: 98 DISABLED, ENABLED, ONESHOT, RUNNING 99 @group State machine: 100 hit, disable, enable, one_shot, running, 101 is_disabled, is_enabled, is_one_shot, is_running, 102 get_state, get_state_name 103 @group Information: 104 get_address, get_size, get_span, is_here 105 @group Conditional breakpoints: 106 is_conditional, is_unconditional, 107 get_condition, set_condition, eval_condition 108 @group Automatic breakpoints: 109 is_automatic, is_interactive, 110 get_action, set_action, run_action 111 112 @cvar DISABLED: I{Disabled} S{->} Enabled, OneShot 113 @cvar ENABLED: I{Enabled} S{->} I{Running}, Disabled 114 @cvar ONESHOT: I{OneShot} S{->} I{Disabled} 115 @cvar RUNNING: I{Running} S{->} I{Enabled}, Disabled 116 117 @type DISABLED: int 118 @type ENABLED: int 119 @type ONESHOT: int 120 @type RUNNING: int 121 122 @type stateNames: dict E{lb} int S{->} str E{rb} 123 @cvar stateNames: User-friendly names for each breakpoint state. 124 125 @type typeName: str 126 @cvar typeName: User friendly breakpoint type string. 127 """ 128 129 # I don't think transitions Enabled <-> OneShot should be allowed... plus 130 # it would require special handling to avoid setting the same bp twice 131 132 DISABLED = 0 133 ENABLED = 1 134 ONESHOT = 2 135 RUNNING = 3 136 137 typeName = 'breakpoint' 138 139 stateNames = { 140 DISABLED : 'disabled', 141 ENABLED : 'enabled', 142 ONESHOT : 'one shot', 143 RUNNING : 'running', 144 } 145
146 - def __init__(self, address, size = 1, condition = True, action = None):
147 """ 148 Breakpoint object. 149 150 @type address: int 151 @param address: Memory address for breakpoint. 152 153 @type size: int 154 @param size: Size of breakpoint in bytes (defaults to 1). 155 156 @type condition: function 157 @param condition: (Optional) Condition callback function. 158 159 The callback signature is:: 160 161 def condition_callback(event): 162 return True # returns True or False 163 164 Where B{event} is an L{Event} object, 165 and the return value is a boolean 166 (C{True} to dispatch the event, C{False} otherwise). 167 168 @type action: function 169 @param action: (Optional) Action callback function. 170 If specified, the event is handled by this callback instead of 171 being dispatched normally. 172 173 The callback signature is:: 174 175 def action_callback(event): 176 pass # no return value 177 178 Where B{event} is an L{Event} object. 179 """ 180 self.__address = address 181 self.__size = size 182 self.__state = self.DISABLED 183 184 self.set_condition(condition) 185 self.set_action(action)
186
187 - def __repr__(self):
188 if self.is_disabled(): 189 state = 'Disabled' 190 else: 191 state = 'Active (%s)' % self.get_state_name() 192 if self.is_conditional(): 193 condition = 'conditional' 194 else: 195 condition = 'unconditional' 196 name = self.typeName 197 size = self.get_size() 198 if size == 1: 199 address = HexDump.address( self.get_address() ) 200 else: 201 begin = self.get_address() 202 end = begin + size 203 begin = HexDump.address(begin) 204 end = HexDump.address(end) 205 address = "range %s-%s" % (begin, end) 206 msg = "<%s %s %s at remote address %s>" 207 msg = msg % (state, condition, name, address) 208 return msg
209 210 #------------------------------------------------------------------------------ 211
212 - def is_disabled(self):
213 """ 214 @rtype: bool 215 @return: C{True} if the breakpoint is in L{DISABLED} state. 216 """ 217 return self.get_state() == self.DISABLED
218
219 - def is_enabled(self):
220 """ 221 @rtype: bool 222 @return: C{True} if the breakpoint is in L{ENABLED} state. 223 """ 224 return self.get_state() == self.ENABLED
225
226 - def is_one_shot(self):
227 """ 228 @rtype: bool 229 @return: C{True} if the breakpoint is in L{ONESHOT} state. 230 """ 231 return self.get_state() == self.ONESHOT
232
233 - def is_running(self):
234 """ 235 @rtype: bool 236 @return: C{True} if the breakpoint is in L{RUNNING} state. 237 """ 238 return self.get_state() == self.RUNNING
239
240 - def is_here(self, address):
241 """ 242 @rtype: bool 243 @return: C{True} if the address is within the range of the breakpoint. 244 """ 245 begin = self.get_address() 246 end = begin + self.get_size() 247 return begin <= address < end
248
249 - def get_address(self):
250 """ 251 @rtype: int 252 @return: The target memory address for the breakpoint. 253 """ 254 return self.__address
255
256 - def get_size(self):
257 """ 258 @rtype: int 259 @return: The size in bytes of the breakpoint. 260 """ 261 return self.__size
262
263 - def get_span(self):
264 """ 265 @rtype: tuple( int, int ) 266 @return: 267 Starting and ending address of the memory range 268 covered by the breakpoint. 269 """ 270 address = self.get_address() 271 size = self.get_size() 272 return ( address, address + size )
273
274 - def get_state(self):
275 """ 276 @rtype: int 277 @return: The current state of the breakpoint 278 (L{DISABLED}, L{ENABLED}, L{ONESHOT}, L{RUNNING}). 279 """ 280 return self.__state
281
282 - def get_state_name(self):
283 """ 284 @rtype: str 285 @return: The name of the current state of the breakpoint. 286 """ 287 return self.stateNames[ self.get_state() ]
288 289 #------------------------------------------------------------------------------ 290
291 - def is_conditional(self):
292 """ 293 @see: L{__init__} 294 @rtype: bool 295 @return: C{True} if the breakpoint has a condition callback defined. 296 """ 297 # Do not evaluate as boolean! Test for identity with True instead. 298 return self.__condition is not True
299
300 - def is_unconditional(self):
301 """ 302 @rtype: bool 303 @return: C{True} if the breakpoint doesn't have a condition callback defined. 304 """ 305 # Do not evaluate as boolean! Test for identity with True instead. 306 return self.__condition is True
307
308 - def get_condition(self):
309 """ 310 @rtype: bool, function 311 @return: Returns the condition callback for conditional breakpoints. 312 Returns C{True} for unconditional breakpoints. 313 """ 314 return self.__condition
315
316 - def set_condition(self, condition = True):
317 """ 318 Sets a new condition callback for the breakpoint. 319 320 @see: L{__init__} 321 322 @type condition: function 323 @param condition: (Optional) Condition callback function. 324 """ 325 if condition is None: 326 self.__condition = True 327 else: 328 self.__condition = condition
329
330 - def eval_condition(self, event):
331 """ 332 Evaluates the breakpoint condition, if any was set. 333 334 @type event: L{Event} 335 @param event: Debug event triggered by the breakpoint. 336 337 @rtype: bool 338 @return: C{True} to dispatch the event, C{False} otherwise. 339 """ 340 condition = self.get_condition() 341 if condition is True: # shortcut for unconditional breakpoints 342 return True 343 if callable(condition): 344 try: 345 return bool( condition(event) ) 346 except Exception, e: 347 msg = ("Breakpoint condition callback %r" 348 " raised an exception: %s") 349 msg = msg % (condition, traceback.format_exc(e)) 350 warnings.warn(msg, BreakpointCallbackWarning) 351 return False 352 return bool( condition ) # force evaluation now
353 354 #------------------------------------------------------------------------------ 355
356 - def is_automatic(self):
357 """ 358 @rtype: bool 359 @return: C{True} if the breakpoint has an action callback defined. 360 """ 361 return self.__action is not None
362
363 - def is_interactive(self):
364 """ 365 @rtype: bool 366 @return: 367 C{True} if the breakpoint doesn't have an action callback defined. 368 """ 369 return self.__action is None
370
371 - def get_action(self):
372 """ 373 @rtype: bool, function 374 @return: Returns the action callback for automatic breakpoints. 375 Returns C{None} for interactive breakpoints. 376 """ 377 return self.__action
378
379 - def set_action(self, action = None):
380 """ 381 Sets a new action callback for the breakpoint. 382 383 @type action: function 384 @param action: (Optional) Action callback function. 385 """ 386 self.__action = action
387
388 - def run_action(self, event):
389 """ 390 Executes the breakpoint action callback, if any was set. 391 392 @type event: L{Event} 393 @param event: Debug event triggered by the breakpoint. 394 """ 395 action = self.get_action() 396 if action is not None: 397 try: 398 return bool( action(event) ) 399 except Exception, e: 400 msg = ("Breakpoint action callback %r" 401 " raised an exception: %s") 402 msg = msg % (action, traceback.format_exc(e)) 403 warnings.warn(msg, BreakpointCallbackWarning) 404 return False 405 return True
406 407 #------------------------------------------------------------------------------ 408
409 - def __bad_transition(self, state):
410 """ 411 Raises an C{AssertionError} exception for an invalid state transition. 412 413 @see: L{stateNames} 414 415 @type state: int 416 @param state: Intended breakpoint state. 417 418 @raise Exception: Always. 419 """ 420 statemsg = "" 421 oldState = self.stateNames[ self.get_state() ] 422 newState = self.stateNames[ state ] 423 msg = "Invalid state transition (%s -> %s)" \ 424 " for breakpoint at address %s" 425 msg = msg % (oldState, newState, HexDump.address(self.get_address())) 426 raise AssertionError(msg)
427
428 - def disable(self, aProcess, aThread):
429 """ 430 Transition to L{DISABLED} state. 431 - When hit: OneShot S{->} Disabled 432 - Forced by user: Enabled, OneShot, Running S{->} Disabled 433 - Transition from running state may require special handling 434 by the breakpoint implementation class. 435 436 @type aProcess: L{Process} 437 @param aProcess: Process object. 438 439 @type aThread: L{Thread} 440 @param aThread: Thread object. 441 """ 442 ## if self.__state not in (self.ENABLED, self.ONESHOT, self.RUNNING): 443 ## self.__bad_transition(self.DISABLED) 444 self.__state = self.DISABLED
445
446 - def enable(self, aProcess, aThread):
447 """ 448 Transition to L{ENABLED} state. 449 - When hit: Running S{->} Enabled 450 - Forced by user: Disabled, Running S{->} Enabled 451 - Transition from running state may require special handling 452 by the breakpoint implementation class. 453 454 @type aProcess: L{Process} 455 @param aProcess: Process object. 456 457 @type aThread: L{Thread} 458 @param aThread: Thread object. 459 """ 460 ## if self.__state not in (self.DISABLED, self.RUNNING): 461 ## self.__bad_transition(self.ENABLED) 462 self.__state = self.ENABLED
463
464 - def one_shot(self, aProcess, aThread):
465 """ 466 Transition to L{ONESHOT} state. 467 - Forced by user: Disabled S{->} OneShot 468 469 @type aProcess: L{Process} 470 @param aProcess: Process object. 471 472 @type aThread: L{Thread} 473 @param aThread: Thread object. 474 """ 475 ## if self.__state != self.DISABLED: 476 ## self.__bad_transition(self.ONESHOT) 477 self.__state = self.ONESHOT
478
479 - def running(self, aProcess, aThread):
480 """ 481 Transition to L{RUNNING} state. 482 - When hit: Enabled S{->} Running 483 484 @type aProcess: L{Process} 485 @param aProcess: Process object. 486 487 @type aThread: L{Thread} 488 @param aThread: Thread object. 489 """ 490 if self.__state != self.ENABLED: 491 self.__bad_transition(self.RUNNING) 492 self.__state = self.RUNNING
493
494 - def hit(self, event):
495 """ 496 Notify a breakpoint that it's been hit. 497 498 This triggers the corresponding state transition and sets the 499 C{breakpoint} property of the given L{Event} object. 500 501 @see: L{disable}, L{enable}, L{one_shot}, L{running} 502 503 @type event: L{Event} 504 @param event: Debug event to handle (depends on the breakpoint type). 505 506 @raise AssertionError: Disabled breakpoints can't be hit. 507 """ 508 aProcess = event.get_process() 509 aThread = event.get_thread() 510 state = self.get_state() 511 512 event.breakpoint = self 513 514 if state == self.ENABLED: 515 self.running(aProcess, aThread) 516 517 elif state == self.RUNNING: 518 self.enable(aProcess, aThread) 519 520 elif state == self.ONESHOT: 521 self.disable(aProcess, aThread) 522 523 elif state == self.DISABLED: 524 # this should not happen 525 msg = "Hit a disabled breakpoint at address %s" 526 msg = msg % HexDump.address( self.get_address() ) 527 warnings.warn(msg, BreakpointWarning)
528
529 #============================================================================== 530 531 # XXX TODO 532 # Check if the user is trying to set a code breakpoint on a memory mapped file, 533 # so we don't end up writing the int3 instruction in the file by accident. 534 535 -class CodeBreakpoint (Breakpoint):
536 """ 537 Code execution breakpoints (using an int3 opcode). 538 539 @see: L{Debug.break_at} 540 541 @type bpInstruction: str 542 @cvar bpInstruction: Breakpoint instruction for the current processor. 543 """ 544 545 typeName = 'code breakpoint' 546 547 if win32.arch in (win32.ARCH_I386, win32.ARCH_AMD64): 548 bpInstruction = '\xCC' # int 3 549
550 - def __init__(self, address, condition = True, action = None):
551 """ 552 Code breakpoint object. 553 554 @see: L{Breakpoint.__init__} 555 556 @type address: int 557 @param address: Memory address for breakpoint. 558 559 @type condition: function 560 @param condition: (Optional) Condition callback function. 561 562 @type action: function 563 @param action: (Optional) Action callback function. 564 """ 565 if win32.arch not in (win32.ARCH_I386, win32.ARCH_AMD64): 566 msg = "Code breakpoints not supported for %s" % win32.arch 567 raise NotImplementedError(msg) 568 Breakpoint.__init__(self, address, len(self.bpInstruction), 569 condition, action) 570 self.__previousValue = self.bpInstruction
571
572 - def __set_bp(self, aProcess):
573 """ 574 Writes a breakpoint instruction at the target address. 575 576 @type aProcess: L{Process} 577 @param aProcess: Process object. 578 """ 579 address = self.get_address() 580 self.__previousValue = aProcess.read(address, len(self.bpInstruction)) 581 if self.__previousValue == self.bpInstruction: 582 msg = "Possible overlapping code breakpoints at %s" 583 msg = msg % HexDump.address(address) 584 warnings.warn(msg, BreakpointWarning) 585 aProcess.write(address, self.bpInstruction)
586
587 - def __clear_bp(self, aProcess):
588 """ 589 Restores the original byte at the target address. 590 591 @type aProcess: L{Process} 592 @param aProcess: Process object. 593 """ 594 address = self.get_address() 595 currentValue = aProcess.read(address, len(self.bpInstruction)) 596 if currentValue == self.bpInstruction: 597 # Only restore the previous value if the int3 is still there. 598 aProcess.write(self.get_address(), self.__previousValue) 599 else: 600 self.__previousValue = currentValue 601 msg = "Overwritten code breakpoint at %s" 602 msg = msg % HexDump.address(address) 603 warnings.warn(msg, BreakpointWarning)
604
605 - def disable(self, aProcess, aThread):
606 if not self.is_disabled() and not self.is_running(): 607 self.__clear_bp(aProcess) 608 super(CodeBreakpoint, self).disable(aProcess, aThread)
609
610 - def enable(self, aProcess, aThread):
611 if not self.is_enabled() and not self.is_one_shot(): 612 self.__set_bp(aProcess) 613 super(CodeBreakpoint, self).enable(aProcess, aThread)
614
615 - def one_shot(self, aProcess, aThread):
616 if not self.is_enabled() and not self.is_one_shot(): 617 self.__set_bp(aProcess) 618 super(CodeBreakpoint, self).one_shot(aProcess, aThread)
619 620 # FIXME race condition here (however unlikely) 621 # If another thread runs on over the target address while 622 # the breakpoint is in RUNNING state, we'll miss it. There 623 # is a solution to this but it's somewhat complicated, so 624 # I'm leaving it for another version of the debugger. :(
625 - def running(self, aProcess, aThread):
626 if self.is_enabled(): 627 self.__clear_bp(aProcess) 628 aThread.set_tf() 629 super(CodeBreakpoint, self).running(aProcess, aThread)
630
631 #============================================================================== 632 633 # TODO: 634 # * If the original page was already a guard page, the exception should be 635 # passed to the debugee instead of being handled by the debugger. 636 # * If the original page was already a guard page, it should NOT be converted 637 # to a no-access page when disabling the breakpoint. 638 # * If the page permissions were modified after the breakpoint was enabled, 639 # no change should be done on them when disabling the breakpoint. For this 640 # we need to remember the original page permissions instead of blindly 641 # setting and clearing the guard page bit on them. 642 # * Some pages seem to be "magic" and resist all attempts at changing their 643 # protect bits (for example the pages where the PEB and TEB reside). Maybe 644 # a more descriptive error message could be shown in this case. 645 646 -class PageBreakpoint (Breakpoint):
647 """ 648 Page access breakpoint (using guard pages). 649 650 @see: L{Debug.watch_buffer} 651 652 @group Information: 653 get_size_in_pages 654 """ 655 656 typeName = 'page breakpoint' 657 658 #------------------------------------------------------------------------------ 659
660 - def __init__(self, address, pages = 1, condition = True, action = None):
661 """ 662 Page breakpoint object. 663 664 @see: L{Breakpoint.__init__} 665 666 @type address: int 667 @param address: Memory address for breakpoint. 668 669 @type pages: int 670 @param address: Size of breakpoint in pages. 671 672 @type condition: function 673 @param condition: (Optional) Condition callback function. 674 675 @type action: function 676 @param action: (Optional) Action callback function. 677 """ 678 Breakpoint.__init__(self, address, pages * MemoryAddresses.pageSize, 679 condition, action) 680 ## if (address & 0x00000FFF) != 0: 681 floordiv_align = long(address) // long(MemoryAddresses.pageSize) 682 truediv_align = float(address) / float(MemoryAddresses.pageSize) 683 if floordiv_align != truediv_align: 684 msg = "Address of page breakpoint " \ 685 "must be aligned to a page size boundary " \ 686 "(value %s received)" % HexDump.address(address) 687 raise ValueError(msg)
688
689 - def get_size_in_pages(self):
690 """ 691 @rtype: int 692 @return: The size in pages of the breakpoint. 693 """ 694 # The size is always a multiple of the page size. 695 return self.get_size() // MemoryAddresses.pageSize
696
697 - def __set_bp(self, aProcess):
698 """ 699 Sets the target pages as guard pages. 700 701 @type aProcess: L{Process} 702 @param aProcess: Process object. 703 """ 704 lpAddress = self.get_address() 705 dwSize = self.get_size() 706 flNewProtect = aProcess.mquery(lpAddress).Protect 707 flNewProtect = flNewProtect | win32.PAGE_GUARD 708 aProcess.mprotect(lpAddress, dwSize, flNewProtect)
709
710 - def __clear_bp(self, aProcess):
711 """ 712 Restores the original permissions of the target pages. 713 714 @type aProcess: L{Process} 715 @param aProcess: Process object. 716 """ 717 lpAddress = self.get_address() 718 flNewProtect = aProcess.mquery(lpAddress).Protect 719 flNewProtect = flNewProtect & (0xFFFFFFFF ^ win32.PAGE_GUARD) # DWORD 720 aProcess.mprotect(lpAddress, self.get_size(), flNewProtect)
721
722 - def disable(self, aProcess, aThread):
723 if not self.is_disabled(): 724 self.__clear_bp(aProcess) 725 super(PageBreakpoint, self).disable(aProcess, aThread)
726
727 - def enable(self, aProcess, aThread):
728 if win32.arch not in (win32.ARCH_I386, win32.ARCH_AMD64): 729 msg = "Only one-shot page breakpoints are supported for %s" 730 raise NotImplementedError(msg % win32.arch) 731 if not self.is_enabled() and not self.is_one_shot(): 732 self.__set_bp(aProcess) 733 super(PageBreakpoint, self).enable(aProcess, aThread)
734
735 - def one_shot(self, aProcess, aThread):
736 if not self.is_enabled() and not self.is_one_shot(): 737 self.__set_bp(aProcess) 738 super(PageBreakpoint, self).one_shot(aProcess, aThread)
739
740 - def running(self, aProcess, aThread):
741 aThread.set_tf() 742 super(PageBreakpoint, self).running(aProcess, aThread)
743
744 #============================================================================== 745 746 -class HardwareBreakpoint (Breakpoint):
747 """ 748 Hardware breakpoint (using debug registers). 749 750 @see: L{Debug.watch_variable} 751 752 @group Information: 753 get_slot, get_trigger, get_watch 754 755 @group Trigger flags: 756 BREAK_ON_EXECUTION, BREAK_ON_WRITE, BREAK_ON_ACCESS 757 758 @group Watch size flags: 759 WATCH_BYTE, WATCH_WORD, WATCH_DWORD, WATCH_QWORD 760 761 @type BREAK_ON_EXECUTION: int 762 @cvar BREAK_ON_EXECUTION: Break on execution. 763 764 @type BREAK_ON_WRITE: int 765 @cvar BREAK_ON_WRITE: Break on write. 766 767 @type BREAK_ON_ACCESS: int 768 @cvar BREAK_ON_ACCESS: Break on read or write. 769 770 @type WATCH_BYTE: int 771 @cvar WATCH_BYTE: Watch a byte. 772 773 @type WATCH_WORD: int 774 @cvar WATCH_WORD: Watch a word (2 bytes). 775 776 @type WATCH_DWORD: int 777 @cvar WATCH_DWORD: Watch a double word (4 bytes). 778 779 @type WATCH_QWORD: int 780 @cvar WATCH_QWORD: Watch one quad word (8 bytes). 781 782 @type validTriggers: tuple 783 @cvar validTriggers: Valid trigger flag values. 784 785 @type validWatchSizes: tuple 786 @cvar validWatchSizes: Valid watch flag values. 787 """ 788 789 typeName = 'hardware breakpoint' 790 791 BREAK_ON_EXECUTION = DebugRegister.BREAK_ON_EXECUTION 792 BREAK_ON_WRITE = DebugRegister.BREAK_ON_WRITE 793 BREAK_ON_ACCESS = DebugRegister.BREAK_ON_ACCESS 794 795 WATCH_BYTE = DebugRegister.WATCH_BYTE 796 WATCH_WORD = DebugRegister.WATCH_WORD 797 WATCH_DWORD = DebugRegister.WATCH_DWORD 798 WATCH_QWORD = DebugRegister.WATCH_QWORD 799 800 validTriggers = ( 801 BREAK_ON_EXECUTION, 802 BREAK_ON_WRITE, 803 BREAK_ON_ACCESS, 804 ) 805 806 validWatchSizes = ( 807 WATCH_BYTE, 808 WATCH_WORD, 809 WATCH_DWORD, 810 WATCH_QWORD, 811 ) 812
813 - def __init__(self, address, triggerFlag = BREAK_ON_ACCESS, 814 sizeFlag = WATCH_DWORD, 815 condition = True, 816 action = None):
817 """ 818 Hardware breakpoint object. 819 820 @see: L{Breakpoint.__init__} 821 822 @type address: int 823 @param address: Memory address for breakpoint. 824 825 @type triggerFlag: int 826 @param triggerFlag: Trigger of breakpoint. Must be one of the following: 827 828 - L{BREAK_ON_EXECUTION} 829 830 Break on code execution. 831 832 - L{BREAK_ON_WRITE} 833 834 Break on memory read or write. 835 836 - L{BREAK_ON_ACCESS} 837 838 Break on memory write. 839 840 @type sizeFlag: int 841 @param sizeFlag: Size of breakpoint. Must be one of the following: 842 843 - L{WATCH_BYTE} 844 845 One (1) byte in size. 846 847 - L{WATCH_WORD} 848 849 Two (2) bytes in size. 850 851 - L{WATCH_DWORD} 852 853 Four (4) bytes in size. 854 855 - L{WATCH_QWORD} 856 857 Eight (8) bytes in size. 858 859 @type condition: function 860 @param condition: (Optional) Condition callback function. 861 862 @type action: function 863 @param action: (Optional) Action callback function. 864 """ 865 if win32.arch not in (win32.ARCH_I386, win32.ARCH_AMD64): 866 msg = "Hardware breakpoints not supported for %s" % win32.arch 867 raise NotImplementedError(msg) 868 if sizeFlag == self.WATCH_BYTE: 869 size = 1 870 elif sizeFlag == self.WATCH_WORD: 871 size = 2 872 elif sizeFlag == self.WATCH_DWORD: 873 size = 4 874 elif sizeFlag == self.WATCH_QWORD: 875 size = 8 876 else: 877 msg = "Invalid size flag for hardware breakpoint (%s)" 878 msg = msg % repr(sizeFlag) 879 raise ValueError(msg) 880 881 if triggerFlag not in self.validTriggers: 882 msg = "Invalid trigger flag for hardware breakpoint (%s)" 883 msg = msg % repr(triggerFlag) 884 raise ValueError(msg) 885 886 Breakpoint.__init__(self, address, size, condition, action) 887 self.__trigger = triggerFlag 888 self.__watch = sizeFlag 889 self.__slot = None
890
891 - def __clear_bp(self, aThread):
892 """ 893 Clears this breakpoint from the debug registers. 894 895 @type aThread: L{Thread} 896 @param aThread: Thread object. 897 """ 898 if self.__slot is not None: 899 aThread.suspend() 900 try: 901 ctx = aThread.get_context(win32.CONTEXT_DEBUG_REGISTERS) 902 DebugRegister.clear_bp(ctx, self.__slot) 903 aThread.set_context(ctx) 904 self.__slot = None 905 finally: 906 aThread.resume()
907
908 - def __set_bp(self, aThread):
909 """ 910 Sets this breakpoint in the debug registers. 911 912 @type aThread: L{Thread} 913 @param aThread: Thread object. 914 """ 915 if self.__slot is None: 916 aThread.suspend() 917 try: 918 ctx = aThread.get_context(win32.CONTEXT_DEBUG_REGISTERS) 919 self.__slot = DebugRegister.find_slot(ctx) 920 if self.__slot is None: 921 msg = "No available hardware breakpoint slots for thread ID %d" 922 msg = msg % aThread.get_tid() 923 raise RuntimeError(msg) 924 DebugRegister.set_bp(ctx, self.__slot, self.get_address(), 925 self.__trigger, self.__watch) 926 aThread.set_context(ctx) 927 finally: 928 aThread.resume()
929
930 - def get_slot(self):
931 """ 932 @rtype: int 933 @return: The debug register number used by this breakpoint, 934 or C{None} if the breakpoint is not active. 935 """ 936 return self.__slot
937
938 - def get_trigger(self):
939 """ 940 @see: L{validTriggers} 941 @rtype: int 942 @return: The breakpoint trigger flag. 943 """ 944 return self.__trigger
945
946 - def get_watch(self):
947 """ 948 @see: L{validWatchSizes} 949 @rtype: int 950 @return: The breakpoint watch flag. 951 """ 952 return self.__watch
953
954 - def disable(self, aProcess, aThread):
955 if not self.is_disabled(): 956 self.__clear_bp(aThread) 957 super(HardwareBreakpoint, self).disable(aProcess, aThread)
958
959 - def enable(self, aProcess, aThread):
960 if not self.is_enabled() and not self.is_one_shot(): 961 self.__set_bp(aThread) 962 super(HardwareBreakpoint, self).enable(aProcess, aThread)
963
964 - def one_shot(self, aProcess, aThread):
965 if not self.is_enabled() and not self.is_one_shot(): 966 self.__set_bp(aThread) 967 super(HardwareBreakpoint, self).one_shot(aProcess, aThread)
968
969 - def running(self, aProcess, aThread):
970 self.__clear_bp(aThread) 971 super(HardwareBreakpoint, self).running(aProcess, aThread) 972 aThread.set_tf()
973
974 #============================================================================== 975 976 # XXX FIXME 977 # 978 # The implementation of function hooks is very simple. A breakpoint is set at 979 # the entry point. Each time it's hit the "pre" callback is executed. If a 980 # "post" callback was defined, a one-shot breakpoint is set at the return 981 # address - and when that breakpoint hits, the "post" callback is executed. 982 # 983 # Functions hooks, as they are implemented now, don't work correctly for 984 # recursive functions. The problem is we don't know when to remove the 985 # breakpoint at the return address. Also there could be more than one return 986 # address. 987 # 988 # One possible solution would involve a dictionary of lists, where the key 989 # would be the thread ID and the value a stack of return addresses. But we 990 # still don't know what to do if the "wrong" return address is hit for some 991 # reason (maybe check the stack pointer?). Or if both a code and a hardware 992 # breakpoint are hit simultaneously. 993 # 994 # For now, the workaround for the user is to set only the "pre" callback for 995 # functions that are known to be recursive. 996 # 997 # If an exception is thrown by a hooked function and caught by one of it's 998 # parent functions, the "post" callback won't be called and weird stuff may 999 # happen. A possible solution is to put a breakpoint in the system call that 1000 # unwinds the stack, to detect this case and remove the "post" breakpoint. 1001 # 1002 # Hooks may also behave oddly if the return address is overwritten by a buffer 1003 # overflow bug (this is similar to the exception problem). But it's probably a 1004 # minor issue since when you're fuzzing a function for overflows you're usually 1005 # not interested in the return value anyway. 1006 1007 # TODO: an API to modify the hooked function's arguments 1008 1009 -class Hook (object):
1010 """ 1011 Factory class to produce hook objects. Used by L{Debug.hook_function} and 1012 L{Debug.stalk_function}. 1013 1014 When you try to instance this class, one of the architecture specific 1015 implementations is returned instead. 1016 1017 Instances act as an action callback for code breakpoints set at the 1018 beginning of a function. It automatically retrieves the parameters from 1019 the stack, sets a breakpoint at the return address and retrieves the 1020 return value from the function call. 1021 1022 @see: L{_Hook_i386}, L{_Hook_amd64} 1023 1024 @type useHardwareBreakpoints: bool 1025 @cvar useHardwareBreakpoints: C{True} to try to use hardware breakpoints, 1026 C{False} otherwise. 1027 """ 1028 1029 # This is a factory class that returns 1030 # the architecture specific implementation.
1031 - def __new__(cls, *argv, **argd):
1032 try: 1033 arch = argd['arch'] 1034 del argd['arch'] 1035 except KeyError: 1036 try: 1037 arch = argv[4] 1038 argv = argv[:4] + argv[5:] 1039 except IndexError: 1040 raise TypeError("Missing 'arch' argument!") 1041 if arch is None: 1042 arch = win32.arch 1043 if arch == win32.ARCH_I386: 1044 return _Hook_i386(*argv, **argd) 1045 if arch == win32.ARCH_AMD64: 1046 return _Hook_amd64(*argv, **argd) 1047 return object.__new__(cls, *argv, **argd)
1048 1049 # XXX FIXME 1050 # 1051 # Hardware breakpoints don't work correctly (or al all) in old VirtualBox 1052 # versions (3.0 and below). 1053 # 1054 # Maybe there should be a way to autodetect the buggy VirtualBox versions 1055 # and tell Hook objects not to use hardware breakpoints? 1056 # 1057 # For now the workaround is to manually set this variable to True when 1058 # WinAppDbg is installed on a physical machine. 1059 # 1060 useHardwareBreakpoints = False 1061
1062 - def __init__(self, preCB = None, postCB = None, 1063 paramCount = None, signature = None, 1064 arch = None):
1065 """ 1066 @type preCB: function 1067 @param preCB: (Optional) Callback triggered on function entry. 1068 1069 The signature for the callback should be something like this:: 1070 1071 def pre_LoadLibraryEx(event, ra, lpFilename, hFile, dwFlags): 1072 1073 # return address 1074 ra = params[0] 1075 1076 # function arguments start from here... 1077 szFilename = event.get_process().peek_string(lpFilename) 1078 1079 # (...) 1080 1081 Note that all pointer types are treated like void pointers, so your 1082 callback won't get the string or structure pointed to by it, but 1083 the remote memory address instead. This is so to prevent the ctypes 1084 library from being "too helpful" and trying to dereference the 1085 pointer. To get the actual data being pointed to, use one of the 1086 L{Process.read} methods. 1087 1088 @type postCB: function 1089 @param postCB: (Optional) Callback triggered on function exit. 1090 1091 The signature for the callback should be something like this:: 1092 1093 def post_LoadLibraryEx(event, return_value): 1094 1095 # (...) 1096 1097 @type paramCount: int 1098 @param paramCount: 1099 (Optional) Number of parameters for the C{preCB} callback, 1100 not counting the return address. Parameters are read from 1101 the stack and assumed to be DWORDs in 32 bits and QWORDs in 64. 1102 1103 This is a faster way to pull stack parameters in 32 bits, but in 64 1104 bits (or with some odd APIs in 32 bits) it won't be useful, since 1105 not all arguments to the hooked function will be of the same size. 1106 1107 For a more reliable and cross-platform way of hooking use the 1108 C{signature} argument instead. 1109 1110 @type signature: tuple 1111 @param signature: 1112 (Optional) Tuple of C{ctypes} data types that constitute the 1113 hooked function signature. When the function is called, this will 1114 be used to parse the arguments from the stack. Overrides the 1115 C{paramCount} argument. 1116 1117 @type arch: str 1118 @param arch: (Optional) Target architecture. Defaults to the current 1119 architecture. See: L{win32.arch} 1120 """ 1121 self.__preCB = preCB 1122 self.__postCB = postCB 1123 self.__paramStack = dict() # tid -> list of tuple( arg, arg, arg... ) 1124 1125 self._paramCount = paramCount 1126 1127 if win32.arch != win32.ARCH_I386: 1128 self.useHardwareBreakpoints = False 1129 1130 if win32.bits == 64 and paramCount and not signature: 1131 signature = (win32.QWORD,) * paramCount 1132 1133 if signature: 1134 self._signature = self._calc_signature(signature) 1135 else: 1136 self._signature = None
1137
1138 - def _cast_signature_pointers_to_void(self, signature):
1139 c_void_p = ctypes.c_void_p 1140 c_char_p = ctypes.c_char_p 1141 c_wchar_p = ctypes.c_wchar_p 1142 _Pointer = ctypes._Pointer 1143 cast = ctypes.cast 1144 for i in xrange(len(signature)): 1145 t = signature[i] 1146 if t is not c_void_p and (issubclass(t, _Pointer) \ 1147 or t in [c_char_p, c_wchar_p]): 1148 signature[i] = cast(t, c_void_p)
1149
1150 - def _calc_signature(self, signature):
1151 raise NotImplementedError( 1152 "Hook signatures are not supported for architecture: %s" \ 1153 % win32.arch)
1154
1155 - def _get_return_address(self, aProcess, aThread):
1156 return None
1157
1158 - def _get_function_arguments(self, aProcess, aThread):
1159 if self._signature or self._paramCount: 1160 raise NotImplementedError( 1161 "Hook signatures are not supported for architecture: %s" \ 1162 % win32.arch) 1163 return ()
1164
1165 - def _get_return_value(self, aThread):
1166 return None
1167 1168 # By using break_at() to set a process-wide breakpoint on the function's 1169 # return address, we might hit a race condition when more than one thread 1170 # is being debugged. 1171 # 1172 # Hardware breakpoints should be used instead. But since a thread can run 1173 # out of those, we need to fall back to this method when needed. 1174
1175 - def __call__(self, event):
1176 """ 1177 Handles the breakpoint event on entry of the function. 1178 1179 @type event: L{ExceptionEvent} 1180 @param event: Breakpoint hit event. 1181 1182 @raise WindowsError: An error occured. 1183 """ 1184 debug = event.debug 1185 1186 dwProcessId = event.get_pid() 1187 dwThreadId = event.get_tid() 1188 aProcess = event.get_process() 1189 aThread = event.get_thread() 1190 1191 # Get the return address and function arguments. 1192 ra = self._get_return_address(aProcess, aThread) 1193 params = self._get_function_arguments(aProcess, aThread) 1194 1195 # Keep the function arguments for later use. 1196 self.__push_params(dwThreadId, params) 1197 1198 # If we need to hook the return from the function... 1199 bHookedReturn = False 1200 if ra is not None and self.__postCB is not None: 1201 1202 # Try to set a one shot hardware breakpoint at the return address. 1203 useHardwareBreakpoints = self.useHardwareBreakpoints 1204 if useHardwareBreakpoints: 1205 try: 1206 debug.define_hardware_breakpoint( 1207 dwThreadId, 1208 ra, 1209 event.debug.BP_BREAK_ON_EXECUTION, 1210 event.debug.BP_WATCH_BYTE, 1211 True, 1212 self.__postCallAction_hwbp 1213 ) 1214 debug.enable_one_shot_hardware_breakpoint(dwThreadId, ra) 1215 bHookedReturn = True 1216 except Exception, e: 1217 useHardwareBreakpoints = False 1218 msg = ("Failed to set hardware breakpoint" 1219 " at address %s for thread ID %d") 1220 msg = msg % (HexDump.address(ra), dwThreadId) 1221 warnings.warn(msg, BreakpointWarning) 1222 1223 # If not possible, set a code breakpoint instead. 1224 if not useHardwareBreakpoints: 1225 try: 1226 debug.break_at(dwProcessId, ra, 1227 self.__postCallAction_codebp) 1228 bHookedReturn = True 1229 except Exception, e: 1230 msg = ("Failed to set code breakpoint" 1231 " at address %s for process ID %d") 1232 msg = msg % (HexDump.address(ra), dwProcessId) 1233 warnings.warn(msg, BreakpointWarning) 1234 1235 # Call the "pre" callback. 1236 try: 1237 self.__callHandler(self.__preCB, event, ra, *params) 1238 1239 # If no "post" callback is defined, forget the function arguments. 1240 finally: 1241 if not bHookedReturn: 1242 self.__pop_params(dwThreadId)
1243
1244 - def __postCallAction_hwbp(self, event):
1245 """ 1246 Handles hardware breakpoint events on return from the function. 1247 1248 @type event: L{ExceptionEvent} 1249 @param event: Single step event. 1250 """ 1251 1252 # Remove the one shot hardware breakpoint 1253 # at the return address location in the stack. 1254 tid = event.get_tid() 1255 address = event.breakpoint.get_address() 1256 event.debug.erase_hardware_breakpoint(tid, address) 1257 1258 # Call the "post" callback. 1259 try: 1260 self.__postCallAction(event) 1261 1262 # Forget the parameters. 1263 finally: 1264 self.__pop_params(tid)
1265
1266 - def __postCallAction_codebp(self, event):
1267 """ 1268 Handles code breakpoint events on return from the function. 1269 1270 @type event: L{ExceptionEvent} 1271 @param event: Breakpoint hit event. 1272 """ 1273 1274 # If the breakpoint was accidentally hit by another thread, 1275 # pass it to the debugger instead of calling the "post" callback. 1276 # 1277 # XXX FIXME: 1278 # I suppose this check will fail under some weird conditions... 1279 # 1280 tid = event.get_tid() 1281 if tid not in self.__paramStack: 1282 return True 1283 1284 # Remove the code breakpoint at the return address. 1285 pid = event.get_pid() 1286 address = event.breakpoint.get_address() 1287 event.debug.dont_break_at(pid, address) 1288 1289 # Call the "post" callback. 1290 try: 1291 self.__postCallAction(event) 1292 1293 # Forget the parameters. 1294 finally: 1295 self.__pop_params(tid)
1296
1297 - def __postCallAction(self, event):
1298 """ 1299 Calls the "post" callback. 1300 1301 @type event: L{ExceptionEvent} 1302 @param event: Breakpoint hit event. 1303 """ 1304 aThread = event.get_thread() 1305 retval = self._get_return_value(aThread) 1306 self.__callHandler(self.__postCB, event, retval)
1307
1308 - def __callHandler(self, callback, event, *params):
1309 """ 1310 Calls a "pre" or "post" handler, if set. 1311 1312 @type callback: function 1313 @param callback: Callback function to call. 1314 1315 @type event: L{ExceptionEvent} 1316 @param event: Breakpoint hit event. 1317 1318 @type params: tuple 1319 @param params: Parameters for the callback function. 1320 """ 1321 if callback is not None: 1322 event.hook = self 1323 callback(event, *params)
1324
1325 - def __push_params(self, tid, params):
1326 """ 1327 Remembers the arguments tuple for the last call to the hooked function 1328 from this thread. 1329 1330 @type tid: int 1331 @param tid: Thread global ID. 1332 1333 @type params: tuple( arg, arg, arg... ) 1334 @param params: Tuple of arguments. 1335 """ 1336 stack = self.__paramStack.get( tid, [] ) 1337 stack.append(params) 1338 self.__paramStack[tid] = stack
1339
1340 - def __pop_params(self, tid):
1341 """ 1342 Forgets the arguments tuple for the last call to the hooked function 1343 from this thread. 1344 1345 @type tid: int 1346 @param tid: Thread global ID. 1347 """ 1348 stack = self.__paramStack[tid] 1349 stack.pop() 1350 if not stack: 1351 del self.__paramStack[tid]
1352
1353 - def get_params(self, tid):
1354 """ 1355 Returns the parameters found in the stack when the hooked function 1356 was last called by this thread. 1357 1358 @type tid: int 1359 @param tid: Thread global ID. 1360 1361 @rtype: tuple( arg, arg, arg... ) 1362 @return: Tuple of arguments. 1363 """ 1364 try: 1365 params = self.get_params_stack(tid)[-1] 1366 except IndexError: 1367 msg = "Hooked function called from thread %d already returned" 1368 raise IndexError(msg % tid) 1369 return params
1370
1371 - def get_params_stack(self, tid):
1372 """ 1373 Returns the parameters found in the stack each time the hooked function 1374 was called by this thread and hasn't returned yet. 1375 1376 @type tid: int 1377 @param tid: Thread global ID. 1378 1379 @rtype: list of tuple( arg, arg, arg... ) 1380 @return: List of argument tuples. 1381 """ 1382 try: 1383 stack = self.__paramStack[tid] 1384 except KeyError: 1385 msg = "Hooked function was not called from thread %d" 1386 raise KeyError(msg % tid) 1387 return stack
1388
1389 - def hook(self, debug, pid, address):
1390 """ 1391 Installs the function hook at a given process and address. 1392 1393 @see: L{unhook} 1394 1395 @warning: Do not call from an function hook callback. 1396 1397 @type debug: L{Debug} 1398 @param debug: Debug object. 1399 1400 @type pid: int 1401 @param pid: Process ID. 1402 1403 @type address: int 1404 @param address: Function address. 1405 """ 1406 return debug.break_at(pid, address, self)
1407
1408 - def unhook(self, debug, pid, address):
1409 """ 1410 Removes the function hook at a given process and address. 1411 1412 @see: L{hook} 1413 1414 @warning: Do not call from an function hook callback. 1415 1416 @type debug: L{Debug} 1417 @param debug: Debug object. 1418 1419 @type pid: int 1420 @param pid: Process ID. 1421 1422 @type address: int 1423 @param address: Function address. 1424 """ 1425 return debug.dont_break_at(pid, address)
1426
1427 -class _Hook_i386 (Hook):
1428 """ 1429 Implementation details for L{Hook} on the L{win32.ARCH_I386} architecture. 1430 """ 1431 1432 # We don't want to inherit the parent class __new__ method. 1433 __new__ = object.__new__ 1434
1435 - def _calc_signature(self, signature):
1436 self._cast_signature_pointers_to_void(signature) 1437 class Arguments (ctypes.Structure): 1438 _fields_ = [ ("arg_%s" % i, signature[i]) \ 1439 for i in xrange(len(signature) - 1, -1, -1) ]
1440 return Arguments
1441
1442 - def _get_return_address(self, aProcess, aThread):
1443 return aProcess.read_pointer( aThread.get_sp() )
1444
1445 - def _get_function_arguments(self, aProcess, aThread):
1446 if self._signature: 1447 params = aThread.read_stack_structure(self._signature, 1448 offset = win32.sizeof(win32.LPVOID)) 1449 elif self._paramCount: 1450 params = aThread.read_stack_dwords(self._paramCount, 1451 offset = win32.sizeof(win32.LPVOID)) 1452 else: 1453 params = () 1454 return params
1455
1456 - def _get_return_value(self, aThread):
1457 ctx = aThread.get_context(win32.CONTEXT_INTEGER) 1458 return ctx['Eax']
1459
1460 -class _Hook_amd64 (Hook):
1461 """ 1462 Implementation details for L{Hook} on the L{win32.ARCH_AMD64} architecture. 1463 """ 1464 1465 # We don't want to inherit the parent class __new__ method. 1466 __new__ = object.__new__ 1467 1468 # Make a list of floating point types. 1469 __float_types = ( 1470 ctypes.c_double, 1471 ctypes.c_float, 1472 ) 1473 # Long doubles are not supported in old versions of ctypes! 1474 try: 1475 __float_types += (ctypes.c_longdouble,) 1476 except AttributeError: 1477 pass 1478
1479 - def _calc_signature(self, signature):
1480 self._cast_signature_pointers_to_void(signature) 1481 1482 float_types = self.__float_types 1483 c_sizeof = ctypes.sizeof 1484 reg_size = c_sizeof(ctypes.c_size_t) 1485 1486 reg_int_sig = [] 1487 reg_float_sig = [] 1488 stack_sig = [] 1489 1490 for i in xrange(len(signature)): 1491 arg = signature[i] 1492 name = "arg_%d" % i 1493 stack_sig.insert( 0, (name, arg) ) 1494 if i < 4: 1495 if type(arg) in float_types: 1496 reg_float_sig.append( (name, arg) ) 1497 elif c_sizeof(arg) <= reg_size: 1498 reg_int_sig.append( (name, arg) ) 1499 else: 1500 msg = ("Hook signatures don't support structures" 1501 " within the first 4 arguments of a function" 1502 " for the %s architecture") % win32.arch 1503 raise NotImplementedError(msg) 1504 1505 if reg_int_sig: 1506 class RegisterArguments (ctypes.Structure): 1507 _fields_ = reg_int_sig
1508 else: 1509 RegisterArguments = None 1510 if reg_float_sig: 1511 class FloatArguments (ctypes.Structure): 1512 _fields_ = reg_float_sig
1513 else: 1514 FloatArguments = None 1515 if stack_sig: 1516 class StackArguments (ctypes.Structure): 1517 _fields_ = stack_sig 1518 else: 1519 StackArguments = None 1520 1521 return (len(signature), 1522 RegisterArguments, 1523 FloatArguments, 1524 StackArguments) 1525
1526 - def _get_return_address(self, aProcess, aThread):
1527 return aProcess.read_pointer( aThread.get_sp() )
1528
1529 - def _get_function_arguments(self, aProcess, aThread):
1530 if self._signature: 1531 (args_count, 1532 RegisterArguments, 1533 FloatArguments, 1534 StackArguments) = self._signature 1535 arguments = {} 1536 if StackArguments: 1537 address = aThread.get_sp() + win32.sizeof(win32.LPVOID) 1538 stack_struct = aProcess.read_structure(address, 1539 StackArguments) 1540 stack_args = dict( 1541 [ (name, stack_struct.__getattribute__(name)) 1542 for (name, type) in stack_struct._fields_ ] 1543 ) 1544 arguments.update(stack_args) 1545 flags = 0 1546 if RegisterArguments: 1547 flags = flags | win32.CONTEXT_INTEGER 1548 if FloatArguments: 1549 flags = flags | win32.CONTEXT_MMX_REGISTERS 1550 if flags: 1551 ctx = aThread.get_context(flags) 1552 if RegisterArguments: 1553 buffer = (win32.QWORD * 4)(ctx['Rcx'], ctx['Rdx'], 1554 ctx['R8'], ctx['R9']) 1555 reg_args = self._get_arguments_from_buffer(buffer, 1556 RegisterArguments) 1557 arguments.update(reg_args) 1558 if FloatArguments: 1559 buffer = (win32.M128A * 4)(ctx['XMM0'], ctx['XMM1'], 1560 ctx['XMM2'], ctx['XMM3']) 1561 float_args = self._get_arguments_from_buffer(buffer, 1562 FloatArguments) 1563 arguments.update(float_args) 1564 params = tuple( [ arguments["arg_%d" % i] 1565 for i in xrange(args_count) ] ) 1566 else: 1567 params = () 1568 return params
1569
1570 - def _get_arguments_from_buffer(self, buffer, structure):
1571 b_ptr = ctypes.pointer(buffer) 1572 v_ptr = ctypes.cast(b_ptr, ctypes.c_void_p) 1573 s_ptr = ctypes.cast(v_ptr, ctypes.POINTER(structure)) 1574 struct = s_ptr.contents 1575 return dict( 1576 [ (name, struct.__getattribute__(name)) 1577 for (name, type) in struct._fields_ ] 1578 )
1579
1580 - def _get_return_value(self, aThread):
1581 ctx = aThread.get_context(win32.CONTEXT_INTEGER) 1582 return ctx['Rax']
1583
1584 #------------------------------------------------------------------------------ 1585 1586 # This class acts as a factory of Hook objects, one per target process. 1587 # Said objects are deleted by the unhook() method. 1588 1589 -class ApiHook (object):
1590 """ 1591 Used by L{EventHandler}. 1592 1593 This class acts as an action callback for code breakpoints set at the 1594 beginning of a function. It automatically retrieves the parameters from 1595 the stack, sets a breakpoint at the return address and retrieves the 1596 return value from the function call. 1597 1598 @see: L{EventHandler.apiHooks} 1599 1600 @type modName: str 1601 @ivar modName: Module name. 1602 1603 @type procName: str 1604 @ivar procName: Procedure name. 1605 """ 1606
1607 - def __init__(self, eventHandler, modName, procName, paramCount = None, 1608 signature = None):
1609 """ 1610 @type eventHandler: L{EventHandler} 1611 @param eventHandler: Event handler instance. This is where the hook 1612 callbacks are to be defined (see below). 1613 1614 @type modName: str 1615 @param modName: Module name. 1616 1617 @type procName: str 1618 @param procName: Procedure name. 1619 The pre and post callbacks will be deduced from it. 1620 1621 For example, if the procedure is "LoadLibraryEx" the callback 1622 routines will be "pre_LoadLibraryEx" and "post_LoadLibraryEx". 1623 1624 The signature for the callbacks should be something like this:: 1625 1626 def pre_LoadLibraryEx(self, event, ra, lpFilename, hFile, dwFlags): 1627 1628 # return address 1629 ra = params[0] 1630 1631 # function arguments start from here... 1632 szFilename = event.get_process().peek_string(lpFilename) 1633 1634 # (...) 1635 1636 def post_LoadLibraryEx(self, event, return_value): 1637 1638 # (...) 1639 1640 Note that all pointer types are treated like void pointers, so your 1641 callback won't get the string or structure pointed to by it, but 1642 the remote memory address instead. This is so to prevent the ctypes 1643 library from being "too helpful" and trying to dereference the 1644 pointer. To get the actual data being pointed to, use one of the 1645 L{Process.read} methods. 1646 1647 @type paramCount: int 1648 @param paramCount: 1649 (Optional) Number of parameters for the C{preCB} callback, 1650 not counting the return address. Parameters are read from 1651 the stack and assumed to be DWORDs in 32 bits and QWORDs in 64. 1652 1653 This is a faster way to pull stack parameters in 32 bits, but in 64 1654 bits (or with some odd APIs in 32 bits) it won't be useful, since 1655 not all arguments to the hooked function will be of the same size. 1656 1657 For a more reliable and cross-platform way of hooking use the 1658 C{signature} argument instead. 1659 1660 @type signature: tuple 1661 @param signature: 1662 (Optional) Tuple of C{ctypes} data types that constitute the 1663 hooked function signature. When the function is called, this will 1664 be used to parse the arguments from the stack. Overrides the 1665 C{paramCount} argument. 1666 """ 1667 self.__modName = modName 1668 self.__procName = procName 1669 self.__paramCount = paramCount 1670 self.__signature = signature 1671 self.__preCB = getattr(eventHandler, 'pre_%s' % procName, None) 1672 self.__postCB = getattr(eventHandler, 'post_%s' % procName, None) 1673 self.__hook = dict()
1674
1675 - def __call__(self, event):
1676 """ 1677 Handles the breakpoint event on entry of the function. 1678 1679 @type event: L{ExceptionEvent} 1680 @param event: Breakpoint hit event. 1681 1682 @raise WindowsError: An error occured. 1683 """ 1684 pid = event.get_pid() 1685 try: 1686 hook = self.__hook[pid] 1687 except KeyError: 1688 hook = Hook(self.__preCB, self.__postCB, 1689 self.__paramCount, self.__signature, 1690 event.get_process().get_arch() ) 1691 self.__hook[pid] = hook 1692 return hook(event)
1693 1694 @property
1695 - def modName(self):
1696 return self.__modName
1697 1698 @property
1699 - def procName(self):
1700 return self.__procName
1701
1702 - def hook(self, debug, pid):
1703 """ 1704 Installs the API hook on a given process and module. 1705 1706 @warning: Do not call from an API hook callback. 1707 1708 @type debug: L{Debug} 1709 @param debug: Debug object. 1710 1711 @type pid: int 1712 @param pid: Process ID. 1713 """ 1714 label = "%s!%s" % (self.__modName, self.__procName) 1715 try: 1716 hook = self.__hook[pid] 1717 except KeyError: 1718 try: 1719 aProcess = debug.system.get_process(pid) 1720 except KeyError: 1721 aProcess = Process(pid) 1722 hook = Hook(self.__preCB, self.__postCB, 1723 self.__paramCount, self.__signature, 1724 aProcess.get_arch() ) 1725 self.__hook[pid] = hook 1726 hook.hook(debug, pid, label)
1727
1728 - def unhook(self, debug, pid):
1729 """ 1730 Removes the API hook from the given process and module. 1731 1732 @warning: Do not call from an API hook callback. 1733 1734 @type debug: L{Debug} 1735 @param debug: Debug object. 1736 1737 @type pid: int 1738 @param pid: Process ID. 1739 """ 1740 try: 1741 hook = self.__hook[pid] 1742 except KeyError: 1743 return 1744 label = "%s!%s" % (self.__modName, self.__procName) 1745 hook.unhook(debug, pid, label) 1746 del self.__hook[pid]
1747
1748 #============================================================================== 1749 1750 -class BufferWatch (object):
1751 """ 1752 Returned by L{Debug.watch_buffer}. 1753 1754 This object uniquely references a buffer being watched, even if there are 1755 multiple watches set on the exact memory region. 1756 1757 @type pid: int 1758 @ivar pid: Process ID. 1759 1760 @type start: int 1761 @ivar start: Memory address of the start of the buffer. 1762 1763 @type end: int 1764 @ivar end: Memory address of the end of the buffer. 1765 1766 @type action: callable 1767 @ivar action: Action callback. 1768 1769 @type oneshot: bool 1770 @ivar oneshot: C{True} for one shot breakpoints, C{False} otherwise. 1771 """ 1772
1773 - def __init__(self, pid, start, end, action = None, oneshot = False):
1774 self.__pid = pid 1775 self.__start = start 1776 self.__end = end 1777 self.__action = action 1778 self.__oneshot = oneshot
1779 1780 @property
1781 - def pid(self):
1782 return self.__pid
1783 1784 @property
1785 - def start(self):
1786 return self.__start
1787 1788 @property
1789 - def end(self):
1790 return self.__end
1791 1792 @property
1793 - def action(self):
1794 return self.__action
1795 1796 @property
1797 - def oneshot(self):
1798 return self.__oneshot
1799
1800 - def match(self, address):
1801 """ 1802 Determine if the given memory address lies within the watched buffer. 1803 1804 @rtype: bool 1805 @return: C{True} if the given memory address lies within the watched 1806 buffer, C{False} otherwise. 1807 """ 1808 return self.__start <= address < self.__end
1809
1810 #============================================================================== 1811 1812 -class _BufferWatchCondition (object):
1813 """ 1814 Used by L{Debug.watch_buffer}. 1815 1816 This class acts as a condition callback for page breakpoints. 1817 It emulates page breakpoints that can overlap and/or take up less 1818 than a page's size. 1819 """ 1820
1821 - def __init__(self):
1822 self.__ranges = list() # list of BufferWatch in definition order
1823
1824 - def add(self, bw):
1825 """ 1826 Adds a buffer watch identifier. 1827 1828 @type bw: L{BufferWatch} 1829 @param bw: 1830 Buffer watch identifier. 1831 """ 1832 self.__ranges.append(bw)
1833
1834 - def remove(self, bw):
1835 """ 1836 Removes a buffer watch identifier. 1837 1838 @type bw: L{BufferWatch} 1839 @param bw: 1840 Buffer watch identifier. 1841 1842 @raise KeyError: The buffer watch identifier was already removed. 1843 """ 1844 try: 1845 self.__ranges.remove(bw) 1846 except KeyError: 1847 if not bw.oneshot: 1848 raise
1849
1850 - def remove_last_match(self, address, size):
1851 """ 1852 Removes the last buffer from the watch object 1853 to match the given address and size. 1854 1855 @type address: int 1856 @param address: Memory address of buffer to stop watching. 1857 1858 @type size: int 1859 @param size: Size in bytes of buffer to stop watching. 1860 1861 @rtype: int 1862 @return: Number of matching elements found. Only the last one to be 1863 added is actually deleted upon calling this method. 1864 1865 This counter allows you to know if there are more matching elements 1866 and how many. 1867 """ 1868 count = 0 1869 start = address 1870 end = address + size - 1 1871 matched = None 1872 for item in self.__ranges: 1873 if item.match(start) and item.match(end): 1874 matched = item 1875 count += 1 1876 self.__ranges.remove(matched) 1877 return count
1878
1879 - def count(self):
1880 """ 1881 @rtype: int 1882 @return: Number of buffers being watched. 1883 """ 1884 return len(self.__ranges)
1885
1886 - def __call__(self, event):
1887 """ 1888 Breakpoint condition callback. 1889 1890 This method will also call the action callbacks for each 1891 buffer being watched. 1892 1893 @type event: L{ExceptionEvent} 1894 @param event: Guard page exception event. 1895 1896 @rtype: bool 1897 @return: C{True} if the address being accessed belongs 1898 to at least one of the buffers that was being watched 1899 and had no action callback. 1900 """ 1901 address = event.get_exception_information(1) 1902 bCondition = False 1903 for bw in self.__ranges: 1904 bMatched = bw.match(address) 1905 try: 1906 action = bw.action 1907 if bMatched and action is not None: 1908 try: 1909 action(event) 1910 except Exception, e: 1911 msg = ("Breakpoint action callback %r" 1912 " raised an exception: %s") 1913 msg = msg % (action, traceback.format_exc(e)) 1914 warnings.warn(msg, BreakpointCallbackWarning) 1915 else: 1916 bCondition = bCondition or bMatched 1917 finally: 1918 if bMatched and bw.oneshot: 1919 event.debug.dont_watch_buffer(bw) 1920 return bCondition
1921
1922 #============================================================================== 1923 1924 -class _BreakpointContainer (object):
1925 """ 1926 Encapsulates the capability to contain Breakpoint objects. 1927 1928 @group Breakpoints: 1929 break_at, watch_variable, watch_buffer, hook_function, 1930 dont_break_at, dont_watch_variable, dont_watch_buffer, 1931 dont_hook_function, unhook_function, 1932 break_on_error, dont_break_on_error 1933 1934 @group Stalking: 1935 stalk_at, stalk_variable, stalk_buffer, stalk_function, 1936 dont_stalk_at, dont_stalk_variable, dont_stalk_buffer, 1937 dont_stalk_function 1938 1939 @group Tracing: 1940 is_tracing, get_traced_tids, 1941 start_tracing, stop_tracing, 1942 start_tracing_process, stop_tracing_process, 1943 start_tracing_all, stop_tracing_all 1944 1945 @group Symbols: 1946 resolve_label, resolve_exported_function 1947 1948 @group Advanced breakpoint use: 1949 define_code_breakpoint, 1950 define_page_breakpoint, 1951 define_hardware_breakpoint, 1952 has_code_breakpoint, 1953 has_page_breakpoint, 1954 has_hardware_breakpoint, 1955 get_code_breakpoint, 1956 get_page_breakpoint, 1957 get_hardware_breakpoint, 1958 erase_code_breakpoint, 1959 erase_page_breakpoint, 1960 erase_hardware_breakpoint, 1961 enable_code_breakpoint, 1962 enable_page_breakpoint, 1963 enable_hardware_breakpoint, 1964 enable_one_shot_code_breakpoint, 1965 enable_one_shot_page_breakpoint, 1966 enable_one_shot_hardware_breakpoint, 1967 disable_code_breakpoint, 1968 disable_page_breakpoint, 1969 disable_hardware_breakpoint 1970 1971 @group Listing breakpoints: 1972 get_all_breakpoints, 1973 get_all_code_breakpoints, 1974 get_all_page_breakpoints, 1975 get_all_hardware_breakpoints, 1976 get_process_breakpoints, 1977 get_process_code_breakpoints, 1978 get_process_page_breakpoints, 1979 get_process_hardware_breakpoints, 1980 get_thread_hardware_breakpoints, 1981 get_all_deferred_code_breakpoints, 1982 get_process_deferred_code_breakpoints 1983 1984 @group Batch operations on breakpoints: 1985 enable_all_breakpoints, 1986 enable_one_shot_all_breakpoints, 1987 disable_all_breakpoints, 1988 erase_all_breakpoints, 1989 enable_process_breakpoints, 1990 enable_one_shot_process_breakpoints, 1991 disable_process_breakpoints, 1992 erase_process_breakpoints 1993 1994 @group Breakpoint types: 1995 BP_TYPE_ANY, BP_TYPE_CODE, BP_TYPE_PAGE, BP_TYPE_HARDWARE 1996 @group Breakpoint states: 1997 BP_STATE_DISABLED, BP_STATE_ENABLED, BP_STATE_ONESHOT, BP_STATE_RUNNING 1998 @group Memory breakpoint trigger flags: 1999 BP_BREAK_ON_EXECUTION, BP_BREAK_ON_WRITE, BP_BREAK_ON_ACCESS 2000 @group Memory breakpoint size flags: 2001 BP_WATCH_BYTE, BP_WATCH_WORD, BP_WATCH_DWORD, BP_WATCH_QWORD 2002 2003 @type BP_TYPE_ANY: int 2004 @cvar BP_TYPE_ANY: To get all breakpoints 2005 @type BP_TYPE_CODE: int 2006 @cvar BP_TYPE_CODE: To get code breakpoints only 2007 @type BP_TYPE_PAGE: int 2008 @cvar BP_TYPE_PAGE: To get page breakpoints only 2009 @type BP_TYPE_HARDWARE: int 2010 @cvar BP_TYPE_HARDWARE: To get hardware breakpoints only 2011 2012 @type BP_STATE_DISABLED: int 2013 @cvar BP_STATE_DISABLED: Breakpoint is disabled. 2014 @type BP_STATE_ENABLED: int 2015 @cvar BP_STATE_ENABLED: Breakpoint is enabled. 2016 @type BP_STATE_ONESHOT: int 2017 @cvar BP_STATE_ONESHOT: Breakpoint is enabled for one shot. 2018 @type BP_STATE_RUNNING: int 2019 @cvar BP_STATE_RUNNING: Breakpoint is running (recently hit). 2020 2021 @type BP_BREAK_ON_EXECUTION: int 2022 @cvar BP_BREAK_ON_EXECUTION: Break on code execution. 2023 @type BP_BREAK_ON_WRITE: int 2024 @cvar BP_BREAK_ON_WRITE: Break on memory write. 2025 @type BP_BREAK_ON_ACCESS: int 2026 @cvar BP_BREAK_ON_ACCESS: Break on memory read or write. 2027 """ 2028 2029 # Breakpoint types 2030 BP_TYPE_ANY = 0 # to get all breakpoints 2031 BP_TYPE_CODE = 1 2032 BP_TYPE_PAGE = 2 2033 BP_TYPE_HARDWARE = 3 2034 2035 # Breakpoint states 2036 BP_STATE_DISABLED = Breakpoint.DISABLED 2037 BP_STATE_ENABLED = Breakpoint.ENABLED 2038 BP_STATE_ONESHOT = Breakpoint.ONESHOT 2039 BP_STATE_RUNNING = Breakpoint.RUNNING 2040 2041 # Memory breakpoint trigger flags 2042 BP_BREAK_ON_EXECUTION = HardwareBreakpoint.BREAK_ON_EXECUTION 2043 BP_BREAK_ON_WRITE = HardwareBreakpoint.BREAK_ON_WRITE 2044 BP_BREAK_ON_ACCESS = HardwareBreakpoint.BREAK_ON_ACCESS 2045 2046 # Memory breakpoint size flags 2047 BP_WATCH_BYTE = HardwareBreakpoint.WATCH_BYTE 2048 BP_WATCH_WORD = HardwareBreakpoint.WATCH_WORD 2049 BP_WATCH_QWORD = HardwareBreakpoint.WATCH_QWORD 2050 BP_WATCH_DWORD = HardwareBreakpoint.WATCH_DWORD 2051
2052 - def __init__(self):
2053 self.__codeBP = dict() # (pid, address) -> CodeBreakpoint 2054 self.__pageBP = dict() # (pid, address) -> PageBreakpoint 2055 self.__hardwareBP = dict() # tid -> [ HardwareBreakpoint ] 2056 self.__runningBP = dict() # tid -> set( Breakpoint ) 2057 self.__tracing = set() # set( tid ) 2058 self.__deferredBP = dict() # pid -> label -> (action, oneshot)
2059 2060 #------------------------------------------------------------------------------ 2061 2062 # This operates on the dictionary of running breakpoints. 2063 # Since the bps are meant to stay alive no cleanup is done here. 2064
2065 - def __get_running_bp_set(self, tid):
2066 "Auxiliary method." 2067 return self.__runningBP.get(tid, ())
2068
2069 - def __add_running_bp(self, tid, bp):
2070 "Auxiliary method." 2071 if tid not in self.__runningBP: 2072 self.__runningBP[tid] = set() 2073 self.__runningBP[tid].add(bp)
2074
2075 - def __del_running_bp(self, tid, bp):
2076 "Auxiliary method." 2077 self.__runningBP[tid].remove(bp) 2078 if not self.__runningBP[tid]: 2079 del self.__runningBP[tid]
2080
2082 "Auxiliary method." 2083 for (tid, bpset) in self.__runningBP.iteritems(): 2084 if bp in bpset: 2085 bpset.remove(bp) 2086 self.system.get_thread(tid).clear_tf()
2087 2088 #------------------------------------------------------------------------------ 2089 2090 # This is the cleanup code. Mostly called on response to exit/unload debug 2091 # events. If possible it shouldn't raise exceptions on runtime errors. 2092 # The main goal here is to avoid memory or handle leaks. 2093
2094 - def __cleanup_breakpoint(self, event, bp):
2095 "Auxiliary method." 2096 try: 2097 process = event.get_process() 2098 thread = event.get_thread() 2099 bp.disable(process, thread) # clear the debug regs / trap flag 2100 except Exception: 2101 pass 2102 bp.set_condition(True) # break possible circular reference 2103 bp.set_action(None) # break possible circular reference
2104
2105 - def __cleanup_thread(self, event):
2106 """ 2107 Auxiliary method for L{_notify_exit_thread} 2108 and L{_notify_exit_process}. 2109 """ 2110 tid = event.get_tid() 2111 2112 # Cleanup running breakpoints 2113 try: 2114 for bp in self.__runningBP[tid]: 2115 self.__cleanup_breakpoint(event, bp) 2116 del self.__runningBP[tid] 2117 except KeyError: 2118 pass 2119 2120 # Cleanup hardware breakpoints 2121 try: 2122 for bp in self.__hardwareBP[tid]: 2123 self.__cleanup_breakpoint(event, bp) 2124 del self.__hardwareBP[tid] 2125 except KeyError: 2126 pass 2127 2128 # Cleanup set of threads being traced 2129 if tid in self.__tracing: 2130 self.__tracing.remove(tid)
2131
2132 - def __cleanup_process(self, event):
2133 """ 2134 Auxiliary method for L{_notify_exit_process}. 2135 """ 2136 pid = event.get_pid() 2137 process = event.get_process() 2138 2139 # Cleanup code breakpoints 2140 for (bp_pid, bp_address) in self.__codeBP.keys(): 2141 if bp_pid == pid: 2142 bp = self.__codeBP[ (bp_pid, bp_address) ] 2143 self.__cleanup_breakpoint(event, bp) 2144 del self.__codeBP[ (bp_pid, bp_address) ] 2145 2146 # Cleanup page breakpoints 2147 for (bp_pid, bp_address) in self.__pageBP.keys(): 2148 if bp_pid == pid: 2149 bp = self.__pageBP[ (bp_pid, bp_address) ] 2150 self.__cleanup_breakpoint(event, bp) 2151 del self.__pageBP[ (bp_pid, bp_address) ] 2152 2153 # Cleanup deferred code breakpoints 2154 try: 2155 del self.__deferredBP[pid] 2156 except KeyError: 2157 pass
2158
2159 - def __cleanup_module(self, event):
2160 """ 2161 Auxiliary method for L{_notify_unload_dll}. 2162 """ 2163 pid = event.get_pid() 2164 process = event.get_process() 2165 module = event.get_module() 2166 2167 # Cleanup thread breakpoints on this module 2168 for tid in process.iter_thread_ids(): 2169 thread = process.get_thread(tid) 2170 2171 # Running breakpoints 2172 if tid in self.__runningBP: 2173 bplist = list(self.__runningBP[tid]) 2174 for bp in bplist: 2175 bp_address = bp.get_address() 2176 if process.get_module_at_address(bp_address) == module: 2177 self.__cleanup_breakpoint(event, bp) 2178 self.__runningBP[tid].remove(bp) 2179 2180 # Hardware breakpoints 2181 if tid in self.__hardwareBP: 2182 bplist = list(self.__hardwareBP[tid]) 2183 for bp in bplist: 2184 bp_address = bp.get_address() 2185 if process.get_module_at_address(bp_address) == module: 2186 self.__cleanup_breakpoint(event, bp) 2187 self.__hardwareBP[tid].remove(bp) 2188 2189 # Cleanup code breakpoints on this module 2190 for (bp_pid, bp_address) in self.__codeBP.keys(): 2191 if bp_pid == pid: 2192 if process.get_module_at_address(bp_address) == module: 2193 bp = self.__codeBP[ (bp_pid, bp_address) ] 2194 self.__cleanup_breakpoint(event, bp) 2195 del self.__codeBP[ (bp_pid, bp_address) ] 2196 2197 # Cleanup page breakpoints on this module 2198 for (bp_pid, bp_address) in self.__pageBP.keys(): 2199 if bp_pid == pid: 2200 if process.get_module_at_address(bp_address) == module: 2201 bp = self.__pageBP[ (bp_pid, bp_address) ] 2202 self.__cleanup_breakpoint(event, bp) 2203 del self.__pageBP[ (bp_pid, bp_address) ]
2204 2205 #------------------------------------------------------------------------------ 2206 2207 # Defining breakpoints. 2208 2209 # Code breakpoints.
2210 - def define_code_breakpoint(self, dwProcessId, address, condition = True, 2211 action = None):
2212 """ 2213 Creates a disabled code breakpoint at the given address. 2214 2215 @see: 2216 L{has_code_breakpoint}, 2217 L{get_code_breakpoint}, 2218 L{enable_code_breakpoint}, 2219 L{enable_one_shot_code_breakpoint}, 2220 L{disable_code_breakpoint}, 2221 L{erase_code_breakpoint} 2222 2223 @type dwProcessId: int 2224 @param dwProcessId: Process global ID. 2225 2226 @type address: int 2227 @param address: Memory address of the code instruction to break at. 2228 2229 @type condition: function 2230 @param condition: (Optional) Condition callback function. 2231 2232 The callback signature is:: 2233 2234 def condition_callback(event): 2235 return True # returns True or False 2236 2237 Where B{event} is an L{Event} object, 2238 and the return value is a boolean 2239 (C{True} to dispatch the event, C{False} otherwise). 2240 2241 @type action: function 2242 @param action: (Optional) Action callback function. 2243 If specified, the event is handled by this callback instead of 2244 being dispatched normally. 2245 2246 The callback signature is:: 2247 2248 def action_callback(event): 2249 pass # no return value 2250 2251 Where B{event} is an L{Event} object, 2252 and the return value is a boolean 2253 (C{True} to dispatch the event, C{False} otherwise). 2254 2255 @rtype: L{CodeBreakpoint} 2256 @return: The code breakpoint object. 2257 """ 2258 process = self.system.get_process(dwProcessId) 2259 bp = CodeBreakpoint(address, condition, action) 2260 2261 key = (dwProcessId, bp.get_address()) 2262 if key in self.__codeBP: 2263 msg = "Already exists (PID %d) : %r" 2264 raise KeyError(msg % (dwProcessId, self.__codeBP[key])) 2265 self.__codeBP[key] = bp 2266 return bp
2267 2268 # Page breakpoints.
2269 - def define_page_breakpoint(self, dwProcessId, address, pages = 1, 2270 condition = True, 2271 action = None):
2272 """ 2273 Creates a disabled page breakpoint at the given address. 2274 2275 @see: 2276 L{has_page_breakpoint}, 2277 L{get_page_breakpoint}, 2278 L{enable_page_breakpoint}, 2279 L{enable_one_shot_page_breakpoint}, 2280 L{disable_page_breakpoint}, 2281 L{erase_page_breakpoint} 2282 2283 @type dwProcessId: int 2284 @param dwProcessId: Process global ID. 2285 2286 @type address: int 2287 @param address: Memory address of the first page to watch. 2288 2289 @type pages: int 2290 @param pages: Number of pages to watch. 2291 2292 @type condition: function 2293 @param condition: (Optional) Condition callback function. 2294 2295 The callback signature is:: 2296 2297 def condition_callback(event): 2298 return True # returns True or False 2299 2300 Where B{event} is an L{Event} object, 2301 and the return value is a boolean 2302 (C{True} to dispatch the event, C{False} otherwise). 2303 2304 @type action: function 2305 @param action: (Optional) Action callback function. 2306 If specified, the event is handled by this callback instead of 2307 being dispatched normally. 2308 2309 The callback signature is:: 2310 2311 def action_callback(event): 2312 pass # no return value 2313 2314 Where B{event} is an L{Event} object, 2315 and the return value is a boolean 2316 (C{True} to dispatch the event, C{False} otherwise). 2317 2318 @rtype: L{PageBreakpoint} 2319 @return: The page breakpoint object. 2320 """ 2321 process = self.system.get_process(dwProcessId) 2322 bp = PageBreakpoint(address, pages, condition, action) 2323 begin = bp.get_address() 2324 end = begin + bp.get_size() 2325 2326 address = begin 2327 pageSize = MemoryAddresses.pageSize 2328 while address < end: 2329 key = (dwProcessId, address) 2330 if key in self.__pageBP: 2331 msg = "Already exists (PID %d) : %r" 2332 msg = msg % (dwProcessId, self.__pageBP[key]) 2333 raise KeyError(msg) 2334 address = address + pageSize 2335 2336 address = begin 2337 while address < end: 2338 key = (dwProcessId, address) 2339 self.__pageBP[key] = bp 2340 address = address + pageSize 2341 return bp
2342 2343 # Hardware breakpoints.
2344 - def define_hardware_breakpoint(self, dwThreadId, address, 2345 triggerFlag = BP_BREAK_ON_ACCESS, 2346 sizeFlag = BP_WATCH_DWORD, 2347 condition = True, 2348 action = None):
2349 """ 2350 Creates a disabled hardware breakpoint at the given address. 2351 2352 @see: 2353 L{has_hardware_breakpoint}, 2354 L{get_hardware_breakpoint}, 2355 L{enable_hardware_breakpoint}, 2356 L{enable_one_shot_hardware_breakpoint}, 2357 L{disable_hardware_breakpoint}, 2358 L{erase_hardware_breakpoint} 2359 2360 @note: 2361 Hardware breakpoints do not seem to work properly on VirtualBox. 2362 See U{http://www.virtualbox.org/ticket/477}. 2363 2364 @type dwThreadId: int 2365 @param dwThreadId: Thread global ID. 2366 2367 @type address: int 2368 @param address: Memory address to watch. 2369 2370 @type triggerFlag: int 2371 @param triggerFlag: Trigger of breakpoint. Must be one of the following: 2372 2373 - L{BP_BREAK_ON_EXECUTION} 2374 2375 Break on code execution. 2376 2377 - L{BP_BREAK_ON_WRITE} 2378 2379 Break on memory read or write. 2380 2381 - L{BP_BREAK_ON_ACCESS} 2382 2383 Break on memory write. 2384 2385 @type sizeFlag: int 2386 @param sizeFlag: Size of breakpoint. Must be one of the following: 2387 2388 - L{BP_WATCH_BYTE} 2389 2390 One (1) byte in size. 2391 2392 - L{BP_WATCH_WORD} 2393 2394 Two (2) bytes in size. 2395 2396 - L{BP_WATCH_DWORD} 2397 2398 Four (4) bytes in size. 2399 2400 - L{BP_WATCH_QWORD} 2401 2402 Eight (8) bytes in size. 2403 2404 @type condition: function 2405 @param condition: (Optional) Condition callback function. 2406 2407 The callback signature is:: 2408 2409 def condition_callback(event): 2410 return True # returns True or False 2411 2412 Where B{event} is an L{Event} object, 2413 and the return value is a boolean 2414 (C{True} to dispatch the event, C{False} otherwise). 2415 2416 @type action: function 2417 @param action: (Optional) Action callback function. 2418 If specified, the event is handled by this callback instead of 2419 being dispatched normally. 2420 2421 The callback signature is:: 2422 2423 def action_callback(event): 2424 pass # no return value 2425 2426 Where B{event} is an L{Event} object, 2427 and the return value is a boolean 2428 (C{True} to dispatch the event, C{False} otherwise). 2429 2430 @rtype: L{HardwareBreakpoint} 2431 @return: The hardware breakpoint object. 2432 """ 2433 thread = self.system.get_thread(dwThreadId) 2434 bp = HardwareBreakpoint(address, triggerFlag, sizeFlag, condition, 2435 action) 2436 begin = bp.get_address() 2437 end = begin + bp.get_size() 2438 2439 if dwThreadId in self.__hardwareBP: 2440 bpSet = self.__hardwareBP[dwThreadId] 2441 for oldbp in bpSet: 2442 old_begin = oldbp.get_address() 2443 old_end = old_begin + oldbp.get_size() 2444 if MemoryAddresses.do_ranges_intersect(begin, end, old_begin, 2445 old_end): 2446 msg = "Already exists (TID %d) : %r" % (dwThreadId, oldbp) 2447 raise KeyError(msg) 2448 else: 2449 bpSet = set() 2450 self.__hardwareBP[dwThreadId] = bpSet 2451 bpSet.add(bp) 2452 return bp
2453 2454 #------------------------------------------------------------------------------ 2455 2456 # Checking breakpoint definitions. 2457
2458 - def has_code_breakpoint(self, dwProcessId, address):
2459 """ 2460 Checks if a code breakpoint is defined at the given address. 2461 2462 @see: 2463 L{define_code_breakpoint}, 2464 L{get_code_breakpoint}, 2465 L{erase_code_breakpoint}, 2466 L{enable_code_breakpoint}, 2467 L{enable_one_shot_code_breakpoint}, 2468 L{disable_code_breakpoint} 2469 2470 @type dwProcessId: int 2471 @param dwProcessId: Process global ID. 2472 2473 @type address: int 2474 @param address: Memory address of breakpoint. 2475 2476 @rtype: bool 2477 @return: C{True} if the breakpoint is defined, C{False} otherwise. 2478 """ 2479 return (dwProcessId, address) in self.__codeBP
2480
2481 - def has_page_breakpoint(self, dwProcessId, address):
2482 """ 2483 Checks if a page breakpoint is defined at the given address. 2484 2485 @see: 2486 L{define_page_breakpoint}, 2487 L{get_page_breakpoint}, 2488 L{erase_page_breakpoint}, 2489 L{enable_page_breakpoint}, 2490 L{enable_one_shot_page_breakpoint}, 2491 L{disable_page_breakpoint} 2492 2493 @type dwProcessId: int 2494 @param dwProcessId: Process global ID. 2495 2496 @type address: int 2497 @param address: Memory address of breakpoint. 2498 2499 @rtype: bool 2500 @return: C{True} if the breakpoint is defined, C{False} otherwise. 2501 """ 2502 return (dwProcessId, address) in self.__pageBP
2503
2504 - def has_hardware_breakpoint(self, dwThreadId, address):
2505 """ 2506 Checks if a hardware breakpoint is defined at the given address. 2507 2508 @see: 2509 L{define_hardware_breakpoint}, 2510 L{get_hardware_breakpoint}, 2511 L{erase_hardware_breakpoint}, 2512 L{enable_hardware_breakpoint}, 2513 L{enable_one_shot_hardware_breakpoint}, 2514 L{disable_hardware_breakpoint} 2515 2516 @type dwThreadId: int 2517 @param dwThreadId: Thread global ID. 2518 2519 @type address: int 2520 @param address: Memory address of breakpoint. 2521 2522 @rtype: bool 2523 @return: C{True} if the breakpoint is defined, C{False} otherwise. 2524 """ 2525 if dwThreadId in self.__hardwareBP: 2526 bpSet = self.__hardwareBP[dwThreadId] 2527 for bp in bpSet: 2528 if bp.get_address() == address: 2529 return True 2530 return False
2531 2532 #------------------------------------------------------------------------------ 2533 2534 # Getting breakpoints. 2535
2536 - def get_code_breakpoint(self, dwProcessId, address):
2537 """ 2538 Returns the internally used breakpoint object, 2539 for the code breakpoint defined at the given address. 2540 2541 @warning: It's usually best to call the L{Debug} methods 2542 instead of accessing the breakpoint objects directly. 2543 2544 @see: 2545 L{define_code_breakpoint}, 2546 L{has_code_breakpoint}, 2547 L{enable_code_breakpoint}, 2548 L{enable_one_shot_code_breakpoint}, 2549 L{disable_code_breakpoint}, 2550 L{erase_code_breakpoint} 2551 2552 @type dwProcessId: int 2553 @param dwProcessId: Process global ID. 2554 2555 @type address: int 2556 @param address: Memory address where the breakpoint is defined. 2557 2558 @rtype: L{CodeBreakpoint} 2559 @return: The code breakpoint object. 2560 """ 2561 key = (dwProcessId, address) 2562 if key not in self.__codeBP: 2563 msg = "No breakpoint at process %d, address %s" 2564 address = HexDump.address(address) 2565 raise KeyError(msg % (dwProcessId, address)) 2566 return self.__codeBP[key]
2567
2568 - def get_page_breakpoint(self, dwProcessId, address):
2569 """ 2570 Returns the internally used breakpoint object, 2571 for the page breakpoint defined at the given address. 2572 2573 @warning: It's usually best to call the L{Debug} methods 2574 instead of accessing the breakpoint objects directly. 2575 2576 @see: 2577 L{define_page_breakpoint}, 2578 L{has_page_breakpoint}, 2579 L{enable_page_breakpoint}, 2580 L{enable_one_shot_page_breakpoint}, 2581 L{disable_page_breakpoint}, 2582 L{erase_page_breakpoint} 2583 2584 @type dwProcessId: int 2585 @param dwProcessId: Process global ID. 2586 2587 @type address: int 2588 @param address: Memory address where the breakpoint is defined. 2589 2590 @rtype: L{PageBreakpoint} 2591 @return: The page breakpoint object. 2592 """ 2593 key = (dwProcessId, address) 2594 if key not in self.__pageBP: 2595 msg = "No breakpoint at process %d, address %s" 2596 address = HexDump.addresS(address) 2597 raise KeyError(msg % (dwProcessId, address)) 2598 return self.__pageBP[key]
2599
2600 - def get_hardware_breakpoint(self, dwThreadId, address):
2601 """ 2602 Returns the internally used breakpoint object, 2603 for the code breakpoint defined at the given address. 2604 2605 @warning: It's usually best to call the L{Debug} methods 2606 instead of accessing the breakpoint objects directly. 2607 2608 @see: 2609 L{define_hardware_breakpoint}, 2610 L{has_hardware_breakpoint}, 2611 L{get_code_breakpoint}, 2612 L{enable_hardware_breakpoint}, 2613 L{enable_one_shot_hardware_breakpoint}, 2614 L{disable_hardware_breakpoint}, 2615 L{erase_hardware_breakpoint} 2616 2617 @type dwThreadId: int 2618 @param dwThreadId: Thread global ID. 2619 2620 @type address: int 2621 @param address: Memory address where the breakpoint is defined. 2622 2623 @rtype: L{HardwareBreakpoint} 2624 @return: The hardware breakpoint object. 2625 """ 2626 if dwThreadId not in self.__hardwareBP: 2627 msg = "No hardware breakpoints set for thread %d" 2628 raise KeyError(msg % dwThreadId) 2629 for bp in self.__hardwareBP[dwThreadId]: 2630 if bp.is_here(address): 2631 return bp 2632 msg = "No hardware breakpoint at thread %d, address %s" 2633 raise KeyError(msg % (dwThreadId, HexDump.address(address)))
2634 2635 #------------------------------------------------------------------------------ 2636 2637 # Enabling and disabling breakpoints. 2638
2639 - def enable_code_breakpoint(self, dwProcessId, address):
2640 """ 2641 Enables the code breakpoint at the given address. 2642 2643 @see: 2644 L{define_code_breakpoint}, 2645 L{has_code_breakpoint}, 2646 L{enable_one_shot_code_breakpoint}, 2647 L{disable_code_breakpoint} 2648 L{erase_code_breakpoint}, 2649 2650 @type dwProcessId: int 2651 @param dwProcessId: Process global ID. 2652 2653 @type address: int 2654 @param address: Memory address of breakpoint. 2655 """ 2656 p = self.system.get_process(dwProcessId) 2657 bp = self.get_code_breakpoint(dwProcessId, address) 2658 if bp.is_running(): 2659 self.__del_running_bp_from_all_threads(bp) 2660 bp.enable(p, None) # XXX HACK thread is not used
2661
2662 - def enable_page_breakpoint(self, dwProcessId, address):
2663 """ 2664 Enables the page breakpoint at the given address. 2665 2666 @see: 2667 L{define_page_breakpoint}, 2668 L{has_page_breakpoint}, 2669 L{get_page_breakpoint}, 2670 L{enable_one_shot_page_breakpoint}, 2671 L{disable_page_breakpoint} 2672 L{erase_page_breakpoint}, 2673 2674 @type dwProcessId: int 2675 @param dwProcessId: Process global ID. 2676 2677 @type address: int 2678 @param address: Memory address of breakpoint. 2679 """ 2680 p = self.system.get_process(dwProcessId) 2681 bp = self.get_page_breakpoint(dwProcessId, address) 2682 if bp.is_running(): 2683 self.__del_running_bp_from_all_threads(bp) 2684 bp.enable(p, None) # XXX HACK thread is not used
2685
2686 - def enable_hardware_breakpoint(self, dwThreadId, address):
2687 """ 2688 Enables the hardware breakpoint at the given address. 2689 2690 @see: 2691 L{define_hardware_breakpoint}, 2692 L{has_hardware_breakpoint}, 2693 L{get_hardware_breakpoint}, 2694 L{enable_one_shot_hardware_breakpoint}, 2695 L{disable_hardware_breakpoint} 2696 L{erase_hardware_breakpoint}, 2697 2698 @note: Do not set hardware breakpoints while processing the system 2699 breakpoint event. 2700 2701 @type dwThreadId: int 2702 @param dwThreadId: Thread global ID. 2703 2704 @type address: int 2705 @param address: Memory address of breakpoint. 2706 """ 2707 t = self.system.get_thread(dwThreadId) 2708 bp = self.get_hardware_breakpoint(dwThreadId, address) 2709 if bp.is_running(): 2710 self.__del_running_bp_from_all_threads(bp) 2711 bp.enable(None, t) # XXX HACK process is not used
2712
2713 - def enable_one_shot_code_breakpoint(self, dwProcessId, address):
2714 """ 2715 Enables the code breakpoint at the given address for only one shot. 2716 2717 @see: 2718 L{define_code_breakpoint}, 2719 L{has_code_breakpoint}, 2720 L{get_code_breakpoint}, 2721 L{enable_code_breakpoint}, 2722 L{disable_code_breakpoint} 2723 L{erase_code_breakpoint}, 2724 2725 @type dwProcessId: int 2726 @param dwProcessId: Process global ID. 2727 2728 @type address: int 2729 @param address: Memory address of breakpoint. 2730 """ 2731 p = self.system.get_process(dwProcessId) 2732 bp = self.get_code_breakpoint(dwProcessId, address) 2733 if bp.is_running(): 2734 self.__del_running_bp_from_all_threads(bp) 2735 bp.one_shot(p, None) # XXX HACK thread is not used
2736
2737 - def enable_one_shot_page_breakpoint(self, dwProcessId, address):
2738 """ 2739 Enables the page breakpoint at the given address for only one shot. 2740 2741 @see: 2742 L{define_page_breakpoint}, 2743 L{has_page_breakpoint}, 2744 L{get_page_breakpoint}, 2745 L{enable_page_breakpoint}, 2746 L{disable_page_breakpoint} 2747 L{erase_page_breakpoint}, 2748 2749 @type dwProcessId: int 2750 @param dwProcessId: Process global ID. 2751 2752 @type address: int 2753 @param address: Memory address of breakpoint. 2754 """ 2755 p = self.system.get_process(dwProcessId) 2756 bp = self.get_page_breakpoint(dwProcessId, address) 2757 if bp.is_running(): 2758 self.__del_running_bp_from_all_threads(bp) 2759 bp.one_shot(p, None) # XXX HACK thread is not used
2760
2761 - def enable_one_shot_hardware_breakpoint(self, dwThreadId, address):
2762 """ 2763 Enables the hardware breakpoint at the given address for only one shot. 2764 2765 @see: 2766 L{define_hardware_breakpoint}, 2767 L{has_hardware_breakpoint}, 2768 L{get_hardware_breakpoint}, 2769 L{enable_hardware_breakpoint}, 2770 L{disable_hardware_breakpoint} 2771 L{erase_hardware_breakpoint}, 2772 2773 @type dwThreadId: int 2774 @param dwThreadId: Thread global ID. 2775 2776 @type address: int 2777 @param address: Memory address of breakpoint. 2778 """ 2779 t = self.system.get_thread(dwThreadId) 2780 bp = self.get_hardware_breakpoint(dwThreadId, address) 2781 if bp.is_running(): 2782 self.__del_running_bp_from_all_threads(bp) 2783 bp.one_shot(None, t) # XXX HACK process is not used
2784
2785 - def disable_code_breakpoint(self, dwProcessId, address):
2786 """ 2787 Disables the code breakpoint at the given address. 2788 2789 @see: 2790 L{define_code_breakpoint}, 2791 L{has_code_breakpoint}, 2792 L{get_code_breakpoint}, 2793 L{enable_code_breakpoint} 2794 L{enable_one_shot_code_breakpoint}, 2795 L{erase_code_breakpoint}, 2796 2797 @type dwProcessId: int 2798 @param dwProcessId: Process global ID. 2799 2800 @type address: int 2801 @param address: Memory address of breakpoint. 2802 """ 2803 p = self.system.get_process(dwProcessId) 2804 bp = self.get_code_breakpoint(dwProcessId, address) 2805 if bp.is_running(): 2806 self.__del_running_bp_from_all_threads(bp) 2807 bp.disable(p, None) # XXX HACK thread is not used
2808
2809 - def disable_page_breakpoint(self, dwProcessId, address):
2810 """ 2811 Disables the page breakpoint at the given address. 2812 2813 @see: 2814 L{define_page_breakpoint}, 2815 L{has_page_breakpoint}, 2816 L{get_page_breakpoint}, 2817 L{enable_page_breakpoint} 2818 L{enable_one_shot_page_breakpoint}, 2819 L{erase_page_breakpoint}, 2820 2821 @type dwProcessId: int 2822 @param dwProcessId: Process global ID. 2823 2824 @type address: int 2825 @param address: Memory address of breakpoint. 2826 """ 2827 p = self.system.get_process(dwProcessId) 2828 bp = self.get_page_breakpoint(dwProcessId, address) 2829 if bp.is_running(): 2830 self.__del_running_bp_from_all_threads(bp) 2831 bp.disable(p, None) # XXX HACK thread is not used
2832
2833 - def disable_hardware_breakpoint(self, dwThreadId, address):
2834 """ 2835 Disables the hardware breakpoint at the given address. 2836 2837 @see: 2838 L{define_hardware_breakpoint}, 2839 L{has_hardware_breakpoint}, 2840 L{get_hardware_breakpoint}, 2841 L{enable_hardware_breakpoint} 2842 L{enable_one_shot_hardware_breakpoint}, 2843 L{erase_hardware_breakpoint}, 2844 2845 @type dwThreadId: int 2846 @param dwThreadId: Thread global ID. 2847 2848 @type address: int 2849 @param address: Memory address of breakpoint. 2850 """ 2851 t = self.system.get_thread(dwThreadId) 2852 p = t.get_process() 2853 bp = self.get_hardware_breakpoint(dwThreadId, address) 2854 if bp.is_running(): 2855 self.__del_running_bp(dwThreadId, bp) 2856 bp.disable(p, t)
2857 2858 #------------------------------------------------------------------------------ 2859 2860 # Undefining (erasing) breakpoints. 2861
2862 - def erase_code_breakpoint(self, dwProcessId, address):
2863 """ 2864 Erases the code breakpoint at the given address. 2865 2866 @see: 2867 L{define_code_breakpoint}, 2868 L{has_code_breakpoint}, 2869 L{get_code_breakpoint}, 2870 L{enable_code_breakpoint}, 2871 L{enable_one_shot_code_breakpoint}, 2872 L{disable_code_breakpoint} 2873 2874 @type dwProcessId: int 2875 @param dwProcessId: Process global ID. 2876 2877 @type address: int 2878 @param address: Memory address of breakpoint. 2879 """ 2880 bp = self.get_code_breakpoint(dwProcessId, address) 2881 if not bp.is_disabled(): 2882 self.disable_code_breakpoint(dwProcessId, address) 2883 del self.__codeBP[ (dwProcessId, address) ]
2884
2885 - def erase_page_breakpoint(self, dwProcessId, address):
2886 """ 2887 Erases the page breakpoint at the given address. 2888 2889 @see: 2890 L{define_page_breakpoint}, 2891 L{has_page_breakpoint}, 2892 L{get_page_breakpoint}, 2893 L{enable_page_breakpoint}, 2894 L{enable_one_shot_page_breakpoint}, 2895 L{disable_page_breakpoint} 2896 2897 @type dwProcessId: int 2898 @param dwProcessId: Process global ID. 2899 2900 @type address: int 2901 @param address: Memory address of breakpoint. 2902 """ 2903 bp = self.get_page_breakpoint(dwProcessId, address) 2904 begin = bp.get_address() 2905 end = begin + bp.get_size() 2906 if not bp.is_disabled(): 2907 self.disable_page_breakpoint(dwProcessId, address) 2908 address = begin 2909 pageSize = MemoryAddresses.pageSize 2910 while address < end: 2911 del self.__pageBP[ (dwProcessId, address) ] 2912 address = address + pageSize
2913
2914 - def erase_hardware_breakpoint(self, dwThreadId, address):
2915 """ 2916 Erases the hardware breakpoint at the given address. 2917 2918 @see: 2919 L{define_hardware_breakpoint}, 2920 L{has_hardware_breakpoint}, 2921 L{get_hardware_breakpoint}, 2922 L{enable_hardware_breakpoint}, 2923 L{enable_one_shot_hardware_breakpoint}, 2924 L{disable_hardware_breakpoint} 2925 2926 @type dwThreadId: int 2927 @param dwThreadId: Thread global ID. 2928 2929 @type address: int 2930 @param address: Memory address of breakpoint. 2931 """ 2932 bp = self.get_hardware_breakpoint(dwThreadId, address) 2933 if not bp.is_disabled(): 2934 self.disable_hardware_breakpoint(dwThreadId, address) 2935 bpSet = self.__hardwareBP[dwThreadId] 2936 bpSet.remove(bp) 2937 if not bpSet: 2938 del self.__hardwareBP[dwThreadId]
2939 2940 #------------------------------------------------------------------------------ 2941 2942 # Listing breakpoints. 2943
2944 - def get_all_breakpoints(self):
2945 """ 2946 Returns all breakpoint objects as a list of tuples. 2947 2948 Each tuple contains: 2949 - Process global ID to which the breakpoint applies. 2950 - Thread global ID to which the breakpoint applies, or C{None}. 2951 - The L{Breakpoint} object itself. 2952 2953 @note: If you're only interested in a specific breakpoint type, or in 2954 breakpoints for a specific process or thread, it's probably faster 2955 to call one of the following methods: 2956 - L{get_all_code_breakpoints} 2957 - L{get_all_page_breakpoints} 2958 - L{get_all_hardware_breakpoints} 2959 - L{get_process_code_breakpoints} 2960 - L{get_process_page_breakpoints} 2961 - L{get_process_hardware_breakpoints} 2962 - L{get_thread_hardware_breakpoints} 2963 2964 @rtype: list of tuple( pid, tid, bp ) 2965 @return: List of all breakpoints. 2966 """ 2967 bplist = list() 2968 2969 # Get the code breakpoints. 2970 for (pid, bp) in self.get_all_code_breakpoints(): 2971 bplist.append( (pid, None, bp) ) 2972 2973 # Get the page breakpoints. 2974 for (pid, bp) in self.get_all_page_breakpoints(): 2975 bplist.append( (pid, None, bp) ) 2976 2977 # Get the hardware breakpoints. 2978 for (tid, bp) in self.get_all_hardware_breakpoints(): 2979 pid = self.system.get_thread(tid).get_pid() 2980 bplist.append( (pid, tid, bp) ) 2981 2982 # Return the list of breakpoints. 2983 return bplist
2984
2985 - def get_all_code_breakpoints(self):
2986 """ 2987 @rtype: list of tuple( int, L{CodeBreakpoint} ) 2988 @return: All code breakpoints as a list of tuples (pid, bp). 2989 """ 2990 return [ (pid, bp) for ((pid, address), bp) in self.__codeBP.iteritems() ]
2991
2992 - def get_all_page_breakpoints(self):
2993 """ 2994 @rtype: list of tuple( int, L{PageBreakpoint} ) 2995 @return: All page breakpoints as a list of tuples (pid, bp). 2996 """ 2997 ## return list( set( [ (pid, bp) for ((pid, address), bp) in self.__pageBP.iteritems() ] ) ) 2998 result = set() 2999 for ((pid, address), bp) in self.__pageBP.iteritems(): 3000 result.add( (pid, bp) ) 3001 return list(result)
3002
3004 """ 3005 @rtype: list of tuple( int, L{HardwareBreakpoint} ) 3006 @return: All hardware breakpoints as a list of tuples (tid, bp). 3007 """ 3008 result = list() 3009 for (tid, bplist) in self.__hardwareBP.iteritems(): 3010 for bp in bplist: 3011 result.append( (tid, bp) ) 3012 return result
3013
3014 - def get_process_breakpoints(self, dwProcessId):
3015 """ 3016 Returns all breakpoint objects for the given process as a list of tuples. 3017 3018 Each tuple contains: 3019 - Process global ID to which the breakpoint applies. 3020 - Thread global ID to which the breakpoint applies, or C{None}. 3021 - The L{Breakpoint} object itself. 3022 3023 @note: If you're only interested in a specific breakpoint type, or in 3024 breakpoints for a specific process or thread, it's probably faster 3025 to call one of the following methods: 3026 - L{get_all_code_breakpoints} 3027 - L{get_all_page_breakpoints} 3028 - L{get_all_hardware_breakpoints} 3029 - L{get_process_code_breakpoints} 3030 - L{get_process_page_breakpoints} 3031 - L{get_process_hardware_breakpoints} 3032 - L{get_thread_hardware_breakpoints} 3033 3034 @type dwProcessId: int 3035 @param dwProcessId: Process global ID. 3036 3037 @rtype: list of tuple( pid, tid, bp ) 3038 @return: List of all breakpoints for the given process. 3039 """ 3040 bplist = list() 3041 3042 # Get the code breakpoints. 3043 for bp in self.get_process_code_breakpoints(dwProcessId): 3044 bplist.append( (dwProcessId, None, bp) ) 3045 3046 # Get the page breakpoints. 3047 for bp in self.get_process_page_breakpoints(dwProcessId): 3048 bplist.append( (dwProcessId, None, bp) ) 3049 3050 # Get the hardware breakpoints. 3051 for (tid, bp) in self.get_process_hardware_breakpoints(dwProcessId): 3052 pid = self.system.get_thread(tid).get_pid() 3053 bplist.append( (dwProcessId, tid, bp) ) 3054 3055 # Return the list of breakpoints. 3056 return bplist
3057
3058 - def get_process_code_breakpoints(self, dwProcessId):
3059 """ 3060 @type dwProcessId: int 3061 @param dwProcessId: Process global ID. 3062 3063 @rtype: list of L{CodeBreakpoint} 3064 @return: All code breakpoints for the given process. 3065 """ 3066 return [ bp for ((pid, address), bp) in self.__codeBP.iteritems() \ 3067 if pid == dwProcessId ]
3068
3069 - def get_process_page_breakpoints(self, dwProcessId):
3070 """ 3071 @type dwProcessId: int 3072 @param dwProcessId: Process global ID. 3073 3074 @rtype: list of L{PageBreakpoint} 3075 @return: All page breakpoints for the given process. 3076 """ 3077 return [ bp for ((pid, address), bp) in self.__pageBP.iteritems() \ 3078 if pid == dwProcessId ]
3079
3080 - def get_thread_hardware_breakpoints(self, dwThreadId):
3081 """ 3082 @see: L{get_process_hardware_breakpoints} 3083 3084 @type dwThreadId: int 3085 @param dwThreadId: Thread global ID. 3086 3087 @rtype: list of L{HardwareBreakpoint} 3088 @return: All hardware breakpoints for the given thread. 3089 """ 3090 result = list() 3091 for (tid, bplist) in self.__hardwareBP.iteritems(): 3092 if tid == dwThreadId: 3093 for bp in bplist: 3094 result.append(bp) 3095 return result
3096
3097 - def get_process_hardware_breakpoints(self, dwProcessId):
3098 """ 3099 @see: L{get_thread_hardware_breakpoints} 3100 3101 @type dwProcessId: int 3102 @param dwProcessId: Process global ID. 3103 3104 @rtype: list of tuple( int, L{HardwareBreakpoint} ) 3105 @return: All hardware breakpoints for each thread in the given process 3106 as a list of tuples (tid, bp). 3107 """ 3108 result = list() 3109 aProcess = self.system.get_process(dwProcessId) 3110 for dwThreadId in aProcess.iter_thread_ids(): 3111 if dwThreadId in self.__hardwareBP: 3112 bplist = self.__hardwareBP[dwThreadId] 3113 for bp in bplist: 3114 result.append( (dwThreadId, bp) ) 3115 return result
3116 3117 ## def get_all_hooks(self): 3118 ## """ 3119 ## @see: L{get_process_hooks} 3120 ## 3121 ## @rtype: list of tuple( int, int, L{Hook} ) 3122 ## @return: All defined hooks as a list of tuples (pid, address, hook). 3123 ## """ 3124 ## return [ (pid, address, hook) \ 3125 ## for ((pid, address), hook) in self.__hook_objects ] 3126 ## 3127 ## def get_process_hooks(self, dwProcessId): 3128 ## """ 3129 ## @see: L{get_all_hooks} 3130 ## 3131 ## @type dwProcessId: int 3132 ## @param dwProcessId: Process global ID. 3133 ## 3134 ## @rtype: list of tuple( int, int, L{Hook} ) 3135 ## @return: All hooks for the given process as a list of tuples 3136 ## (pid, address, hook). 3137 ## """ 3138 ## return [ (pid, address, hook) \ 3139 ## for ((pid, address), hook) in self.__hook_objects \ 3140 ## if pid == dwProcessId ] 3141 3142 #------------------------------------------------------------------------------ 3143 3144 # Batch operations on all breakpoints. 3145
3146 - def enable_all_breakpoints(self):
3147 """ 3148 Enables all disabled breakpoints in all processes. 3149 3150 @see: 3151 enable_code_breakpoint, 3152 enable_page_breakpoint, 3153 enable_hardware_breakpoint 3154 """ 3155 3156 # disable code breakpoints 3157 for (pid, bp) in self.get_all_code_breakpoints(): 3158 if bp.is_disabled(): 3159 self.enable_code_breakpoint(pid, bp.get_address()) 3160 3161 # disable page breakpoints 3162 for (pid, bp) in self.get_all_page_breakpoints(): 3163 if bp.is_disabled(): 3164 self.enable_page_breakpoint(pid, bp.get_address()) 3165 3166 # disable hardware breakpoints 3167 for (tid, bp) in self.get_all_hardware_breakpoints(): 3168 if bp.is_disabled(): 3169 self.enable_hardware_breakpoint(tid, bp.get_address())
3170
3172 """ 3173 Enables for one shot all disabled breakpoints in all processes. 3174 3175 @see: 3176 enable_one_shot_code_breakpoint, 3177 enable_one_shot_page_breakpoint, 3178 enable_one_shot_hardware_breakpoint 3179 """ 3180 3181 # disable code breakpoints for one shot 3182 for (pid, bp) in self.get_all_code_breakpoints(): 3183 if bp.is_disabled(): 3184 self.enable_one_shot_code_breakpoint(pid, bp.get_address()) 3185 3186 # disable page breakpoints for one shot 3187 for (pid, bp) in self.get_all_page_breakpoints(): 3188 if bp.is_disabled(): 3189 self.enable_one_shot_page_breakpoint(pid, bp.get_address()) 3190 3191 # disable hardware breakpoints for one shot 3192 for (tid, bp) in self.get_all_hardware_breakpoints(): 3193 if bp.is_disabled(): 3194 self.enable_one_shot_hardware_breakpoint(tid, bp.get_address())
3195
3196 - def disable_all_breakpoints(self):
3197 """ 3198 Disables all breakpoints in all processes. 3199 3200 @see: 3201 disable_code_breakpoint, 3202 disable_page_breakpoint, 3203 disable_hardware_breakpoint 3204 """ 3205 3206 # disable code breakpoints 3207 for (pid, bp) in self.get_all_code_breakpoints(): 3208 self.disable_code_breakpoint(pid, bp.get_address()) 3209 3210 # disable page breakpoints 3211 for (pid, bp) in self.get_all_page_breakpoints(): 3212 self.disable_page_breakpoint(pid, bp.get_address()) 3213 3214 # disable hardware breakpoints 3215 for (tid, bp) in self.get_all_hardware_breakpoints(): 3216 self.disable_hardware_breakpoint(tid, bp.get_address())
3217
3218 - def erase_all_breakpoints(self):
3219 """ 3220 Erases all breakpoints in all processes. 3221 3222 @see: 3223 erase_code_breakpoint, 3224 erase_page_breakpoint, 3225 erase_hardware_breakpoint 3226 """ 3227 3228 # This should be faster but let's not trust the GC so much :P 3229 # self.disable_all_breakpoints() 3230 # self.__codeBP = dict() 3231 # self.__pageBP = dict() 3232 # self.__hardwareBP = dict() 3233 # self.__runningBP = dict() 3234 # self.__hook_objects = dict() 3235 3236 ## # erase hooks 3237 ## for (pid, address, hook) in self.get_all_hooks(): 3238 ## self.dont_hook_function(pid, address) 3239 3240 # erase code breakpoints 3241 for (pid, bp) in self.get_all_code_breakpoints(): 3242 self.erase_code_breakpoint(pid, bp.get_address()) 3243 3244 # erase page breakpoints 3245 for (pid, bp) in self.get_all_page_breakpoints(): 3246 self.erase_page_breakpoint(pid, bp.get_address()) 3247 3248 # erase hardware breakpoints 3249 for (tid, bp) in self.get_all_hardware_breakpoints(): 3250 self.erase_hardware_breakpoint(tid, bp.get_address())
3251 3252 #------------------------------------------------------------------------------ 3253 3254 # Batch operations on breakpoints per process. 3255
3256 - def enable_process_breakpoints(self, dwProcessId):
3257 """ 3258 Enables all disabled breakpoints for the given process. 3259 3260 @type dwProcessId: int 3261 @param dwProcessId: Process global ID. 3262 """ 3263 3264 # enable code breakpoints 3265 for bp in self.get_process_code_breakpoints(dwProcessId): 3266 if bp.is_disabled(): 3267 self.enable_code_breakpoint(dwProcessId, bp.get_address()) 3268 3269 # enable page breakpoints 3270 for bp in self.get_process_page_breakpoints(dwProcessId): 3271 if bp.is_disabled(): 3272 self.enable_page_breakpoint(dwProcessId, bp.get_address()) 3273 3274 # enable hardware breakpoints 3275 if self.system.has_process(dwProcessId): 3276 aProcess = self.system.get_process(dwProcessId) 3277 else: 3278 aProcess = Process(dwProcessId) 3279 aProcess.scan_threads() 3280 for aThread in aProcess.iter_threads(): 3281 dwThreadId = aThread.get_tid() 3282 for bp in self.get_thread_hardware_breakpoints(dwThreadId): 3283 if bp.is_disabled(): 3284 self.enable_hardware_breakpoint(dwThreadId, bp.get_address())
3285
3286 - def enable_one_shot_process_breakpoints(self, dwProcessId):
3287 """ 3288 Enables for one shot all disabled breakpoints for the given process. 3289 3290 @type dwProcessId: int 3291 @param dwProcessId: Process global ID. 3292 """ 3293 3294 # enable code breakpoints for one shot 3295 for bp in self.get_process_code_breakpoints(dwProcessId): 3296 if bp.is_disabled(): 3297 self.enable_one_shot_code_breakpoint(dwProcessId, bp.get_address()) 3298 3299 # enable page breakpoints for one shot 3300 for bp in self.get_process_page_breakpoints(dwProcessId): 3301 if bp.is_disabled(): 3302 self.enable_one_shot_page_breakpoint(dwProcessId, bp.get_address()) 3303 3304 # enable hardware breakpoints for one shot 3305 if self.system.has_process(dwProcessId): 3306 aProcess = self.system.get_process(dwProcessId) 3307 else: 3308 aProcess = Process(dwProcessId) 3309 aProcess.scan_threads() 3310 for aThread in aProcess.iter_threads(): 3311 dwThreadId = aThread.get_tid() 3312 for bp in self.get_thread_hardware_breakpoints(dwThreadId): 3313 if bp.is_disabled(): 3314 self.enable_one_shot_hardware_breakpoint(dwThreadId, bp.get_address())
3315
3316 - def disable_process_breakpoints(self, dwProcessId):
3317 """ 3318 Disables all breakpoints for the given process. 3319 3320 @type dwProcessId: int 3321 @param dwProcessId: Process global ID. 3322 """ 3323 3324 # disable code breakpoints 3325 for bp in self.get_process_code_breakpoints(dwProcessId): 3326 self.disable_code_breakpoint(dwProcessId, bp.get_address()) 3327 3328 # disable page breakpoints 3329 for bp in self.get_process_page_breakpoints(dwProcessId): 3330 self.disable_page_breakpoint(dwProcessId, bp.get_address()) 3331 3332 # disable hardware breakpoints 3333 if self.system.has_process(dwProcessId): 3334 aProcess = self.system.get_process(dwProcessId) 3335 else: 3336 aProcess = Process(dwProcessId) 3337 aProcess.scan_threads() 3338 for aThread in aProcess.iter_threads(): 3339 dwThreadId = aThread.get_tid() 3340 for bp in self.get_thread_hardware_breakpoints(dwThreadId): 3341 self.disable_hardware_breakpoint(dwThreadId, bp.get_address())
3342
3343 - def erase_process_breakpoints(self, dwProcessId):
3344 """ 3345 Erases all breakpoints for the given process. 3346 3347 @type dwProcessId: int 3348 @param dwProcessId: Process global ID. 3349 """ 3350 3351 # disable breakpoints first 3352 # if an error occurs, no breakpoint is erased 3353 self.disable_process_breakpoints(dwProcessId) 3354 3355 ## # erase hooks 3356 ## for address, hook in self.get_process_hooks(dwProcessId): 3357 ## self.dont_hook_function(dwProcessId, address) 3358 3359 # erase code breakpoints 3360 for bp in self.get_process_code_breakpoints(dwProcessId): 3361 self.erase_code_breakpoint(dwProcessId, bp.get_address()) 3362 3363 # erase page breakpoints 3364 for bp in self.get_process_page_breakpoints(dwProcessId): 3365 self.erase_page_breakpoint(dwProcessId, bp.get_address()) 3366 3367 # erase hardware breakpoints 3368 if self.system.has_process(dwProcessId): 3369 aProcess = self.system.get_process(dwProcessId) 3370 else: 3371 aProcess = Process(dwProcessId) 3372 aProcess.scan_threads() 3373 for aThread in aProcess.iter_threads(): 3374 dwThreadId = aThread.get_tid() 3375 for bp in self.get_thread_hardware_breakpoints(dwThreadId): 3376 self.erase_hardware_breakpoint(dwThreadId, bp.get_address())
3377 3378 #------------------------------------------------------------------------------ 3379 3380 # Internal handlers of debug events. 3381
3382 - def _notify_guard_page(self, event):
3383 """ 3384 Notify breakpoints of a guard page exception event. 3385 3386 @type event: L{ExceptionEvent} 3387 @param event: Guard page exception event. 3388 3389 @rtype: bool 3390 @return: C{True} to call the user-defined handle, C{False} otherwise. 3391 """ 3392 address = event.get_fault_address() 3393 pid = event.get_pid() 3394 bCallHandler = True 3395 3396 # Align address to page boundary. 3397 mask = ~(MemoryAddresses.pageSize - 1) 3398 address = address & mask 3399 3400 # Do we have an active page breakpoint there? 3401 key = (pid, address) 3402 if key in self.__pageBP: 3403 bp = self.__pageBP[key] 3404 if bp.is_enabled() or bp.is_one_shot(): 3405 3406 # Breakpoint is ours. 3407 event.continueStatus = win32.DBG_CONTINUE 3408 ## event.continueStatus = win32.DBG_EXCEPTION_HANDLED 3409 3410 # Hit the breakpoint. 3411 bp.hit(event) 3412 3413 # Remember breakpoints in RUNNING state. 3414 if bp.is_running(): 3415 tid = event.get_tid() 3416 self.__add_running_bp(tid, bp) 3417 3418 # Evaluate the breakpoint condition. 3419 bCondition = bp.eval_condition(event) 3420 3421 # If the breakpoint is automatic, run the action. 3422 # If not, notify the user. 3423 if bCondition and bp.is_automatic(): 3424 bp.run_action(event) 3425 bCallHandler = False 3426 else: 3427 bCallHandler = bCondition 3428 3429 # If we don't have a breakpoint here pass the exception to the debugee. 3430 # This is a normally occurring exception so we shouldn't swallow it. 3431 else: 3432 event.continueStatus = win32.DBG_EXCEPTION_NOT_HANDLED 3433 3434 return bCallHandler
3435
3436 - def _notify_breakpoint(self, event):
3437 """ 3438 Notify breakpoints of a breakpoint exception event. 3439 3440 @type event: L{ExceptionEvent} 3441 @param event: Breakpoint exception event. 3442 3443 @rtype: bool 3444 @return: C{True} to call the user-defined handle, C{False} otherwise. 3445 """ 3446 address = event.get_exception_address() 3447 pid = event.get_pid() 3448 bCallHandler = True 3449 3450 # Do we have an active code breakpoint there? 3451 key = (pid, address) 3452 if key in self.__codeBP: 3453 bp = self.__codeBP[key] 3454 if not bp.is_disabled(): 3455 3456 # Change the program counter (PC) to the exception address. 3457 # This accounts for the change in PC caused by 3458 # executing the breakpoint instruction, no matter 3459 # the size of it. 3460 aThread = event.get_thread() 3461 aThread.set_pc(address) 3462 3463 # Swallow the exception. 3464 event.continueStatus = win32.DBG_CONTINUE 3465 3466 # Hit the breakpoint. 3467 bp.hit(event) 3468 3469 # Remember breakpoints in RUNNING state. 3470 if bp.is_running(): 3471 tid = event.get_tid() 3472 self.__add_running_bp(tid, bp) 3473 3474 # Evaluate the breakpoint condition. 3475 bCondition = bp.eval_condition(event) 3476 3477 # If the breakpoint is automatic, run the action. 3478 # If not, notify the user. 3479 if bCondition and bp.is_automatic(): 3480 bCallHandler = bp.run_action(event) 3481 else: 3482 bCallHandler = bCondition 3483 3484 # Handle the system breakpoint. 3485 # TODO: examine the stack trace to figure out if it's really a 3486 # system breakpoint or an antidebug trick. The caller should be 3487 # inside ntdll if it's legit. 3488 elif event.get_process().is_system_defined_breakpoint(address): 3489 event.continueStatus = win32.DBG_CONTINUE 3490 3491 # In hostile mode, if we don't have a breakpoint here pass the 3492 # exception to the debugee. In normal mode assume all breakpoint 3493 # exceptions are to be handled by the debugger. 3494 else: 3495 if self.in_hostile_mode(): 3496 event.continueStatus = win32.DBG_EXCEPTION_NOT_HANDLED 3497 else: 3498 event.continueStatus = win32.DBG_CONTINUE 3499 3500 return bCallHandler
3501
3502 - def _notify_single_step(self, event):
3503 """ 3504 Notify breakpoints of a single step exception event. 3505 3506 @type event: L{ExceptionEvent} 3507 @param event: Single step exception event. 3508 3509 @rtype: bool 3510 @return: C{True} to call the user-defined handle, C{False} otherwise. 3511 """ 3512 pid = event.get_pid() 3513 tid = event.get_tid() 3514 aThread = event.get_thread() 3515 aProcess = event.get_process() 3516 bCallHandler = True 3517 bIsOurs = False 3518 3519 # In hostile mode set the default to pass the exception to the debugee. 3520 # If we later determine the exception is ours, hide it instead. 3521 old_continueStatus = event.continueStatus 3522 try: 3523 if self.in_hostile_mode(): 3524 event.continueStatus = win32.DBG_EXCEPTION_NOT_HANDLED 3525 3526 # Single step support is implemented on x86/x64 architectures only. 3527 if self.system.arch not in (win32.ARCH_I386, win32.ARCH_AMD64): 3528 return bCallHandler 3529 3530 # In hostile mode, read the last executed bytes to try to detect 3531 # some antidebug tricks. Skip this check in normal mode because 3532 # it'd slow things down. 3533 # 3534 # FIXME: weird opcode encodings may bypass this check! 3535 # 3536 # bFakeSingleStep: Ice Breakpoint undocumented instruction. 3537 # bHideTrapFlag: Don't let pushf instructions get the real value of 3538 # the trap flag. 3539 # bNextIsPopFlags: Don't let popf instructions clear the trap flag. 3540 # 3541 bFakeSingleStep = False 3542 bLastIsPushFlags = False 3543 bNextIsPopFlags = False 3544 if self.in_hostile_mode(): 3545 pc = aThread.get_pc() 3546 c = aProcess.read_char(pc - 1) 3547 if c == 0xF1: # int1 3548 bFakeSingleStep = True 3549 elif c == 0x9C: # pushf 3550 bLastIsPushFlags = True 3551 c = aProcess.peek_char(pc) 3552 if c == 0x66: # the only valid prefix for popf 3553 c = aProcess.peek_char(pc + 1) 3554 if c == 0x9D: # popf 3555 if bLastIsPushFlags: 3556 bLastIsPushFlags = False # they cancel each other out 3557 else: 3558 bNextIsPopFlags = True 3559 3560 # When the thread is in tracing mode, 3561 # don't pass the exception to the debugee 3562 # and set the trap flag again. 3563 if self.is_tracing(tid): 3564 bIsOurs = True 3565 if not bFakeSingleStep: 3566 event.continueStatus = win32.DBG_CONTINUE 3567 aThread.set_tf() 3568 3569 # Don't let the debugee read or write the trap flag. 3570 # This code works in 32 and 64 bits thanks to the endianness. 3571 if bLastIsPushFlags or bNextIsPopFlags: 3572 sp = aThread.get_sp() 3573 flags = aProcess.read_dword(sp) 3574 if bLastIsPushFlags: 3575 flags &= ~Thread.Flags.Trap 3576 else: # if bNextIsPopFlags: 3577 flags |= Thread.Flags.Trap 3578 aProcess.write_dword(sp, flags) 3579 3580 # Handle breakpoints in RUNNING state. 3581 running = self.__get_running_bp_set(tid) 3582 if running: 3583 bIsOurs = True 3584 if not bFakeSingleStep: 3585 event.continueStatus = win32.DBG_CONTINUE 3586 bCallHandler = False 3587 while running: 3588 try: 3589 running.pop().hit(event) 3590 except Exception, e: 3591 warnings.warn(str(e), BreakpointWarning) 3592 3593 # Handle hardware breakpoints. 3594 if tid in self.__hardwareBP: 3595 ctx = aThread.get_context(win32.CONTEXT_DEBUG_REGISTERS) 3596 Dr6 = ctx['Dr6'] 3597 ctx['Dr6'] = Dr6 & DebugRegister.clearHitMask 3598 aThread.set_context(ctx) 3599 bFoundBreakpoint = False 3600 bCondition = False 3601 hwbpList = [ bp for bp in self.__hardwareBP[tid] ] 3602 for bp in hwbpList: 3603 if not bp in self.__hardwareBP[tid]: 3604 continue # it was removed by a user-defined callback 3605 slot = bp.get_slot() 3606 if (slot is not None) and \ 3607 (Dr6 & DebugRegister.hitMask[slot]): 3608 if not bFoundBreakpoint: #set before actions are called 3609 if not bFakeSingleStep: 3610 event.continueStatus = win32.DBG_CONTINUE 3611 bFoundBreakpoint = True 3612 bIsOurs = True 3613 bp.hit(event) 3614 if bp.is_running(): 3615 self.__add_running_bp(tid, bp) 3616 bThisCondition = bp.eval_condition(event) 3617 if bThisCondition and bp.is_automatic(): 3618 bp.run_action(event) 3619 bThisCondition = False 3620 bCondition = bCondition or bThisCondition 3621 if bFoundBreakpoint: 3622 bCallHandler = bCondition 3623 3624 # Always call the user-defined handler 3625 # when the thread is in tracing mode. 3626 if self.is_tracing(tid): 3627 bCallHandler = True 3628 3629 # If we're not in hostile mode, by default we assume all single 3630 # step exceptions are caused by the debugger. 3631 if not bIsOurs and not self.in_hostile_mode(): 3632 aThread.clear_tf() 3633 3634 # If the user hit Control-C while we were inside the try block, 3635 # set the default continueStatus back. 3636 except: 3637 event.continueStatus = old_continueStatus 3638 raise 3639 3640 return bCallHandler
3641
3642 - def _notify_load_dll(self, event):
3643 """ 3644 Notify the loading of a DLL. 3645 3646 @type event: L{LoadDLLEvent} 3647 @param event: Load DLL event. 3648 3649 @rtype: bool 3650 @return: C{True} to call the user-defined handler, C{False} otherwise. 3651 """ 3652 self.__set_deferred_breakpoints(event) 3653 return True
3654
3655 - def _notify_unload_dll(self, event):
3656 """ 3657 Notify the unloading of a DLL. 3658 3659 @type event: L{UnloadDLLEvent} 3660 @param event: Unload DLL event. 3661 3662 @rtype: bool 3663 @return: C{True} to call the user-defined handler, C{False} otherwise. 3664 """ 3665 self.__cleanup_module(event) 3666 return True
3667
3668 - def _notify_exit_thread(self, event):
3669 """ 3670 Notify the termination of a thread. 3671 3672 @type event: L{ExitThreadEvent} 3673 @param event: Exit thread event. 3674 3675 @rtype: bool 3676 @return: C{True} to call the user-defined handler, C{False} otherwise. 3677 """ 3678 self.__cleanup_thread(event) 3679 return True
3680
3681 - def _notify_exit_process(self, event):
3682 """ 3683 Notify the termination of a process. 3684 3685 @type event: L{ExitProcessEvent} 3686 @param event: Exit process event. 3687 3688 @rtype: bool 3689 @return: C{True} to call the user-defined handler, C{False} otherwise. 3690 """ 3691 self.__cleanup_process(event) 3692 self.__cleanup_thread(event) 3693 return True
3694 3695 #------------------------------------------------------------------------------ 3696 3697 # This is the high level breakpoint interface. Here we don't have to care 3698 # about defining or enabling breakpoints, and many errors are ignored 3699 # (like for example setting the same breakpoint twice, here the second 3700 # breakpoint replaces the first, much like in WinDBG). It should be easier 3701 # and more intuitive, if less detailed. It also allows the use of deferred 3702 # breakpoints. 3703 3704 #------------------------------------------------------------------------------ 3705 3706 # Code breakpoints 3707
3708 - def __set_break(self, pid, address, action, oneshot):
3709 """ 3710 Used by L{break_at} and L{stalk_at}. 3711 3712 @type pid: int 3713 @param pid: Process global ID. 3714 3715 @type address: int or str 3716 @param address: 3717 Memory address of code instruction to break at. It can be an 3718 integer value for the actual address or a string with a label 3719 to be resolved. 3720 3721 @type action: function 3722 @param action: (Optional) Action callback function. 3723 3724 See L{define_code_breakpoint} for more details. 3725 3726 @type oneshot: bool 3727 @param oneshot: C{True} for one-shot breakpoints, C{False} otherwise. 3728 3729 @rtype: L{Breakpoint} 3730 @return: Returns the new L{Breakpoint} object, or C{None} if the label 3731 couldn't be resolved and the breakpoint was deferred. Deferred 3732 breakpoints are set when the DLL they point to is loaded. 3733 """ 3734 if type(address) not in (int, long): 3735 label = address 3736 try: 3737 address = self.system.get_process(pid).resolve_label(address) 3738 if not address: 3739 raise Exception() 3740 except Exception: 3741 try: 3742 deferred = self.__deferredBP[pid] 3743 except KeyError: 3744 deferred = dict() 3745 self.__deferredBP[pid] = deferred 3746 if label in deferred: 3747 msg = "Redefined deferred code breakpoint at %s in process ID %d" 3748 msg = msg % (label, pid) 3749 warnings.warn(msg, BreakpointWarning) 3750 deferred[label] = (action, oneshot) 3751 return None 3752 if self.has_code_breakpoint(pid, address): 3753 bp = self.get_code_breakpoint(pid, address) 3754 if bp.get_action() != action: # can't use "is not", fails for bound methods 3755 bp.set_action(action) 3756 msg = "Redefined code breakpoint at %s in process ID %d" 3757 msg = msg % (label, pid) 3758 warnings.warn(msg, BreakpointWarning) 3759 else: 3760 self.define_code_breakpoint(pid, address, True, action) 3761 bp = self.get_code_breakpoint(pid, address) 3762 if oneshot: 3763 if not bp.is_one_shot(): 3764 self.enable_one_shot_code_breakpoint(pid, address) 3765 else: 3766 if not bp.is_enabled(): 3767 self.enable_code_breakpoint(pid, address) 3768 return bp
3769
3770 - def __clear_break(self, pid, address):
3771 """ 3772 Used by L{dont_break_at} and L{dont_stalk_at}. 3773 3774 @type pid: int 3775 @param pid: Process global ID. 3776 3777 @type address: int or str 3778 @param address: 3779 Memory address of code instruction to break at. It can be an 3780 integer value for the actual address or a string with a label 3781 to be resolved. 3782 """ 3783 if type(address) not in (int, long): 3784 unknown = True 3785 label = address 3786 try: 3787 deferred = self.__deferredBP[pid] 3788 del deferred[label] 3789 unknown = False 3790 except KeyError: 3791 ## traceback.print_last() # XXX DEBUG 3792 pass 3793 aProcess = self.system.get_process(pid) 3794 try: 3795 address = aProcess.resolve_label(label) 3796 if not address: 3797 raise Exception() 3798 except Exception: 3799 ## traceback.print_last() # XXX DEBUG 3800 if unknown: 3801 msg = ("Can't clear unknown code breakpoint" 3802 " at %s in process ID %d") 3803 msg = msg % (label, pid) 3804 warnings.warn(msg, BreakpointWarning) 3805 return 3806 if self.has_code_breakpoint(pid, address): 3807 self.erase_code_breakpoint(pid, address)
3808
3809 - def __set_deferred_breakpoints(self, event):
3810 """ 3811 Used internally. Sets all deferred breakpoints for a DLL when it's 3812 loaded. 3813 3814 @type event: L{LoadDLLEvent} 3815 @param event: Load DLL event. 3816 """ 3817 pid = event.get_pid() 3818 try: 3819 deferred = self.__deferredBP[pid] 3820 except KeyError: 3821 return 3822 aProcess = event.get_process() 3823 for (label, (action, oneshot)) in deferred.items(): 3824 try: 3825 address = aProcess.resolve_label(label) 3826 except Exception: 3827 continue 3828 del deferred[label] 3829 try: 3830 self.__set_break(pid, address, action, oneshot) 3831 except Exception: 3832 msg = "Can't set deferred breakpoint %s at process ID %d" 3833 msg = msg % (label, pid) 3834 warnings.warn(msg, BreakpointWarning)
3835
3837 """ 3838 Returns a list of deferred code breakpoints. 3839 3840 @rtype: tuple of (int, str, callable, bool) 3841 @return: Tuple containing the following elements: 3842 - Process ID where to set the breakpoint. 3843 - Label pointing to the address where to set the breakpoint. 3844 - Action callback for the breakpoint. 3845 - C{True} of the breakpoint is one-shot, C{False} otherwise. 3846 """ 3847 result = [] 3848 for pid, deferred in self.__deferredBP.iteritems(): 3849 for (label, (action, oneshot)) in deferred.iteritems(): 3850 result.add( (pid, label, action, oneshot) ) 3851 return result
3852
3853 - def get_process_deferred_code_breakpoints(self, dwProcessId):
3854 """ 3855 Returns a list of deferred code breakpoints. 3856 3857 @type dwProcessId: int 3858 @param dwProcessId: Process ID. 3859 3860 @rtype: tuple of (int, str, callable, bool) 3861 @return: Tuple containing the following elements: 3862 - Label pointing to the address where to set the breakpoint. 3863 - Action callback for the breakpoint. 3864 - C{True} of the breakpoint is one-shot, C{False} otherwise. 3865 """ 3866 return [ (label, action, oneshot) 3867 for (label, (action, oneshot)) 3868 in self.__deferredBP.get(dwProcessId, {}).iteritems() ]
3869
3870 - def stalk_at(self, pid, address, action = None):
3871 """ 3872 Sets a one shot code breakpoint at the given process and address. 3873 3874 If instead of an address you pass a label, the breakpoint may be 3875 deferred until the DLL it points to is loaded. 3876 3877 @see: L{break_at}, L{dont_stalk_at} 3878 3879 @type pid: int 3880 @param pid: Process global ID. 3881 3882 @type address: int or str 3883 @param address: 3884 Memory address of code instruction to break at. It can be an 3885 integer value for the actual address or a string with a label 3886 to be resolved. 3887 3888 @type action: function 3889 @param action: (Optional) Action callback function. 3890 3891 See L{define_code_breakpoint} for more details. 3892 3893 @rtype: bool 3894 @return: C{True} if the breakpoint was set immediately, or C{False} if 3895 it was deferred. 3896 """ 3897 bp = self.__set_break(pid, address, action, oneshot = True) 3898 return bp is not None
3899
3900 - def break_at(self, pid, address, action = None):
3901 """ 3902 Sets a code breakpoint at the given process and address. 3903 3904 If instead of an address you pass a label, the breakpoint may be 3905 deferred until the DLL it points to is loaded. 3906 3907 @see: L{stalk_at}, L{dont_break_at} 3908 3909 @type pid: int 3910 @param pid: Process global ID. 3911 3912 @type address: int or str 3913 @param address: 3914 Memory address of code instruction to break at. It can be an 3915 integer value for the actual address or a string with a label 3916 to be resolved. 3917 3918 @type action: function 3919 @param action: (Optional) Action callback function. 3920 3921 See L{define_code_breakpoint} for more details. 3922 3923 @rtype: bool 3924 @return: C{True} if the breakpoint was set immediately, or C{False} if 3925 it was deferred. 3926 """ 3927 bp = self.__set_break(pid, address, action, oneshot = False) 3928 return bp is not None
3929
3930 - def dont_break_at(self, pid, address):
3931 """ 3932 Clears a code breakpoint set by L{break_at}. 3933 3934 @type pid: int 3935 @param pid: Process global ID. 3936 3937 @type address: int or str 3938 @param address: 3939 Memory address of code instruction to break at. It can be an 3940 integer value for the actual address or a string with a label 3941 to be resolved. 3942 """ 3943 self.__clear_break(pid, address)
3944
3945 - def dont_stalk_at(self, pid, address):
3946 """ 3947 Clears a code breakpoint set by L{stalk_at}. 3948 3949 @type pid: int 3950 @param pid: Process global ID. 3951 3952 @type address: int or str 3953 @param address: 3954 Memory address of code instruction to break at. It can be an 3955 integer value for the actual address or a string with a label 3956 to be resolved. 3957 """ 3958 self.__clear_break(pid, address)
3959 3960 #------------------------------------------------------------------------------ 3961 3962 # Function hooks 3963
3964 - def hook_function(self, pid, address, 3965 preCB = None, postCB = None, 3966 paramCount = None, signature = None):
3967 """ 3968 Sets a function hook at the given address. 3969 3970 If instead of an address you pass a label, the hook may be 3971 deferred until the DLL it points to is loaded. 3972 3973 @type pid: int 3974 @param pid: Process global ID. 3975 3976 @type address: int or str 3977 @param address: 3978 Memory address of code instruction to break at. It can be an 3979 integer value for the actual address or a string with a label 3980 to be resolved. 3981 3982 @type preCB: function 3983 @param preCB: (Optional) Callback triggered on function entry. 3984 3985 The signature for the callback should be something like this:: 3986 3987 def pre_LoadLibraryEx(event, ra, lpFilename, hFile, dwFlags): 3988 3989 # return address 3990 ra = params[0] 3991 3992 # function arguments start from here... 3993 szFilename = event.get_process().peek_string(lpFilename) 3994 3995 # (...) 3996 3997 Note that all pointer types are treated like void pointers, so your 3998 callback won't get the string or structure pointed to by it, but 3999 the remote memory address instead. This is so to prevent the ctypes 4000 library from being "too helpful" and trying to dereference the 4001 pointer. To get the actual data being pointed to, use one of the 4002 L{Process.read} methods. 4003 4004 @type postCB: function 4005 @param postCB: (Optional) Callback triggered on function exit. 4006 4007 The signature for the callback should be something like this:: 4008 4009 def post_LoadLibraryEx(event, return_value): 4010 4011 # (...) 4012 4013 @type paramCount: int 4014 @param paramCount: 4015 (Optional) Number of parameters for the C{preCB} callback, 4016 not counting the return address. Parameters are read from 4017 the stack and assumed to be DWORDs in 32 bits and QWORDs in 64. 4018 4019 This is a faster way to pull stack parameters in 32 bits, but in 64 4020 bits (or with some odd APIs in 32 bits) it won't be useful, since 4021 not all arguments to the hooked function will be of the same size. 4022 4023 For a more reliable and cross-platform way of hooking use the 4024 C{signature} argument instead. 4025 4026 @type signature: tuple 4027 @param signature: 4028 (Optional) Tuple of C{ctypes} data types that constitute the 4029 hooked function signature. When the function is called, this will 4030 be used to parse the arguments from the stack. Overrides the 4031 C{paramCount} argument. 4032 4033 @rtype: bool 4034 @return: C{True} if the hook was set immediately, or C{False} if 4035 it was deferred. 4036 """ 4037 try: 4038 aProcess = self.system.get_process(pid) 4039 except KeyError: 4040 aProcess = Process(pid) 4041 arch = aProcess.get_arch() 4042 hookObj = Hook(preCB, postCB, paramCount, signature, arch) 4043 bp = self.break_at(pid, address, hookObj) 4044 return bp is not None
4045
4046 - def stalk_function(self, pid, address, 4047 preCB = None, postCB = None, 4048 paramCount = None, signature = None):
4049 """ 4050 Sets a one-shot function hook at the given address. 4051 4052 If instead of an address you pass a label, the hook may be 4053 deferred until the DLL it points to is loaded. 4054 4055 @type pid: int 4056 @param pid: Process global ID. 4057 4058 @type address: int or str 4059 @param address: 4060 Memory address of code instruction to break at. It can be an 4061 integer value for the actual address or a string with a label 4062 to be resolved. 4063 4064 @type preCB: function 4065 @param preCB: (Optional) Callback triggered on function entry. 4066 4067 The signature for the callback should be something like this:: 4068 4069 def pre_LoadLibraryEx(event, ra, lpFilename, hFile, dwFlags): 4070 4071 # return address 4072 ra = params[0] 4073 4074 # function arguments start from here... 4075 szFilename = event.get_process().peek_string(lpFilename) 4076 4077 # (...) 4078 4079 Note that all pointer types are treated like void pointers, so your 4080 callback won't get the string or structure pointed to by it, but 4081 the remote memory address instead. This is so to prevent the ctypes 4082 library from being "too helpful" and trying to dereference the 4083 pointer. To get the actual data being pointed to, use one of the 4084 L{Process.read} methods. 4085 4086 @type postCB: function 4087 @param postCB: (Optional) Callback triggered on function exit. 4088 4089 The signature for the callback should be something like this:: 4090 4091 def post_LoadLibraryEx(event, return_value): 4092 4093 # (...) 4094 4095 @type paramCount: int 4096 @param paramCount: 4097 (Optional) Number of parameters for the C{preCB} callback, 4098 not counting the return address. Parameters are read from 4099 the stack and assumed to be DWORDs in 32 bits and QWORDs in 64. 4100 4101 This is a faster way to pull stack parameters in 32 bits, but in 64 4102 bits (or with some odd APIs in 32 bits) it won't be useful, since 4103 not all arguments to the hooked function will be of the same size. 4104 4105 For a more reliable and cross-platform way of hooking use the 4106 C{signature} argument instead. 4107 4108 @type signature: tuple 4109 @param signature: 4110 (Optional) Tuple of C{ctypes} data types that constitute the 4111 hooked function signature. When the function is called, this will 4112 be used to parse the arguments from the stack. Overrides the 4113 C{paramCount} argument. 4114 4115 @rtype: bool 4116 @return: C{True} if the breakpoint was set immediately, or C{False} if 4117 it was deferred. 4118 """ 4119 try: 4120 aProcess = self.system.get_process(pid) 4121 except KeyError: 4122 aProcess = Process(pid) 4123 arch = aProcess.get_arch() 4124 hookObj = Hook(preCB, postCB, paramCount, signature, arch) 4125 bp = self.stalk_at(pid, address, hookObj) 4126 return bp is not None
4127
4128 - def dont_hook_function(self, pid, address):
4129 """ 4130 Removes a function hook set by L{hook_function}. 4131 4132 @type pid: int 4133 @param pid: Process global ID. 4134 4135 @type address: int or str 4136 @param address: 4137 Memory address of code instruction to break at. It can be an 4138 integer value for the actual address or a string with a label 4139 to be resolved. 4140 """ 4141 self.dont_break_at(pid, address)
4142 4143 # alias 4144 unhook_function = dont_hook_function 4145
4146 - def dont_stalk_function(self, pid, address):
4147 """ 4148 Removes a function hook set by L{stalk_function}. 4149 4150 @type pid: int 4151 @param pid: Process global ID. 4152 4153 @type address: int or str 4154 @param address: 4155 Memory address of code instruction to break at. It can be an 4156 integer value for the actual address or a string with a label 4157 to be resolved. 4158 """ 4159 self.dont_stalk_at(pid, address)
4160 4161 #------------------------------------------------------------------------------ 4162 4163 # Variable watches 4164
4165 - def __set_variable_watch(self, tid, address, size, action):
4166 """ 4167 Used by L{watch_variable} and L{stalk_variable}. 4168 4169 @type tid: int 4170 @param tid: Thread global ID. 4171 4172 @type address: int 4173 @param address: Memory address of variable to watch. 4174 4175 @type size: int 4176 @param size: Size of variable to watch. The only supported sizes are: 4177 byte (1), word (2), dword (4) and qword (8). 4178 4179 @type action: function 4180 @param action: (Optional) Action callback function. 4181 4182 See L{define_hardware_breakpoint} for more details. 4183 4184 @rtype: L{HardwareBreakpoint} 4185 @return: Hardware breakpoint at the requested address. 4186 """ 4187 4188 # TODO 4189 # We should merge the breakpoints instead of overwriting them. 4190 # We'll have the same problem as watch_buffer and we'll need to change 4191 # the API again. 4192 4193 if size == 1: 4194 sizeFlag = self.BP_WATCH_BYTE 4195 elif size == 2: 4196 sizeFlag = self.BP_WATCH_WORD 4197 elif size == 4: 4198 sizeFlag = self.BP_WATCH_DWORD 4199 elif size == 8: 4200 sizeFlag = self.BP_WATCH_QWORD 4201 else: 4202 raise ValueError("Bad size for variable watch: %r" % size) 4203 4204 if self.has_hardware_breakpoint(tid, address): 4205 warnings.warn( 4206 "Hardware breakpoint in thread %d at address %s was overwritten!" \ 4207 % (tid, HexDump.address(address, 4208 self.system.get_thread(tid).get_bits())), 4209 BreakpointWarning) 4210 4211 bp = self.get_hardware_breakpoint(tid, address) 4212 if bp.get_trigger() != self.BP_BREAK_ON_ACCESS or \ 4213 bp.get_watch() != sizeFlag: 4214 self.erase_hardware_breakpoint(tid, address) 4215 self.define_hardware_breakpoint(tid, address, 4216 self.BP_BREAK_ON_ACCESS, sizeFlag, True, action) 4217 bp = self.get_hardware_breakpoint(tid, address) 4218 4219 else: 4220 self.define_hardware_breakpoint(tid, address, 4221 self.BP_BREAK_ON_ACCESS, sizeFlag, True, action) 4222 bp = self.get_hardware_breakpoint(tid, address) 4223 4224 return bp
4225
4226 - def __clear_variable_watch(self, tid, address):
4227 """ 4228 Used by L{dont_watch_variable} and L{dont_stalk_variable}. 4229 4230 @type tid: int 4231 @param tid: Thread global ID. 4232 4233 @type address: int 4234 @param address: Memory address of variable to stop watching. 4235 """ 4236 if self.has_hardware_breakpoint(tid, address): 4237 self.erase_hardware_breakpoint(tid, address)
4238
4239 - def watch_variable(self, tid, address, size, action = None):
4240 """ 4241 Sets a hardware breakpoint at the given thread, address and size. 4242 4243 @see: L{dont_watch_variable} 4244 4245 @type tid: int 4246 @param tid: Thread global ID. 4247 4248 @type address: int 4249 @param address: Memory address of variable to watch. 4250 4251 @type size: int 4252 @param size: Size of variable to watch. The only supported sizes are: 4253 byte (1), word (2), dword (4) and qword (8). 4254 4255 @type action: function 4256 @param action: (Optional) Action callback function. 4257 4258 See L{define_hardware_breakpoint} for more details. 4259 """ 4260 bp = self.__set_variable_watch(tid, address, size, action) 4261 if not bp.is_enabled(): 4262 self.enable_hardware_breakpoint(tid, address)
4263
4264 - def stalk_variable(self, tid, address, size, action = None):
4265 """ 4266 Sets a one-shot hardware breakpoint at the given thread, 4267 address and size. 4268 4269 @see: L{dont_watch_variable} 4270 4271 @type tid: int 4272 @param tid: Thread global ID. 4273 4274 @type address: int 4275 @param address: Memory address of variable to watch. 4276 4277 @type size: int 4278 @param size: Size of variable to watch. The only supported sizes are: 4279 byte (1), word (2), dword (4) and qword (8). 4280 4281 @type action: function 4282 @param action: (Optional) Action callback function. 4283 4284 See L{define_hardware_breakpoint} for more details. 4285 """ 4286 bp = self.__set_variable_watch(tid, address, size, action) 4287 if not bp.is_one_shot(): 4288 self.enable_one_shot_hardware_breakpoint(tid, address)
4289
4290 - def dont_watch_variable(self, tid, address):
4291 """ 4292 Clears a hardware breakpoint set by L{watch_variable}. 4293 4294 @type tid: int 4295 @param tid: Thread global ID. 4296 4297 @type address: int 4298 @param address: Memory address of variable to stop watching. 4299 """ 4300 self.__clear_variable_watch(tid, address)
4301
4302 - def dont_stalk_variable(self, tid, address):
4303 """ 4304 Clears a hardware breakpoint set by L{stalk_variable}. 4305 4306 @type tid: int 4307 @param tid: Thread global ID. 4308 4309 @type address: int 4310 @param address: Memory address of variable to stop watching. 4311 """ 4312 self.__clear_variable_watch(tid, address)
4313 4314 #------------------------------------------------------------------------------ 4315 4316 # Buffer watches 4317
4318 - def __set_buffer_watch(self, pid, address, size, action, bOneShot):
4319 """ 4320 Used by L{watch_buffer} and L{stalk_buffer}. 4321 4322 @type pid: int 4323 @param pid: Process global ID. 4324 4325 @type address: int 4326 @param address: Memory address of buffer to watch. 4327 4328 @type size: int 4329 @param size: Size in bytes of buffer to watch. 4330 4331 @type action: function 4332 @param action: (Optional) Action callback function. 4333 4334 See L{define_page_breakpoint} for more details. 4335 4336 @type bOneShot: bool 4337 @param bOneShot: 4338 C{True} to set a one-shot breakpoint, 4339 C{False} to set a normal breakpoint. 4340 """ 4341 4342 # Check the size isn't zero or negative. 4343 if size < 1: 4344 raise ValueError("Bad size for buffer watch: %r" % size) 4345 4346 # Create the buffer watch identifier. 4347 bw = BufferWatch(pid, address, address + size, action, bOneShot) 4348 4349 # Get the base address and size in pages required for this buffer. 4350 base = MemoryAddresses.align_address_to_page_start(address) 4351 limit = MemoryAddresses.align_address_to_page_end(address + size) 4352 pages = MemoryAddresses.get_buffer_size_in_pages(address, size) 4353 4354 try: 4355 4356 # For each page: 4357 # + if a page breakpoint exists reuse it 4358 # + if it doesn't exist define it 4359 4360 bset = set() # all breakpoints used 4361 nset = set() # newly defined breakpoints 4362 cset = set() # condition objects 4363 4364 page_addr = base 4365 pageSize = MemoryAddresses.pageSize 4366 while page_addr < limit: 4367 4368 # If a breakpoints exists, reuse it. 4369 if self.has_page_breakpoint(pid, page_addr): 4370 bp = self.get_page_breakpoint(pid, page_addr) 4371 if bp not in bset: 4372 condition = bp.get_condition() 4373 if not condition in cset: 4374 if not isinstance(condition,_BufferWatchCondition): 4375 # this shouldn't happen unless you tinkered 4376 # with it or defined your own page breakpoints 4377 # manually. 4378 msg = "Can't watch buffer at page %s" 4379 msg = msg % HexDump.address(page_addr) 4380 raise RuntimeError(msg) 4381 cset.add(condition) 4382 bset.add(bp) 4383 4384 # If it doesn't, define it. 4385 else: 4386 condition = _BufferWatchCondition() 4387 bp = self.define_page_breakpoint(pid, page_addr, 1, 4388 condition = condition) 4389 bset.add(bp) 4390 nset.add(bp) 4391 cset.add(condition) 4392 4393 # Next page. 4394 page_addr = page_addr + pageSize 4395 4396 # For each breakpoint, enable it if needed. 4397 aProcess = self.system.get_process(pid) 4398 for bp in bset: 4399 if bp.is_disabled() or bp.is_one_shot(): 4400 bp.enable(aProcess, None) 4401 4402 # On error... 4403 except: 4404 4405 # Erase the newly defined breakpoints. 4406 for bp in nset: 4407 try: 4408 self.erase_page_breakpoint(pid, bp.get_address()) 4409 except: 4410 pass 4411 4412 # Pass the exception to the caller 4413 raise 4414 4415 # For each condition object, add the new buffer. 4416 for condition in cset: 4417 condition.add(bw)
4418
4419 - def __clear_buffer_watch_old_method(self, pid, address, size):
4420 """ 4421 Used by L{dont_watch_buffer} and L{dont_stalk_buffer}. 4422 4423 @warn: Deprecated since WinAppDbg 1.5. 4424 4425 @type pid: int 4426 @param pid: Process global ID. 4427 4428 @type address: int 4429 @param address: Memory address of buffer to stop watching. 4430 4431 @type size: int 4432 @param size: Size in bytes of buffer to stop watching. 4433 """ 4434 warnings.warn("Deprecated since WinAppDbg 1.5", DeprecationWarning) 4435 4436 # Check the size isn't zero or negative. 4437 if size < 1: 4438 raise ValueError("Bad size for buffer watch: %r" % size) 4439 4440 # Get the base address and size in pages required for this buffer. 4441 base = MemoryAddresses.align_address_to_page_start(address) 4442 limit = MemoryAddresses.align_address_to_page_end(address + size) 4443 pages = MemoryAddresses.get_buffer_size_in_pages(address, size) 4444 4445 # For each page, get the breakpoint and it's condition object. 4446 # For each condition, remove the buffer. 4447 # For each breakpoint, if no buffers are on watch, erase it. 4448 cset = set() # condition objects 4449 page_addr = base 4450 pageSize = MemoryAddresses.pageSize 4451 while page_addr < limit: 4452 if self.has_page_breakpoint(pid, page_addr): 4453 bp = self.get_page_breakpoint(pid, page_addr) 4454 condition = bp.get_condition() 4455 if condition not in cset: 4456 if not isinstance(condition, _BufferWatchCondition): 4457 # this shouldn't happen unless you tinkered with it 4458 # or defined your own page breakpoints manually. 4459 continue 4460 cset.add(condition) 4461 condition.remove_last_match(address, size) 4462 if condition.count() == 0: 4463 try: 4464 self.erase_page_breakpoint(pid, bp.get_address()) 4465 except WindowsError: 4466 pass 4467 page_addr = page_addr + pageSize
4468
4469 - def __clear_buffer_watch(self, bw):
4470 """ 4471 Used by L{dont_watch_buffer} and L{dont_stalk_buffer}. 4472 4473 @type bw: L{BufferWatch} 4474 @param bw: Buffer watch identifier. 4475 """ 4476 4477 # Get the PID and the start and end addresses of the buffer. 4478 pid = bw.pid 4479 start = bw.start 4480 end = bw.end 4481 4482 # Get the base address and size in pages required for the buffer. 4483 base = MemoryAddresses.align_address_to_page_start(start) 4484 limit = MemoryAddresses.align_address_to_page_end(end) 4485 pages = MemoryAddresses.get_buffer_size_in_pages(start, end - start) 4486 4487 # For each page, get the breakpoint and it's condition object. 4488 # For each condition, remove the buffer. 4489 # For each breakpoint, if no buffers are on watch, erase it. 4490 cset = set() # condition objects 4491 page_addr = base 4492 pageSize = MemoryAddresses.pageSize 4493 while page_addr < limit: 4494 if self.has_page_breakpoint(pid, page_addr): 4495 bp = self.get_page_breakpoint(pid, page_addr) 4496 condition = bp.get_condition() 4497 if condition not in cset: 4498 if not isinstance(condition, _BufferWatchCondition): 4499 # this shouldn't happen unless you tinkered with it 4500 # or defined your own page breakpoints manually. 4501 continue 4502 cset.add(condition) 4503 condition.remove(bw) 4504 if condition.count() == 0: 4505 try: 4506 self.erase_page_breakpoint(pid, bp.get_address()) 4507 except WindowsError: 4508 msg = "Cannot remove page breakpoint at address %s" 4509 msg = msg % HexDump.address( bp.get_address() ) 4510 warnings.warn(msg, BreakpointWarning) 4511 page_addr = page_addr + pageSize
4512
4513 - def watch_buffer(self, pid, address, size, action = None):
4514 """ 4515 Sets a page breakpoint and notifies when the given buffer is accessed. 4516 4517 @see: L{dont_watch_variable} 4518 4519 @type pid: int 4520 @param pid: Process global ID. 4521 4522 @type address: int 4523 @param address: Memory address of buffer to watch. 4524 4525 @type size: int 4526 @param size: Size in bytes of buffer to watch. 4527 4528 @type action: function 4529 @param action: (Optional) Action callback function. 4530 4531 See L{define_page_breakpoint} for more details. 4532 4533 @rtype: L{BufferWatch} 4534 @return: Buffer watch identifier. 4535 """ 4536 self.__set_buffer_watch(pid, address, size, action, False)
4537
4538 - def stalk_buffer(self, pid, address, size, action = None):
4539 """ 4540 Sets a one-shot page breakpoint and notifies 4541 when the given buffer is accessed. 4542 4543 @see: L{dont_watch_variable} 4544 4545 @type pid: int 4546 @param pid: Process global ID. 4547 4548 @type address: int 4549 @param address: Memory address of buffer to watch. 4550 4551 @type size: int 4552 @param size: Size in bytes of buffer to watch. 4553 4554 @type action: function 4555 @param action: (Optional) Action callback function. 4556 4557 See L{define_page_breakpoint} for more details. 4558 4559 @rtype: L{BufferWatch} 4560 @return: Buffer watch identifier. 4561 """ 4562 self.__set_buffer_watch(pid, address, size, action, True)
4563
4564 - def dont_watch_buffer(self, bw, *argv, **argd):
4565 """ 4566 Clears a page breakpoint set by L{watch_buffer}. 4567 4568 @type bw: L{BufferWatch} 4569 @param bw: 4570 Buffer watch identifier returned by L{watch_buffer}. 4571 """ 4572 4573 # The sane way to do it. 4574 if not (argv or argd): 4575 self.__clear_buffer_watch(bw) 4576 4577 # Backwards compatibility with WinAppDbg 1.4. 4578 else: 4579 argv = list(argv) 4580 argv.insert(0, bw) 4581 if 'pid' in argd: 4582 argv.insert(0, argd.pop('pid')) 4583 if 'address' in argd: 4584 argv.insert(1, argd.pop('address')) 4585 if 'size' in argd: 4586 argv.insert(2, argd.pop('size')) 4587 if argd: 4588 raise TypeError("Wrong arguments for dont_watch_buffer()") 4589 try: 4590 pid, address, size = argv 4591 except ValueError: 4592 raise TypeError("Wrong arguments for dont_watch_buffer()") 4593 self.__clear_buffer_watch_old_method(pid, address, size)
4594
4595 - def dont_stalk_buffer(self, bw, *argv, **argd):
4596 """ 4597 Clears a page breakpoint set by L{stalk_buffer}. 4598 4599 @type bw: L{BufferWatch} 4600 @param bw: 4601 Buffer watch identifier returned by L{stalk_buffer}. 4602 """ 4603 self.dont_watch_buffer(bw, *argv, **argd)
4604 4605 #------------------------------------------------------------------------------ 4606 4607 # Tracing 4608 4609 # XXX TODO 4610 # Add "action" parameter to tracing mode 4611
4612 - def __start_tracing(self, thread):
4613 """ 4614 @type thread: L{Thread} 4615 @param thread: Thread to start tracing. 4616 """ 4617 tid = thread.get_tid() 4618 if not tid in self.__tracing: 4619 thread.set_tf() 4620 self.__tracing.add(tid)
4621
4622 - def __stop_tracing(self, thread):
4623 """ 4624 @type thread: L{Thread} 4625 @param thread: Thread to stop tracing. 4626 """ 4627 tid = thread.get_tid() 4628 if tid in self.__tracing: 4629 self.__tracing.remove(tid) 4630 if thread.is_alive(): 4631 thread.clear_tf()
4632
4633 - def is_tracing(self, tid):
4634 """ 4635 @type tid: int 4636 @param tid: Thread global ID. 4637 4638 @rtype: bool 4639 @return: C{True} if the thread is being traced, C{False} otherwise. 4640 """ 4641 return tid in self.__tracing
4642
4643 - def get_traced_tids(self):
4644 """ 4645 Retrieves the list of global IDs of all threads being traced. 4646 4647 @rtype: list( int... ) 4648 @return: List of thread global IDs. 4649 """ 4650 tids = list(self.__tracing) 4651 tids.sort() 4652 return tids
4653
4654 - def start_tracing(self, tid):
4655 """ 4656 Start tracing mode in the given thread. 4657 4658 @type tid: int 4659 @param tid: Global ID of thread to start tracing. 4660 """ 4661 if not self.is_tracing(tid): 4662 thread = self.system.get_thread(tid) 4663 self.__start_tracing(thread)
4664
4665 - def stop_tracing(self, tid):
4666 """ 4667 Stop tracing mode in the given thread. 4668 4669 @type tid: int 4670 @param tid: Global ID of thread to stop tracing. 4671 """ 4672 if self.is_tracing(tid): 4673 thread = self.system.get_thread(tid) 4674 self.__stop_tracing(thread)
4675
4676 - def start_tracing_process(self, pid):
4677 """ 4678 Start tracing mode for all threads in the given process. 4679 4680 @type pid: int 4681 @param pid: Global ID of process to start tracing. 4682 """ 4683 for thread in self.system.get_process(pid).iter_threads(): 4684 self.__start_tracing(thread)
4685
4686 - def stop_tracing_process(self, pid):
4687 """ 4688 Stop tracing mode for all threads in the given process. 4689 4690 @type pid: int 4691 @param pid: Global ID of process to stop tracing. 4692 """ 4693 for thread in self.system.get_process(pid).iter_threads(): 4694 self.__stop_tracing(thread)
4695
4696 - def start_tracing_all(self):
4697 """ 4698 Start tracing mode for all threads in all debugees. 4699 """ 4700 for pid in self.get_debugee_pids(): 4701 self.start_tracing_process(pid)
4702
4703 - def stop_tracing_all(self):
4704 """ 4705 Stop tracing mode for all threads in all debugees. 4706 """ 4707 for pid in self.get_debugee_pids(): 4708 self.stop_tracing_process(pid)
4709 4710 #------------------------------------------------------------------------------ 4711 4712 # Break on LastError values (only available since Windows Server 2003) 4713
4714 - def break_on_error(self, pid, errorCode):
4715 """ 4716 Sets or clears the system breakpoint for a given Win32 error code. 4717 4718 Use L{Process.is_system_defined_breakpoint} to tell if a breakpoint 4719 exception was caused by a system breakpoint or by the application 4720 itself (for example because of a failed assertion in the code). 4721 4722 @note: This functionality is only available since Windows Server 2003. 4723 In 2003 it only breaks on error values set externally to the 4724 kernel32.dll library, but this was fixed in Windows Vista. 4725 4726 @warn: This method will fail if the debug symbols for ntdll (kernel32 4727 in Windows 2003) are not present. For more information see: 4728 L{System.fix_symbol_store_path}. 4729 4730 @see: U{http://www.nynaeve.net/?p=147} 4731 4732 @type pid: int 4733 @param pid: Process ID. 4734 4735 @type errorCode: int 4736 @param errorCode: Win32 error code to stop on. Set to C{0} or 4737 C{ERROR_SUCCESS} to clear the breakpoint instead. 4738 4739 @raise NotImplementedError: 4740 The functionality is not supported in this system. 4741 4742 @raise WindowsError: 4743 An error occurred while processing this request. 4744 """ 4745 aProcess = self.system.get_process(pid) 4746 address = aProcess.get_break_on_error_ptr() 4747 if not address: 4748 raise NotImplementedError( 4749 "The functionality is not supported in this system.") 4750 aProcess.write_dword(address, errorCode)
4751
4752 - def dont_break_on_error(self, pid):
4753 """ 4754 Alias to L{break_on_error}C{(pid, ERROR_SUCCESS)}. 4755 4756 @type pid: int 4757 @param pid: Process ID. 4758 4759 @raise NotImplementedError: 4760 The functionality is not supported in this system. 4761 4762 @raise WindowsError: 4763 An error occurred while processing this request. 4764 """ 4765 self.break_on_error(pid, 0)
4766 4767 #------------------------------------------------------------------------------ 4768 4769 # Simplified symbol resolving, useful for hooking functions 4770
4771 - def resolve_exported_function(self, pid, modName, procName):
4772 """ 4773 Resolves the exported DLL function for the given process. 4774 4775 @type pid: int 4776 @param pid: Process global ID. 4777 4778 @type modName: str 4779 @param modName: Name of the module that exports the function. 4780 4781 @type procName: str 4782 @param procName: Name of the exported function to resolve. 4783 4784 @rtype: int, None 4785 @return: On success, the address of the exported function. 4786 On failure, returns C{None}. 4787 """ 4788 aProcess = self.system.get_process(pid) 4789 aModule = aProcess.get_module_by_name(modName) 4790 if not aModule: 4791 aProcess.scan_modules() 4792 aModule = aProcess.get_module_by_name(modName) 4793 if aModule: 4794 address = aModule.resolve(procName) 4795 return address 4796 return None
4797
4798 - def resolve_label(self, pid, label):
4799 """ 4800 Resolves a label for the given process. 4801 4802 @type pid: int 4803 @param pid: Process global ID. 4804 4805 @type label: str 4806 @param label: Label to resolve. 4807 4808 @rtype: int 4809 @return: Memory address pointed to by the label. 4810 4811 @raise ValueError: The label is malformed or impossible to resolve. 4812 @raise RuntimeError: Cannot resolve the module or function. 4813 """ 4814 return self.get_process(pid).resolve_label(label)
4815