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

Source Code for Module winappdbg.breakpoint

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