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

Source Code for Module winappdbg.breakpoint

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