def below(ea, includeSegment=False): '''Display all the functions that the function at /ea/ can call''' tryhard = lambda ea: "{:s}+{:x}".format(database.name(function.top( ea)), ea - function.top(ea)) if function.within( ea) else "+{:x}".format(ea) if database.name( ea) is None else database.name(ea) return '\n'.join( ':'.join((segment.name(ea), tryhard(ea)) if includeSegment else (tryhard(ea), )) for ea in function.down(ea))
def enter(self, pc, options): options['database'].address(pc)['name'] = database.name(pc) xrefs_to = database.cxup(pc) func_top = pc for x in xrefs_to: xref_top = function.top(x) context = options['database'].c(xref_top) context.address(x).edge((func_top, func_top)) return
def prototype(key=None): '''Returns the full prototype of the function identified by fn.''' rt,ea = __addressOfRtOrSt(ui.current.address() if key is None else key) funcname = database.name(ea) try: res = internal.declaration.function(ea) idx = res.find('(') result = res[:idx] + ' ' + funcname + res[idx:] except ValueError: if not funcname.startswith('?'): raise result = internal.declaration.demangle(funcname) return result
def makecall(ea=None, target=None): """Output the function call at `ea` and its arguments with the address they originated from. If `target` is specified, then assume that the instruction is calling `target` instead of the target address that the call is referencing. """ ea = current.address() if ea is None else ea if not func.contains(ea, ea): return None if database.config.bits() != 32: raise RuntimeError("{:s}.makecall({!r}, {!r}) : Unable to determine arguments for {:s} due to {:d}-bit calling convention.".format(__name__, ea, target, database.disasm(ea), database.config.bits())) if target is None: # scan down until we find a call that references something chunk, = ((l, r) for l, r in func.chunks(ea) if l <= ea <= r) result = [] while (len(result) < 1) and ea < chunk[1]: # FIXME: it's probably not good to just scan for a call if not database.instruction(ea).startswith('call '): ea = database.next(ea) continue result = database.cxdown(ea) if len(result) == 0: raise TypeError("{:s}.makecall({!r}, {!r}) : Unable to determine number of arguments.".format(__name__, ea, target)) if len(result) != 1: raise ValueError("{:s}.makecall({!r}, {!r}) : An invalid number of targets was returned for the call at {:#x}. The call targets that were returned are {!r}.".format(__name__, ea, result)) fn, = result else: fn = target try: result = [] for offset, name, size in func.arguments(fn): left = database.address.prevstack(ea, offset + database.config.bits() // 8) # FIXME: if left is not an assignment or a push, find last assignment result.append((name, left)) except internal.exceptions.OutOfBoundsError: raise internal.exceptions.OutOfBoundserror("{:s}.makecall({!r}, {!r}) : Unable to get arguments for target function.".format(__name__, ea, target)) # FIXME: replace these crazy list comprehensions with something more comprehensible. # result = ["{:s}={:s}".format(name, instruction.op_repr(ea, 0)) for name, ea in result] result = ["({:#x}){:s}={:s}".format(ea, name, ':'.join(instruction.op_repr(database.address.prevreg(ea, instruction.op_value(ea, 0), write=True), n) for n in instruction.opsi_read(database.address.prevreg(ea, instruction.op_value(ea, 0), write=True))) if instruction.op_type(ea, 0) == 'reg' else instruction.op_repr(ea, 0)) for name, ea in result] try: return "{:s}({:s})".format(internal.declaration.demangle(func.name(func.by_address(fn))), ','.join(result)) except: pass return "{:s}({:s})".format(internal.declaration.demangle(database.name(fn)), ','.join(result))
def makecall(ea=None, target=None): """Output the function call at `ea` and its arguments with the address they originated from. If `target` is specified, then assume that the instruction is calling `target` instead of the target address that the call is referencing. """ ea = current.address() if ea is None else ea if not func.contains(ea, ea): return None if database.config.bits() != 32: raise RuntimeError("{:s}.makecall({!r}, {!r}) : Unable to determine arguments for {:s} due to {:d}-bit calling convention.".format(__name__, ea, target, database.disasm(ea), database.config.bits())) if target is None: # scan down until we find a call that references something chunk, = ((l, r) for l, r in func.chunks(ea) if l <= ea <= r) result = [] while (len(result) < 1) and ea < chunk[1]: # FIXME: it's probably not good to just scan for a call if not database.instruction(ea).startswith('call '): ea = database.next(ea) continue result = database.cxdown(ea) if len(result) == 0: raise TypeError("{:s}.makecall({!r}, {!r}) : Unable to determine number of arguments.".format(__name__, ea, target)) if len(result) != 1: raise ValueError("{:s}.makecall({!r}, {!r}) : An invalid number of targets was returned for the call at {:#x}. The call targets that were returned are {!r}.".format(__name__, ea, result)) fn, = result else: fn = target try: result = [] for offset, name, size in func.arguments(fn): left = database.address.prevstack(ea, offset+database.config.bits()/8) # FIXME: if left is not an assignment or a push, find last assignment result.append((name, left)) except internal.exceptions.OutOfBoundsError: raise internal.exceptions.OutOfBoundserror("{:s}.makecall({!r}, {!r}) : Unable to get arguments for target function.".format(__name__, ea, target)) # FIXME: replace these crazy list comprehensions with something more comprehensible. # result = ["{:s}={:s}".format(name, instruction.op_repr(ea, 0)) for name, ea in result] result = ["({:#x}){:s}={:s}".format(ea, name, ':'.join(instruction.op_repr(database.address.prevreg(ea, instruction.op_value(ea, 0), write=1), n) for n in instruction.ops_read(database.address.prevreg(ea, instruction.op_value(ea, 0), write=1))) if instruction.op_type(ea, 0) == 'reg' else instruction.op_repr(ea, 0)) for name, ea in result] try: return "{:s}({:s})".format(internal.declaration.demangle(func.name(func.by_address(fn))), ','.join(result)) except: pass return "{:s}({:s})".format(internal.declaration.demangle(database.name(fn)), ','.join(result))
def _collectcall(addr, result): process = set() for f in func.down(addr): if any(f in coll for coll in (result, sentinel)): continue if not func.within(f): logging.warn( "{:s}.collectcall({:#x}, {!r}) : Adding non-function address {:#x} ({:s})." .format(__name__, ea, sentinel, f, database.name(f))) result.add(f) continue process.add(f) for addr in process: result |= _collectcall(addr, result | process) return result
def name(key=None, name=None): '''Returns the name of the function or import identified by key.''' rt,ea = __addressOfRtOrSt(ui.current.address() if key is None else key) if rt: if name is None: res = idaapi.get_name(-1, ea) return internal.declaration.extract.fullname(internal.declaration.demangle(res)) if res.startswith('?') else res # FIXME: shuffle the new name into the prototype and then re-mangle it return database.name(ea, name) if name is None: res = idaapi.get_func_name(ea) if not res: res = idaapi.get_name(-1, ea) if not res: res = idaapi.get_true_name(ea, ea) return internal.declaration.extract.fullname(internal.declaration.demangle(res)) if res.startswith('?') else res #return internal.declaration.extract.name(internal.declaration.demangle(res)) if res.startswith('?') else res return idaapi.set_name(ea, name, idaapi.SN_PUBLIC)
def makecall(ea=None, target=None): ea = current.address() if ea is None else ea if not function.contains(ea, ea): return None if database.config.bits() != 32: raise RuntimeError( "{:s}.makecall({!r},{!r}) : Unable to determine arguments for {:s} due to {:d}-bit calling convention." .format(__name__, ea, target, database.disasm(ea), database.config.bits())) if target is None: # scan down until we find a call that references something chunk, = ((l, r) for l, r in function.chunks(ea) if l <= ea <= r) result = [] while (len(result) < 1) and ea < chunk[1]: # FIXME: it's probably not good to just scan for a call if not database.instruction(ea).startswith('call '): ea = database.next(ea) continue result = database.cxdown(ea) if len(result) == 0: raise TypeError( "{:s}.makecall({!r},{!r}) : Unable to determine number of arguments" .format(__name__, ea, target)) if len(result) != 1: raise ValueError( "{:s}.makecall({!r},{!r}) : Too many targets for call at {:x} : {!r}" .format(__name__, ea, result)) fn, = result else: fn = target try: result = [] for offset, name, size in function.arguments(fn): left, _ = function.stack_window( ea, offset + database.config.bits() / 8) # FIXME: if left is not an assignment or a push, find last assignment result.append((name, left)) except LookupError: raise LookupError( "{:s}.makecall({!r},{!r}) : Unable to get arguments for target function" .format(__name__, ea, target)) # FIXME: replace these crazy list comprehensions with something more comprehensible. # result = ["{:s}={:s}".format(name,ins.op_repr(ea, 0)) for name,ea in result] result = [ "({:x}){:s}={:s}".format( ea, name, ':'.join( ins.op_repr( database.address.prevreg(ea, ins.op_value(ea, 0), write=1), n) for n in ins.ops_read( database.address.prevreg(ea, ins.op_value(ea, 0), write=1)) ) if ins.op_type(ea, 0) == 'reg' else ins.op_repr(ea, 0)) for name, ea in result ] try: return "{:s}({:s})".format( internal.declaration.demangle( function.name(function.by_address(fn))), ','.join(result)) except: pass return "{:s}({:s})".format( internal.declaration.demangle(database.name(fn)), ','.join(result))
def below(ea): '''Display all the functions that the function at /ea/ can call''' tryhard = lambda x: '%s+%x'%(database.name(function.top(x)),x-function.top(x)) if function.within(x) else hex(x) if database.name(x) is None else database.name(x) return '\n'.join(map(tryhard,function.down(ea)))
def above(ea): '''Display all the callers of the function at /ea/''' tryhard = lambda x: '%s+%x'%(database.name(function.top(x)),x-function.top(x)) if function.within(x) else hex(x) if database.name(x) is None else database.name(x) return '\n'.join(map(tryhard,function.up(ea)))
def _collectcall(addr, result): process = set() for f in func.down(addr): if any(f in coll for coll in (result, sentinel)): continue if not func.within(f): logging.warn("{:s}.collectcall({:#x}, {!r}) : Adding non-function address {:#x} ({:s}).".format(__name__, ea, sentinel, f, database.name(f))) result.add(f) continue process.add(f) for addr in process: result |= _collectcall(addr, result | process) return result
def below(ea): '''Display all the functions that the function at /ea/ can call''' tryhard = lambda x: '%s+%x' % (database.name(function.top( x)), x - function.top(x)) if function.within(x) else hex( x) if database.name(x) is None else database.name(x) return '\n'.join(map(tryhard, function.down(ea)))
def above(ea): '''Display all the callers of the function at /ea/''' tryhard = lambda x: '%s+%x' % (database.name(function.top( x)), x - function.top(x)) if function.within(x) else hex( x) if database.name(x) is None else database.name(x) return '\n'.join(map(tryhard, function.up(ea)))