def makecall(ea): if not function.contains(ea, ea): return 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 instruction(ea).startswith('call '): ea = next(ea) continue result = cxdown(ea) if len(result) != 1: raise ValueError('Invalid code reference: %x %s'% (ea,repr(result))) fn, = result result = [] for offset,name,size in function.getArguments(fn): left,_ = function.stackwindow(ea, offset+config.bits()/8) # FIXME: if left is not an assignment or a push, find last assignment result.append((name,left)) result = ['%s=%s'%(name,_instruction.op_repr(ea,0)) for name,ea in result] return '%s(%s)'%(internal.declaration.demangle(function.name(function.byAddress(fn))), ','.join(result))
def del_func(pfn): global State if State != state.ready: return # convert all contents into globals for l, r in function.chunks(pfn): for ea in database.address.iterate(l, r): for k in database.tag(ea): internal.comment.contents.dec( ea, k, target=interface.range.start(pfn)) internal.comment.globals.inc(ea, k) logging.debug( u"{:s}.del_func({:#x}) : Exchanging (increasing) refcount for global tag {!s} and (decreasing) refcount for contents tag {!s}." .format(__name__, interface.range.start(pfn), utils.string.repr(k), utils.string.repr(k))) continue continue # remove all function tags for k in function.tag(interface.range.start(pfn)): internal.comment.globals.dec(interface.range.start(pfn), k) logging.debug( u"{:s}.del_func({:#x}) : Removing (global) tag {!s} from function." .format(__name__, interface.range.start(pfn), utils.string.repr(k))) return
def __process_functions(): p = ui.progress() globals = internal.comment.globals.address() funcs = list(database.functions()) p.update(current=0, max=len(funcs), title="Pre-building tagcache...") p.open() for i, fn in enumerate(funcs): chunks = list(function.chunks(fn)) text = functools.partial("{:x} : Processing function {:d} of {:d} : ({:d} chunk{:s})".format, fn, i, len(funcs)) p.update(current=i) contents = set(internal.comment.contents.address(fn)) for ci, (l, r) in enumerate(chunks): p.update(text=text(len(chunks), 's' if len(chunks) != 1 else ''), tooltip="Chunk #{:d} : {:x} - {:x}".format(ci, l, r)) for ea in database.iterate(l, r): # FIXME: no need to iterate really since we should have # all of the addresses for k, v in database.tag(ea).iteritems(): if ea in globals: internal.comment.globals.dec(ea, k) if ea not in contents: internal.comment.contents.inc(ea, k, target=fn) continue continue continue p.close()
def makecall(ea): if not function.contains(ea, ea): return 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 instruction(ea).startswith('call '): ea = next(ea) continue result = cxdown(ea) if len(result) != 1: raise ValueError('Invalid code reference: %x %s' % (ea, repr(result))) fn, = result result = [] for offset, name, size in function.getArguments(fn): left, _ = function.stackwindow(ea, offset + config.bits() / 8) # FIXME: if left is not an assignment or a push, find last assignment result.append((name, left)) result = [ '%s=%s' % (name, _instruction.op_repr(ea, 0)) for name, ea in result ] return '%s(%s)' % (_declaration.demangle( function.name(function.byAddress(fn))), ','.join(result))
def __process_functions(percentage=0.10): p = ui.Progress() globals = set(internal.comment.globals.address()) total = 0 funcs = list(database.functions()) p.update(current=0, max=len(funcs), title=u"Pre-building tagcache...") p.open() six.print_(u"Pre-building tagcache for {:d} functions.".format(len(funcs))) for i, fn in enumerate(funcs): chunks = list(function.chunks(fn)) text = functools.partial(u"Processing function {:#x} ({chunks:d} chunk{plural:s}) -> {:d} of {:d}".format, fn, i + 1, len(funcs)) p.update(current=i) ui.navigation.procedure(fn) if i % (int(len(funcs) * percentage) or 1) == 0: six.print_(u"Processing function {:#x} -> {:d} of {:d} ({:.02f}%)".format(fn, i+1, len(funcs), i / float(len(funcs)) * 100.0)) contents = set(internal.comment.contents.address(fn)) for ci, (l, r) in enumerate(chunks): p.update(text=text(chunks=len(chunks), plural='' if len(chunks) == 1 else 's'), tooltip="Chunk #{:d} : {:#x} - {:#x}".format(ci, l, r)) ui.navigation.analyze(l) for ea in database.address.iterate(l, r): # FIXME: no need to iterate really since we should have # all of the addresses for k, v in six.iteritems(database.tag(ea)): if ea in globals: internal.comment.globals.dec(ea, k) if ea not in contents: internal.comment.contents.inc(ea, k, target=fn) total += 1 continue continue continue six.print_(u"Successfully built tag-cache composed of {:d} tag{:s}.".format(total, '' if total == 1 else 's')) p.close()
def locationToAddress(loc): '''Convert the function location `loc` back into an address.''' ## if location is a tuple, then convert it to an address if isinstance(loc, tuple): f, cid, ofs = loc base, _ = next(b for i, b in enumerate(func.chunks(f)) if i == cid) return base + ofs ## otherwise, it's already an address return loc
def locationToAddress(loc): '''Convert the function location `loc` back into an address.''' ## if location is a tuple, then convert it to an address if isinstance(loc, tuple): f, cid, ofs = loc base, _ = next(b for i, b in enumerate(func.chunks(f)) if i == cid) return base + ofs ## otherwise, it's already an address return loc
def addressToLocation(ea, chunks=None): """Convert the address `ea` to a `(function, id, offset)`. The fields `id` and `offset` represent the chunk index and the offset into the chunk for the function at `ea`. If the list `chunks` is specified as a parameter, then use it as a tuple of ranges in order to calculate the correct address. """ F, chunks = func.by(ea), chunks or [ch for ch in func.chunks(ea)] cid, base = next((i, l) for i, (l, r) in enumerate(chunks) if l <= ea < r) return func.top(F), cid, ea - base
def addressToLocation(ea, chunks=None): """Convert the address `ea` to a `(function, id, offset)`. The fields `id` and `offset` represent the chunk index and the offset into the chunk for the function at `ea`. If the list `chunks` is specified as a parameter, then use it as a tuple of ranges in order to calculate the correct address. """ F, chunks = func.by(ea), chunks or [ch for ch in func.chunks(ea)] cid, base = next((i, l) for i, (l, r) in enumerate(chunks) if l <= ea < r) return func.top(F), cid, ea - base
def add_func(pfn): global State if State != state.ready: return # convert all globals into contents for (l,r) in function.chunks(pfn): for ea in database.iterate(l, r): for k in database.tag(ea): internal.comment.globals.dec(ea, k) internal.comment.contents.inc(ea, k, target=pfn.startEA) continue continue return
def add_func(pfn): global State if State != state.ready: return # convert all globals into contents for l, r in function.chunks(pfn): for ea in database.address.iterate(l, r): for k in database.tag(ea): internal.comment.globals.dec(ea, k) internal.comment.contents.inc(ea, k, target=pfn.startEA) logging.debug("{:s}.add_func({:#x}) : Decreasing refcount for global tag {!r} and increasing refcount for contents tag {!r}".format(__name__, pfn.startEA, k, k)) continue continue return
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 del_func(pfn): global State if State != state.ready: return # convert all contents into globals for (l,r) in function.chunks(pfn): for ea in database.iterate(l, r): for k in database.tag(ea): internal.comment.contents.dec(ea, k, target=pfn.startEA) internal.comment.globals.inc(ea, k) continue continue # remove all function tags for k in function.tag(pfn.startEA): internal.comment.globals.dec(pfn.startEA, k) return
def contents(location=False): """Iterate through the contents tags for all the functions within the database. Each iteration yields a tuple of the format `(location, tags)` where `location` can be either an address or a chunk identifier and offset depending on whether `location` was specified as true or not. """ global read # Iterate through each function in the database for ea in db.functions(): # it's faster to precalculate the chunks here F, chunks = func.by(ea), [ch for ch in func.chunks(ea)] # Iterate through the function's contents yielding each tag for ea, res in read.content(ea): loc = addressToLocation(ea, chunks=chunks) if location else ea yield loc, res continue return
def contents(location=False): """Iterate through the contents tags for all the functions within the database. Each iteration yields a tuple of the format `(location, tags)` where `location` can be either an address or a chunk identifier and offset depending on whether `location` was specified as true or not. """ global read # Iterate through each function in the database for ea in db.functions(): # it's faster to precalculate the chunks here F, chunks = func.by(ea), [ch for ch in func.chunks(ea)] # Iterate through the function's contents yielding each tag for ea, res in read.content(ea): loc = addressToLocation(ea, chunks=chunks) if location else ea yield loc, res continue return
SetDelayed = pyml.function("SetDelayed") Set = pyml.function("Set") List = pyml.function("List") Hold = pyml.function("Hold") RuleDelayed = pyml.function("RuleDelayed") Rule = pyml.function("Rule") call = pyml.function("call") symcall = pyml.function("symcall") rules = [] max = len(database.functions()) for i,ea in enumerate(database.functions()): result = [] for l,r in function.chunks(ea): for x in database.iterate(l,r): address,size,insn = x,idc.ItemSize(x),idc.GetDisasm(x) insn = re.sub(" +", " ", insn) insn = insn.replace("short", "") insn = insn.replace("dword", "") insn = insn.replace("offset", "") insn = insn.replace("large", "") insn = insn.replace("ptr", "") insn = insn.replace("[", "") insn = insn.replace("]", "") if " " in insn: insn = insn.replace(" ", "|", 1) insn = insn.replace(",", "|") insn = insn.replace(" ", "") fn = insn.split("|")
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))