def __init__(self): # Holds a instance of our PyCPU class self.cpu = None # Holds an instance of our PyOS class self.os = None # Tells the emulator whether we are emulating self.emulating = True # Whether to use a frame pointer for stack offsets self.frame_pointer = True # Class members to hold stack and heap limits self.stack_base = 0x0 self.stack_size = 0x0 self.heap_base = 0x0 self.heap_size = 0x0 # Holds an instance of our PyMemory class self.memory = "" # A list of names for public methods self.register_names = {} self.stack_variable_names = {} self.stack_argument_names = {} # A list of our user handlers for various aspects of emulation self.mnemonic_handlers = {} self.opcode_handlers = {} self.register_handlers = {} self.pc_handlers = {} self.exception_handlers = {} self.interrupt_handlers = {} self.library_handlers = {} self.memory_handlers = {} self.memory_read_handler = None self.memory_write_handler = None self.memory_access_handler = None self.stack_read_handler = None self.stack_write_handler = None self.stack_access_handler = None self.heap_read_handler = None self.heap_write_handler = None self.heap_access_handler = None # Instantiate a CPU for use in the emulator self.cpu = PyCPU(self) # Determine which os we are on to instantiate the proper PyOS if os.name == 'nt': self.os = PyWindows() elif os.name == 'posix': # Yea I realize self.os = PyLinux()
def __init__(self): # Holds a instance of our PyCPU class self.cpu = None # Holds an instance of our PyOS class self.os = None # Tells the emulator whether we are emulating self.emulating = True # Whether to use a frame pointer for stack offsets self.frame_pointer = True # Class members to hold stack and heap limits self.stack_base = 0x0 self.stack_size = 0x0 self.heap_base = 0x0 self.heap_size = 0x0 # Holds an instance of our PyMemory class self.memory = None # A list of names for public methods self.register_names = {} self.stack_variable_names = {} self.stack_argument_names = {} # A list of our user handlers for various aspects of emulation self.mnemonic_handlers = {} self.opcode_handlers = {} self.register_handlers = {} self.pc_handlers = {} self.exception_handlers = {} self.interrupt_handlers = {} self.library_handlers = {} self.memory_handlers = {} self.memory_read_handler = None self.memory_write_handler = None self.memory_access_handler = None self.instruction_parsed_handle = None self.instruction_executed_handle = None self.stack_read_handler = None self.stack_write_handler = None self.stack_access_handler = None self.heap_read_handler = None self.heap_write_handler = None self.heap_access_handler = None # Instantiate a CPU for use in the emulator self.cpu = PyCPU(self)
class PyEmu: DEBUG = 0 def __init__(self): # Holds a instance of our PyCPU class self.cpu = None # Holds an instance of our PyOS class self.os = None # Tells the emulator whether we are emulating self.emulating = True # Whether to use a frame pointer for stack offsets self.frame_pointer = True # Class members to hold stack and heap limits self.stack_base = 0x0 self.stack_size = 0x0 self.heap_base = 0x0 self.heap_size = 0x0 # Holds an instance of our PyMemory class self.memory = "" # A list of names for public methods self.register_names = {} self.stack_variable_names = {} self.stack_argument_names = {} # A list of our user handlers for various aspects of emulation self.mnemonic_handlers = {} self.opcode_handlers = {} self.register_handlers = {} self.pc_handlers = {} self.exception_handlers = {} self.interrupt_handlers = {} self.library_handlers = {} self.memory_handlers = {} self.memory_read_handler = None self.memory_write_handler = None self.memory_access_handler = None self.stack_read_handler = None self.stack_write_handler = None self.stack_access_handler = None self.heap_read_handler = None self.heap_write_handler = None self.heap_access_handler = None # Instantiate a CPU for use in the emulator self.cpu = PyCPU(self) # Determine which os we are on to instantiate the proper PyOS if os.name == 'nt': self.os = PyWindows() elif os.name == 'posix': # Yea I realize self.os = PyLinux() # # raise_exception: This method gets called when an exception happens # Currently we only care about general protection # faults (invalid memory access). We will throw a # Python exception when this occurs (I want to change # this). # def raise_exception(self, exception, address): # User must raise their own exception if exception in self.exception_handlers: self.exception_handlers[exception](self, exception, address, self.cpu.EIP) else: print "\n" print "*" * 72 print "* A %s fault has occured at 0x%08x" % (exception, address) print "*" * 72 self.dump_regs() self.dump_stack() raise RuntimeError, "The memory requested was invalid" return False # # debug: A public method for setting global debug levels # def debug(self, level): self.DEBUG = level # Propigate the debug levels throughout self.memory.set_debug(level) self.cpu.set_debug(level) self.os.set_debug(level) # # execute: A public method for executing instructions # def execute(self, steps=1, start=0x0, end=0x0): if not isinstance(steps, int) or not isinstance( start, int) or not isinstance(end, int): return False # If we are called we are emulating self.emulating = True # Set the instruction pointer to the user supplied address if start: self.cpu.set_register32("EIP", start) # Set a stopping point if supplied so we can break if end: if steps > 1: while self.cpu.get_register32("EIP") != end and steps: if not self.emulating: return False if not self.cpu.execute(): print "[!] Problem executing" return False steps -= 1 else: while self.cpu.get_register32("EIP") != end: if not self.emulating: return False if not self.cpu.execute(): print "[!] Problem executing" return False else: for x in range(steps): if not self.emulating: return False if not self.cpu.execute(): print "[!] Problem executing" return False return True # # get_register: A public method to retrieve a register for the user # def get_register(self, register): register = register.upper() # We are smart about the requested register automatically # determining the proper register size # 32 bit registers if re.compile('^E[A-X]{2}$', re.IGNORECASE).match(register): result = self.cpu.get_register32(register) # 16 bit registers elif re.compile('^[ABCD]X$', re.IGNORECASE).match(register): result = self.cpu.get_register16(register) # 8 bit registers elif re.compile('^[ABCD]{1,}[LH]{1}$', re.IGNORECASE).match(register): result = self.cpu.get_register8(register) # Segment registers elif re.compile('^[CSDEFG]{1}S$', re.IGNORECASE).match(register): result = self.cpu.get_register16(register) # Flags elif re.compile('^[CPAZSTIDPR]{1}F$', re.IGNORECASE).match(register) or register in [ "IOPL", "NT", "VM", "AC", "VIF", "VIP", "ID" ]: result = self.cpu.get_register8(register) # Check to make sure the user isnt requesting by name else: if register in self.register_names: result = self.cpu.get_register( self.register_names[register]["name"], self.register_names[register]["size"]) else: print "[!] Couldnt determine register" return False return result # # set_register: A public method for setting a registers value # from a script. # def set_register(self, register, value, name=""): # Make sure its a valid value if not isinstance(value, int) and not isinstance(value, long): print "[!] Dont know how to use non-int value %s" % type(value) return False register = register.upper() name = name.upper() # We are smart about the requested register automatically # determining the proper register size # 32 bit registers if re.compile('^E[A-X]{2}$', re.IGNORECASE).match(register): if name: self.register_names[name] = {"name": register, "size": 4} # Try and set the register if not self.cpu.set_register32(register, value): print "[!] Problem setting register" return False # 16 bit registers elif re.compile('^[ABCD]X$', re.IGNORECASE).match(register): if name: self.register_names[name] = {"name": register, "size": 2} # Try and set the register if not self.cpu.set_register16(register, value): print "[!] Problem setting register" return False # 8 bit registers elif re.compile('^[ABCD]{1,}[LH]{1}$', re.IGNORECASE).match(register): if name: self.register_names[name] = {"name": register, "size": 1} # Try and set the register if not self.cpu.set_register8(register, value): print "[!] Problem setting register" return False # Segment registers elif re.compile('^[CSDEFG]{1}S$', re.IGNORECASE).match(register): if name: self.register_names[name] = {"name": register, "size": 2} # Try and set the register if not self.cpu.set_register16(register, value): print "[!] Problem setting register" return False # Flags elif re.compile('^[CPAZSTIDPR]{1}F$', re.IGNORECASE).match(register) or register in [ "IOPL", "NT", "VM", "AC", "VIF", "VIP", "ID" ]: if name: self.register_names[name] = {"name": register, "size": 1} # Try and set the register if not self.cpu.set_register8(register, value): print "[!] Problem setting register" return False # Check to make sure the user isnt requesting by name else: if name in self.register_names: # Try and set the register if not self.cpu.set_register( self.register_names[name]["name"], self.register_names[name]["size"]): print "[!] Problem setting register" return False else: print "[!] Couldnt determine register size" return False return True # # get_stack_variable: A public method for setting stack local variables # def get_stack_variable(self, offset, size=0): # Validate the type of argument to determine offset or name if isinstance(offset, str): offset = offset.upper() # Check if we have the name if offset not in self.stack_variable_names: print "[!] Couldnt find name %s" % offset return False else: # Retrieve the offset associated offset = self.stack_variable_names[offset] elif not isinstance(offset, int) and not isinstance(offset, long): print "[!] Dont understand %s type" % type(offset) return False # If we dont have a size default to a dword if not size: size = 4 # Check if we are using frame pointers for offsets if self.frame_pointer: address = self.cpu.get_register32("EBP") - offset else: address = self.cpu.get_register32("ESP") + offset # Fetch the address requested from the memory manager result = self.memory.get_memory(address, size) # Return the value return result # # set_stack_variable: A public method for setting a local stack variable # def set_stack_variable(self, offset, value, size=0, name=""): # Make sure our offset is a valid type if not isinstance(offset, int) and not isinstance(offset, long): print "[!] Offset must be int not %s" % type(offset) return False # Automagically determine a size for the supplied string if isinstance(value, str): if not size: size = len(value) else: # Truncate the string if necessary value = value[:size] elif isinstance(value, int) or isinstance(value, long): if not size: size = 4 # If we are setting a name store it in the names list if name: name = name.upper() self.stack_variable_names[name] = offset # Check for a frame pointer to get the proper offset if self.frame_pointer: address = self.cpu.get_register32("EBP") - offset else: address = self.cpu.get_register32("ESP") + offset # Set the value in memory via the memory manager if not self.set_memory(address, value, size): print "[!] Failed setting memory @ %x" % (address) return False return True # # get_stack_argument: A public method to get a functions stack argument # def get_stack_argument(self, offset, size=0): # If we are asking by name check it if isinstance(offset, str): offset = offset.upper() if offset not in self.stack_variable_names: print "[!] Couldnt find name %s" % offset return False else: # Return the offset associated offset = self.stack_variable_names[offset] elif not isinstance(offset, int) and not isinstance(offset, long): print "[!] Dont understand %s type" % type(offset) return False # We only handle dword arguments for now size = 4 # Check for frame pointer to get the proper stack address if self.frame_pointer: address = self.cpu.get_register32("EBP") + offset else: address = self.cpu.get_register32("ESP") + offset # Retrieve the value from memory via the memory manager result = self.memory.get_memory(address, size) return result # # set_stack_argument: A public method to set up a stack argument # def set_stack_argument(self, offset, value, name=""): # Ensure the offset is proper if not isinstance(offset, int) and not isinstance(offset, long): print "[!] Offset must be int not %s" % type(offset) return False # Only dword arguments for now size = 4 # If we have a name we need to get the associated offset if name: name = name.upper() self.stack_variable_names[name] = offset # Check the frame pointer and get the proper address if self.frame_pointer: address = self.cpu.get_register32("EBP") + offset else: address = self.cpu.get_register32("ESP") + offset # Store the value on the stack if not self.set_memory(address, value, size): print "[!] Failed setting memory @ %x" % (address) return False return True # # get_memory: A public method for fetching arbitrary memory # def get_memory(self, address, size=0): if not size: size = 4 # Fetch the value result = self.memory.get_memory(address, size) return result # # get_memory_string: A public method to fetch a string from memory # def get_memory_string(self, address): s = "" x = 0 while True: b = self.get_memory(address + x, size=1) if b != 0x00: s += chr(b) else: break x += 1 return s # # set_memory: A public method for setting arbitrary memory # def set_memory(self, address, value, size=0): # If we are using a string calculate the size if isinstance(value, str): if not size: size = len(value) else: value = value[:size] elif isinstance(value, int) or isinstance(value, long): if not size: size = 4 else: print "[!] I dont know what this type is" return False # For right now we lower the fault so the user can set arbitraty memory self.memory.fault = False # Set the value into memory via the memory manager if not self.memory.set_memory(address, value, size): print "[!] Failed setting memory @ %x" % (address) return False self.memory.fault = True return True # # get_selector: A public method for fetching a selector from the LDT # def get_selector(self, selector): return self.os.get_selector(selector) # # set_register_handler: A public method for setting a custom register # handler. This allows trapping register touches # def set_register_handler(self, register, handler): # We only allow names via this method if not isinstance(register, str): print "[!] Cant understand register of type %s" % type(register) return False # Store the handler register = register.upper() self.register_handlers[register] = handler return True # # set_mnemonic_handler: A public method for setting a custom mnemonic # handler. This allows the user to trap on # execution of a specified mnemonic # def set_mnemonic_handler(self, mnemonic, handler): # We only allow the string representation of the mnemonic if not isinstance(mnemonic, str): print "[!] Cant understand mnemonic of type %s" % type(mnemonic) return False # Store the handler mnemonic = mnemonic.upper() self.mnemonic_handlers[mnemonic] = handler return True # # set_opcode_handler: A public method for setting a custom handler # for opcodes. This allows a user to trap on # the specified opcode. # def set_opcode_handler(self, opcode, handler): # We only allow opcodes by integer if not isinstance(opcode, int) and not isinstance(opcode, long): print "[!] Cant understand opcode of type %s" % type(opcode) return False # Store the handler self.opcode_handlers[opcode] = handler return True # # set_pc_handler: A public method for setting a custom handler on # the instruction pointer. A quasi breakpoint # returning execution to the user at a specified # address. # def set_pc_handler(self, address, handler): # We only allow integer addresses if not isinstance(address, int) and not isinstance(address, long): print "[!] Cant understand address of type %s" % type(address) return False # Store the handler self.pc_handlers[address] = handler # # set_exception_handler: A public method for setting a custom # handler for any exceptions that may happen # currently we are only handling GP/DE faults # def set_exception_handler(self, exception, handler): # We only allow string values if not isinstance(exception, str): print "[!] Cant understand exception of type %s" % type(exception) return False # Store the handler self.exception_handlers[exception] = handler # # set_library_handler: A public method for setting a custom # handler for any import function that # gets called # def set_library_handler(self, function, handler): # We only allow string values if not isinstance(function, str): print "[!] Cant understand function of type %s" % type(function) return False # Store the handler self.library_handlers[function] = handler # # set_interrupt_handler: A public method for setting a custom # handler for any interrupts that may happen # def set_interrupt_handler(self, interrupt, handler): # We only allow int values if not isinstance(exception, int) and not isinstance(exception, long): print "[!] Cant understand interrupt of type %s" % type(interrupt) return False # Store the handler self.interrupt_handlers[interrupt] = handler # # set_memory_handler: A public method for setting a custom handler # for specific memory access. This allows a user # to receive execution when a specified address # is accessed. # def set_memory_handler(self, address, handler): # We only allow integer addresses if not isinstance(address, int) and not isinstance(address, long): print "[!] Cant understand address of type %s" % type(address) return False # Store the handler self.memory_handlers[address] = handler # # set_memory_read_handler: A public memory for setting a custom handler # for *any* read of memory. # def set_memory_read_handler(self, handler): # Store the handler self.memory_read_handler = handler return True # # set_memory_write_handler: A public memory for setting a custom handler # for *any* write of memory. # def set_memory_write_handler(self, handler): # Store the handler self.memory_write_handler = handler return True # # set_memory_access_handler: A public memory for setting a custom handler # for *any* read or write of memory. # def set_memory_access_handler(self, handler): # Store the handler self.memory_access_handler = handler return True # # set_stack_read_handler: A public memory for setting a custom handler # for *any* stack read. # def set_stack_read_handler(self, handler): # Store the handler self.stack_read_handler = handler return True # # set_stack_write_handler: A public memory for setting a custom handler # for *any* stack write. # def set_stack_write_handler(self, handler): # Store the handler self.stack_write_handler = handler return True # # set_stack_access_handler: A public memory for setting a custom handler # for *any* stack read or write. # def set_stack_access_handler(self, handler): # Store the handler self.stack_access_handler = handler return True # # set_heap_read_handler: A public memory for setting a custom handler # for *any* heap read. # def set_heap_read_handler(self, handler): # Store the handler self.heap_read_handler = handler return True # # set_heap_write_handler: A public memory for setting a custom handler # for *any* heap write. # def set_heap_write_handler(self, handler): # Store the handler self.heap_write_handler = handler return True # # set_heap_access_handler: A public memory for setting a custom handler # for *any* heap read or write. # def set_heap_access_handler(self, handler): # Store the handler self.heap_access_handler = handler return True # # dump_regs: A public method to dump the regs from the CPU # def dump_regs(self): self.cpu.dump_regs() # # dump_stack: A public method to dump the stack from EBP # def dump_stack(self, count=64): self.cpu.dump_stack(count) # # get_disasm: A public method to get a pretty dump of the current # instruction disassembly def get_disasm(self): return self.cpu.get_disasm()
class PyEmu: DEBUG = 0 def __init__(self): # Holds a instance of our PyCPU class self.cpu = None # Holds an instance of our PyOS class self.os = None # Tells the emulator whether we are emulating self.emulating = True # Whether to use a frame pointer for stack offsets self.frame_pointer = True # Class members to hold stack and heap limits self.stack_base = 0x0 self.stack_size = 0x0 self.heap_base = 0x0 self.heap_size = 0x0 # Holds an instance of our PyMemory class self.memory = "" # A list of names for public methods self.register_names = {} self.stack_variable_names = {} self.stack_argument_names = {} # A list of our user handlers for various aspects of emulation self.mnemonic_handlers = {} self.opcode_handlers = {} self.register_handlers = {} self.pc_handlers = {} self.exception_handlers = {} self.interrupt_handlers = {} self.library_handlers = {} self.memory_handlers = {} self.memory_read_handler = None self.memory_write_handler = None self.memory_access_handler = None self.stack_read_handler = None self.stack_write_handler = None self.stack_access_handler = None self.heap_read_handler = None self.heap_write_handler = None self.heap_access_handler = None # Instantiate a CPU for use in the emulator self.cpu = PyCPU(self) # Determine which os we are on to instantiate the proper PyOS if os.name == 'nt': self.os = PyWindows() elif os.name == 'posix': # Yea I realize self.os = PyLinux() # # raise_exception: This method gets called when an exception happens # Currently we only care about general protection # faults (invalid memory access). We will throw a # Python exception when this occurs (I want to change # this). # def raise_exception(self, exception, address): # User must raise their own exception if exception in self.exception_handlers: self.exception_handlers[exception](self, exception, address, self.cpu.EIP) else: if self.DEBUG > 0: print "\n" print "*" * 72 print "* A %s fault has occured at 0x%08x" % (exception, address) print "*" * 72 self.dump_regs() self.dump_stack() raise RuntimeError("The memory requested was invalid") return False # # debug: A public method for setting global debug levels # def debug(self, level): self.DEBUG = level # Propigate the debug levels throughout self.memory.set_debug(level) self.cpu.set_debug(level) self.os.set_debug(level) # # execute: A public method for executing instructions # def execute(self, steps=1, start=0x0, end=0x0): if not isinstance(steps, int) or not isinstance(start, int) or not isinstance(end, int): return False # If we are called we are emulating self.emulating = True # Set the instruction pointer to the user supplied address if start: self.cpu.set_register32("EIP", start) # Set a stopping point if supplied so we can break if end: if steps > 1: while self.cpu.get_register32("EIP") != end and steps: if not self.emulating: return False if not self.cpu.execute(): print "[!] Problem executing (steps>0)" return False steps -= 1 else: while self.cpu.get_register32("EIP") != end: if not self.emulating: return False if not self.cpu.execute(): print "[!] Problem executing (steps=0)" return False else: for x in range(steps): if not self.emulating: return False if not self.cpu.execute(): print "[!] Problem executing (steps without end)" return False return True # # get_register: A public method to retrieve a register for the user # def get_register(self, register): register = register.upper() # We are smart about the requested register automatically # determining the proper register size # 32 bit registers if re.compile('^E[A-X]{2}$', re.IGNORECASE).match(register): result = self.cpu.get_register32(register) # 16 bit registers elif re.compile('^[ABCD]X$', re.IGNORECASE).match(register): result = self.cpu.get_register16(register) # 8 bit registers elif re.compile('^[ABCD]{1,}[LH]{1}$', re.IGNORECASE).match(register): result = self.cpu.get_register8(register) # Segment registers elif re.compile('^[CSDEFG]{1}S$', re.IGNORECASE).match(register): result = self.cpu.get_register16(register) # Flags elif re.compile('^[CPAZSTIDPR]{1}F$', re.IGNORECASE).match(register) or register in ["IOPL","NT","VM","AC","VIF","VIP","ID"]: result = self.cpu.get_register8(register) # Check to make sure the user isnt requesting by name else: if register in self.register_names: result = self.cpu.get_register(self.register_names[register]["name"], self.register_names[register]["size"]) else: print "[!] Couldnt determine register" return False return result # # set_register: A public method for setting a registers value # from a script. # def set_register(self, register, value, name=""): # Make sure its a valid value if not isinstance(value, int) and not isinstance(value, long): print "[!] Dont know how to use non-int value %s" % type(value) return False register = register.upper() name = name.upper() # We are smart about the requested register automatically # determining the proper register size # 32 bit registers if re.compile('^E[A-X]{2}$', re.IGNORECASE).match(register): if name: self.register_names[name] = {"name": register, "size": 4} # Try and set the register if not self.cpu.set_register32(register, value): print "[!] Problem setting register" return False # 16 bit registers elif re.compile('^[ABCD]X$', re.IGNORECASE).match(register): if name: self.register_names[name] = {"name": register, "size": 2} # Try and set the register if not self.cpu.set_register16(register, value): print "[!] Problem setting register" return False # 8 bit registers elif re.compile('^[ABCD]{1,}[LH]{1}$', re.IGNORECASE).match(register): if name: self.register_names[name] = {"name": register, "size": 1} # Try and set the register if not self.cpu.set_register8(register, value): print "[!] Problem setting register" return False # Segment registers elif re.compile('^[CSDEFG]{1}S$', re.IGNORECASE).match(register): if name: self.register_names[name] = {"name": register, "size": 2} # Try and set the register if not self.cpu.set_register16(register, value): print "[!] Problem setting register" return False # Flags elif re.compile('^[CPAZSTIDPR]{1}F$', re.IGNORECASE).match(register) or register in ["IOPL","NT","VM","AC","VIF","VIP","ID"]: if name: self.register_names[name] = {"name": register, "size": 1} # Try and set the register if not self.cpu.set_register8(register, value): print "[!] Problem setting register" return False # Check to make sure the user isnt requesting by name else: if name in self.register_names: # Try and set the register if not self.cpu.set_register(self.register_names[name]["name"], self.register_names[name]["size"]): print "[!] Problem setting register" return False else: print "[!] Couldnt determine register size" return False return True # # get_stack_variable: A public method for setting stack local variables # def get_stack_variable(self, offset, size=0): # Validate the type of argument to determine offset or name if isinstance(offset, str): offset = offset.upper() # Check if we have the name if offset not in self.stack_variable_names: print "[!] Couldnt find name %s" % offset return False else: # Retrieve the offset associated offset = self.stack_variable_names[offset] elif not isinstance(offset, int) and not isinstance(offset, long): print "[!] Dont understand %s type" % type(offset) return False # If we dont have a size default to a dword if not size: size = 4 # Check if we are using frame pointers for offsets if self.frame_pointer: address = self.cpu.get_register32("EBP") - offset else: address = self.cpu.get_register32("ESP") + offset # Fetch the address requested from the memory manager result = self.memory.get_memory(address, size) # Return the value return result # # set_stack_variable: A public method for setting a local stack variable # def set_stack_variable(self, offset, value, size=0, name=""): # Make sure our offset is a valid type if not isinstance(offset, int) and not isinstance(offset, long): print "[!] Offset must be int not %s" % type(offset) return False # Automagically determine a size for the supplied string if isinstance(value, str): if not size: size = len(value) else: # Truncate the string if necessary value = value[:size] elif isinstance(value, int) or isinstance(value, long): if not size: size = 4 # If we are setting a name store it in the names list if name: name = name.upper() self.stack_variable_names[name] = offset # Check for a frame pointer to get the proper offset if self.frame_pointer: address = self.cpu.get_register32("EBP") - offset else: address = self.cpu.get_register32("ESP") + offset # Set the value in memory via the memory manager if not self.set_memory(address, value, size): print "[!] Failed setting memory @ %x" % (address) return False return True # # get_stack_argument: A public method to get a functions stack argument # def get_stack_argument(self, offset, size=0): # If we are asking by name check it if isinstance(offset, str): offset = offset.upper() if offset not in self.stack_variable_names: print "[!] Couldnt find name %s" % offset return False else: # Return the offset associated offset = self.stack_variable_names[offset] elif not isinstance(offset, int) and not isinstance(offset, long): print "[!] Dont understand %s type" % type(offset) return False # We only handle dword arguments for now size = 4 # Check for frame pointer to get the proper stack address if self.frame_pointer: address = self.cpu.get_register32("EBP") + offset else: address = self.cpu.get_register32("ESP") + offset # Retrieve the value from memory via the memory manager result = self.memory.get_memory(address, size) return result # # set_stack_argument: A public method to set up a stack argument # def set_stack_argument(self, offset, value, name=""): # Ensure the offset is proper if not isinstance(offset, int) and not isinstance(offset, long): print "[!] Offset must be int not %s" % type(offset) return False # Only dword arguments for now size = 4 # If we have a name we need to get the associated offset if name: name = name.upper() self.stack_variable_names[name] = offset # Check the frame pointer and get the proper address if self.frame_pointer: address = self.cpu.get_register32("EBP") + offset else: address = self.cpu.get_register32("ESP") + offset # Store the value on the stack if not self.set_memory(address, value, size): print "[!] Failed setting memory @ %x" % (address) return False return True # # get_memory: A public method for fetching arbitrary memory # def get_memory(self, address, size=0): if not size: size = 4 # Fetch the value result = self.memory.get_memory(address, size) return result # # get_memory_string: A public method to fetch a string from memory # def get_memory_string(self, address): s = "" x = 0 while True: b = self.get_memory(address + x, size=1) if b != 0x00: s += chr(b) else: break x += 1 return s # # set_memory: A public method for setting arbitrary memory # def set_memory(self, address, value, size=0): # If we are using a string calculate the size if isinstance(value, str): if not size: size = len(value) else: value = value[:size] elif isinstance(value, int) or isinstance(value, long): if not size: size = 4 else: print "[!] I dont know what this type is" return False # For right now we lower the fault so the user can set arbitraty memory self.memory.fault = False # Set the value into memory via the memory manager if not self.memory.set_memory(address, value, size): print "[!] Failed setting memory @ %x" % (address) return False self.memory.fault = True return True # # get_selector: A public method for fetching a selector from the LDT # def get_selector(self, selector): return self.os.get_selector(selector) # # set_register_handler: A public method for setting a custom register # handler. This allows trapping register touches # def set_register_handler(self, register, handler): # We only allow names via this method if not isinstance(register, str): print "[!] Cant understand register of type %s" % type(register) return False # Store the handler register = register.upper() self.register_handlers[register] = handler return True # # set_mnemonic_handler: A public method for setting a custom mnemonic # handler. This allows the user to trap on # execution of a specified mnemonic # def set_mnemonic_handler(self, mnemonic, handler): # We only allow the string representation of the mnemonic if not isinstance(mnemonic, str): print "[!] Cant understand mnemonic of type %s" % type(mnemonic) return False # Store the handler mnemonic = mnemonic.upper() self.mnemonic_handlers[mnemonic] = handler return True # # set_opcode_handler: A public method for setting a custom handler # for opcodes. This allows a user to trap on # the specified opcode. # def set_opcode_handler(self, opcode, handler): # We only allow opcodes by integer if not isinstance(opcode, int) and not isinstance(opcode, long): print "[!] Cant understand opcode of type %s" % type(opcode) return False # Store the handler self.opcode_handlers[opcode] = handler return True # # set_pc_handler: A public method for setting a custom handler on # the instruction pointer. A quasi breakpoint # returning execution to the user at a specified # address. # def set_pc_handler(self, address, handler): # We only allow integer addresses if not isinstance(address, int) and not isinstance(address, long): print "[!] Cant understand address of type %s" % type(address) return False # Store the handler self.pc_handlers[address] = handler # # set_exception_handler: A public method for setting a custom # handler for any exceptions that may happen # currently we are only handling GP/DE faults # def set_exception_handler(self, exception, handler): # We only allow string values if not isinstance(exception, str): print "[!] Cant understand exception of type %s" % type(exception) return False # Store the handler self.exception_handlers[exception] = handler # # set_library_handler: A public method for setting a custom # handler for any import function that # gets called # def set_library_handler(self, function, handler): # We only allow string values if not isinstance(function, str): print "[!] Cant understand function of type %s" % type(function) return False # Store the handler self.library_handlers[function] = handler # # set_interrupt_handler: A public method for setting a custom # handler for any interrupts that may happen # def set_interrupt_handler(self, interrupt, handler): # We only allow int values if not isinstance(exception, int) and not isinstance(exception, long): print "[!] Cant understand interrupt of type %s" % type(interrupt) return False # Store the handler self.interrupt_handlers[interrupt] = handler # # set_memory_handler: A public method for setting a custom handler # for specific memory access. This allows a user # to receive execution when a specified address # is accessed. # def set_memory_handler(self, address, handler): # We only allow integer addresses if not isinstance(address, int) and not isinstance(address, long): print "[!] Cant understand address of type %s" % type(address) return False # Store the handler self.memory_handlers[address] = handler # # set_memory_read_handler: A public memory for setting a custom handler # for *any* read of memory. # def set_memory_read_handler(self, handler): # Store the handler self.memory_read_handler = handler return True # # set_memory_write_handler: A public memory for setting a custom handler # for *any* write of memory. # def set_memory_write_handler(self, handler): # Store the handler self.memory_write_handler = handler return True # # set_memory_access_handler: A public memory for setting a custom handler # for *any* read or write of memory. # def set_memory_access_handler(self, handler): # Store the handler self.memory_access_handler = handler return True # # set_stack_read_handler: A public memory for setting a custom handler # for *any* stack read. # def set_stack_read_handler(self, handler): # Store the handler self.stack_read_handler = handler return True # # set_stack_write_handler: A public memory for setting a custom handler # for *any* stack write. # def set_stack_write_handler(self, handler): # Store the handler self.stack_write_handler = handler return True # # set_stack_access_handler: A public memory for setting a custom handler # for *any* stack read or write. # def set_stack_access_handler(self, handler): # Store the handler self.stack_access_handler = handler return True # # set_heap_read_handler: A public memory for setting a custom handler # for *any* heap read. # def set_heap_read_handler(self, handler): # Store the handler self.heap_read_handler = handler return True # # set_heap_write_handler: A public memory for setting a custom handler # for *any* heap write. # def set_heap_write_handler(self, handler): # Store the handler self.heap_write_handler = handler return True # # set_heap_access_handler: A public memory for setting a custom handler # for *any* heap read or write. # def set_heap_access_handler(self, handler): # Store the handler self.heap_access_handler = handler return True # # dump_regs: A public method to dump the regs from the CPU # def dump_regs(self): self.cpu.dump_regs() # # dump_stack: A public method to dump the stack from EBP # def dump_stack(self, count=64): self.cpu.dump_stack(count) # # get_disasm: A public method to get a pretty dump of the current # instruction disassembly def get_disasm(self): return self.cpu.get_disasm()