-
Notifications
You must be signed in to change notification settings - Fork 76
Debug instruction breakpoints
- debug.addBreakpoint(memoryAddress, callback)
- debug.removeBreakpoint(memoryAddress)
- debug.resume()
- debug.writeRegisters(registers)
- def callback(instructionPointer, registers)
debug.addBreakpoint sets up an instruction breakpoint at memoryAddress and will call your callback when hit. The callback takes an instruction pointer, and a table of registers as arguments.
After your callback is invoked, you should make a debug.resume() call (or one of the stepping functions described further down) which will continue your target's execution. This is typically done at the end of your callback, but can be done later. When your script terminates, the target will be resumed even if you don't explicitly call debug.resume() yourself.
In your callback, you can also use debug.writeRegisters to alter the halted thread's registers, which takes a dictionary of register names and values. If the size you're writing to a value is ambiguous, you may have to provide the value as a bytearray or buffer object. debug.writeRegisters cannot be called if the target is resumed.
To remove your breakpoint, call debug.removeBreakpoint and pass in the memoryAddress to remove. Note that all breakpoints will automatically be removed when a script is disabled, so there's no need to remove them in your finish method.
debug.addBreakpoint raises bitslicer.DebuggerError if a breakpoint could not be added to the instruction located at memoryAddress, or raises ValueError if callback is not callable.
debug.removeBreakpoint raises bitslicer.DebuggerError if the instruction located at memoryAddress could not be parsed.
debug.writeRegisters raises bitslicer.DebuggerError if it fails to write the new registers or raises ValueError if one of the values in the registers dictionary could not be handled.
Example:
#Instruction Breakpoints!
import bitslicer
import struct
ADD_HEALTH_ADDRESS = 0x10D486A05
class Script(object):
def __init__(self):
debug.addBreakpoint(ADD_HEALTH_ADDRESS, self.addHealth)
def addHealth(self, instructionAddress, registers):
oldValue = vm.readInt8(registers['rax'] + registers['rsi'] + 0x4)
debug.log(oldValue)
debug.writeRegisters({'rax' : 0x1000, 'xmm0' : struct.pack('<f', 1.0)})
#only interested in first time called
debug.removeBreakpoint(instructionAddress)
debug.resume()
- debug.stepIn(callback)
- debug.stepOver(callback)
- debug.stepOut(callback)
- def callback(instructionPointer, registers)
Alternatively instead of calling debug.resume() from a breakpoint callback, one of these functions can be used. These functions will resume from the breakpoint and will break and invoke the specified callback after execution has been stepped.
The differences between the three stepping functions are:
debug.stepIn steps a single instruction before breaking
debug.stepOver steps over a function call or a single instruction otherwise before breaking
debug.stepOut steps until after returning out of the current function before breaking
Raises ValueError if callback is not callable or bitslicer.DebuggerError in the case of debug.stepOver and debug.stepOut if unable to find the instructions to step toward.
- debug.backtrace()
Returns a list of instruction memory addresses showing the program's backtrace. This is similar to the backtrace in the Debugger window. Note that this can only be called when a breakpoint you set up is hit, and will only apply for the thread that caused the breakpoint to be hit.
Raises bitslicer.DebuggerError if unable to retrieve a backtrace or if not at a halted breakpoint state.
Searching
- Introduction to Searching
- Data Types
- Storing All Values
- Pointers
- Search Windows
- Pausing Targets
- Web Games
Memory
Debugging
Scripting