importosimportreimportloggingimportclaripyimportbinasciifrom.pluginimportSimStatePluginfrom..errorsimportSimStateErrorl=logging.getLogger(name=__name__)# global heap_location
[docs]classGDB(SimStatePlugin):""" Initialize or update a state from gdb dumps of the stack, heap, registers and data (or arbitrary) segments. """
[docs]def__init__(self,omit_fp=False,adjust_stack=False):""" :param omit_fp: The frame pointer register is used for something else. (i.e. --omit_frame_pointer) :param adjust_stack: Use different stack addresses than the gdb session (not recommended). """SimStatePlugin.__init__(self)# The stack top from gdb's sessionself.real_stack_top=0# Is the binary compiled with --omit_frame_pointer ?self.omit_fp=omit_fp# Adjust the stack w.r.t. the real stack (from the gdb session)self.adjust_stack=adjust_stack
[docs]defset_stack(self,stack_dump,stack_top):""" Stack dump is a dump of the stack from gdb, i.e. the result of the following gdb command : ``dump binary memory [stack_dump] [begin_addr] [end_addr]`` We set the stack to the same addresses as the gdb session to avoid pointers corruption. :param stack_dump: The dump file. :param stack_top: The address of the top of the stack in the gdb session. """data=self._read_data(stack_dump)self.real_stack_top=stack_topaddr=stack_top-len(data)# Address of the bottom of the stackl.info("Setting stack from 0x%x up to %#x",addr,stack_top)# FIXME: we should probably make we don't overwrite other stuff loaded thereself._write(addr,data)
[docs]defset_heap(self,heap_dump,heap_base):""" Heap dump is a dump of the heap from gdb, i.e. the result of the following gdb command: ``dump binary memory [stack_dump] [begin] [end]`` :param heap_dump: The dump file. :param heap_base: The start address of the heap in the gdb session. """# We set the heap at the same addresses as the gdb session to avoid pointer corruption.data=self._read_data(heap_dump)self.state.heap.heap_location=heap_base+len(data)addr=heap_basel.info("Set heap from 0x%x to %#x",addr,addr+len(data))# FIXME: we should probably make we don't overwrite other stuff loaded thereself._write(addr,data)
[docs]defset_data(self,addr,data_dump):""" Update any data range (most likely use is the data segments of loaded objects) """data=self._read_data(data_dump)l.info("Set data from 0x%x to %#x",addr,addr+len(data))self._write(addr,data)
[docs]defset_regs(self,regs_dump):""" Initialize register values within the state :param regs_dump: The output of ``info registers`` in gdb. """ifself.real_stack_top==0andself.adjust_stackisTrue:raiseSimStateError("You need to set the stack first, or set""adjust_stack to False. Beware that in this case, sp and bp won't be updated")data=self._read_data(regs_dump)rdata=re.split(b"\n",data)forrinrdata:ifr==b"":continuereg=re.split(b" +",r)[0].decode()val=int(re.split(b" +",r)[1],16)try:self.state.registers.store(reg,claripy.BVV(val,self.state.arch.bits))# Some registers such as cs, ds, eflags etc. aren't supported in angrexceptKeyErrorase:l.warning("Reg %s was not set",e)self._adjust_regs()
def_adjust_regs(self):""" Adjust bp and sp w.r.t. stack difference between GDB session and angr. This matches sp and bp registers, but there is a high risk of pointers inconsistencies. """ifnotself.adjust_stack:returnbp=self.state.arch.register_names[self.state.arch.bp_offset]sp=self.state.arch.register_names[self.state.arch.sp_offset]stack_shift=self.state.arch.initial_sp-self.real_stack_topself.state.registers.store(sp,self.state.regs.sp+stack_shift)ifnotself.omit_fp:self.state.registers.store(bp,self.state.regs.bp+stack_shift)@staticmethoddef_read_data(path):ifnotos.path.exists(path):raiseSimStateError("File does not exist")f=open(path,"rb")returnf.read()def_write(self,addr,data):self.state.memory.store(addr,data)@staticmethoddef_to_bvv(data):sz=len(data)num=int(binascii.hexlify(data),16)returnclaripy.BVV(num,sz)@SimStatePlugin.memodefcopy(self,memo):# pylint: disable=unused-argumentreturnGDB()