def find6b(h): for f in func.down(h): for ea in func.iterate(f): for opnum in ins.ops_count(ea): if ins.op_type(ea, opnum) == 'phrase' and ins.op( ea, opnum).offset == 0x6b: print(db.disasm(ea))
def sourcechain(fn, *args, **kwds): # sentinel = kwds.get('types', set(('imm','phrase','addr','void'))) sentinel = kwds.get('types', set(('imm', 'addr', 'void'))) result = {} for ea, opi in source(*args): if not function.contains(fn, ea): continue opt = tuple(ins.op_type(ea, i) for i in opi) for i, t in zip(opi, opt): if t in sentinel: result.setdefault(ea, set()).add(i) elif t in ('reg', ): result.setdefault(ea, set()).add(i) r = ins.op_value(ea, i) for a, b in sourcechain(fn, ea, r): map(result.setdefault(a, set()).add, b) elif t in ('phrase', ): result.setdefault(ea, set()).add(i) _, (r1, r2, _) = ins.op_value(ea, i) for a, b in sourcechain( fn, ea, *tuple(r for r in (r1, r2) if r is not None)): map(result.setdefault(a, set()).add, b) elif t in ( 'imm', 'addr', ): result.setdefault(ea, set()).add(i) else: raise ValueError, (t, ea, i) continue continue return [(ea, result[ea]) for ea in sorted(result.keys())]
def search_dyn_calls(addr, curr_addr_list=None, parents=None): dyn_call = namedtuple('dyn_call', ['call', 'parents']) hex = '{:x}'.format # print(hex(addr), curr_addr_list) if curr_addr_list == None: curr_addr_list = [addr] if parents == None: parents = [] calls = [] #print("Addr: {}".format(addr)) for ea in fn.iterate(addr): if not ins.isCall(ea): continue call = ins.op_value(ea, 0) # Don't cycle ourselves if call == addr: # print("Ignoring recursive loop on function: {}".format(hex(addr))) continue # Don't call functions we are currently looking into if call in curr_addr_list: continue """ .text:3F6E66AD 0B4 call ds:memmove Python>x = ins.op_value(h(), 0) Python>print(x.base) None .text:3F6E6208 008 call dword ptr [eax] Python>x.base <instruction.register.eax(0,dt_dword) 'eax' 0:+32> """ # we want non int/long for calls if isinstance(call, (int, long)) and not ins.op_type(ea, 0) in ('phrase'): # Only now call the function once curr_addr_list.append(call) new_parents = copy.deepcopy(parents) new_parents.append(ea) calls.extend( search_dyn_call(call, curr_addr_list=curr_addr_list, parents=new_parents)) elif isinstance( call, ins.intelop.OffsetBaseIndexScale) and call.base == None: # Ignore 'call ds:memmove' or 'call ds:atoi' # print("OffsetBase", call.offset, hex(ea)[2:-1], db.disasm(ea), parents) pass else: calls.append(dyn_call(ea, parents)) return calls
def uses_register(ea, regs): res = [(_instruction.op_type(ea, x), _instruction.op_value(ea, x), _instruction.op_state(ea, x)) for x in xrange(_instruction.ops_count(ea)) if _instruction.op_type(ea, x) in ('opt_reg', 'opt_phrase')] match = lambda r, regs: itertools.imap( _instruction.reg_t.byName(r).related, itertools.imap(_instruction.reg_t.byName, regs)) for t, p, st in res: if t == 'opt_reg' and any(match( p, regs)) and ('w' in st if write else True): return True if t == 'opt_phrase' and not write: _, (base, index, _) = p if (base and any(match(base, regs))) or (index and any( match(index, regs))): return True continue return False
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 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 search_malloc(addr, funcname='malloc', curr_addr_list=None): # print(hex(addr), curr_addr_list) if curr_addr_list == None: curr_addr_list = [addr] print("Addr: {}".format(addr)) curr_calls = fn.tag(addr).get('calls', {}) for ea in fn.iterate(addr): if not ins.isCall(ea): continue if ins.op_type(0) == 'reg': """ Handle this case - malloc(100) mov ebp, ds:malloc push 100 call ebp """ if funcname in db.disasm(ea): # Push before malloc "should" be within 20 instructions """ Handle this case - malloc(100) push 100 mov eax, 10 mov ebx, 20 call malloc """ search_addr = db.prev(ea) for _ in range(20): if ins.mnem(search_addr) == 'push': break search_addr = db.prev(search_addr) print("FOUND PUSH FOR MALLOC: {}".format(hex(search_addr))) malloc_value = ins.op_value(search_addr, 0) if isinstance(malloc_value, (int, long)): curr_calls[funcname] = malloc_value else: curr_calls[funcname] = 'variable' fn.tag(addr, 'calls', curr_calls) return True call = ins.op_value(ea, 0) # Don't cycle ourselves if call == addr: print("Ignoring recursive loop on function: {}".format(hex(addr))) continue # Try to know if the call operand is a valid address # Bail if not.. try: print(hex(call)) except: continue # Check if this function has been analyzed already # and return the result # Cannot return False, because that will exit the loop and not # continue to iterate over the rest of the instrutions in the function call_cache = fn.tag(call).get('calls', {}) print("Call cache: {}".format(call_cache)) if funcname in call_cache: if call_cache[funcname]: curr_calls[funcname] = call_cache[funcname] fn.tag(addr, 'calls', curr_calls) return True # Don't call functions we are currently looking into if call in curr_addr_list: continue # Only now ca curr_addr_list.append(call) search_malloc(call, funcname=funcname, curr_addr_list=curr_addr_list) curr_calls[funcname] = False fn.tag(addr, 'calls', curr_calls) return False
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))