def _tag_decryptor_calls(decryptor_func='decrypt_and_expand', encBlockArray=0xb94c78): faddr = idc.LocByName(decryptor_func) if type(decryptor_func) == type('str') else decryptor_func seen = set() for xref in idautils.CodeRefsTo(faddr, 0): if xref in seen: continue seen.add(xref) print 'trying to xref to call @0x%x' % (xref) fg = bnrev.FunctionGraph(xref) for i in fg.nodes[xref].incoming: try: print 'trying to find eax for call to %s @ 0x%x' % (decryptor_func, i) arg = calculate.calc(i, fg)[bnrev.eax] if not isinstance(arg, symbolic.Number): print 'found a non number: %s' % (arg,) continue else: addr = encBlockArray + (8 * int(arg.n)) print 'adding dref 0x%x -> 0x%x' % (i, addr) idaapi.add_dref(i, addr, idaapi.dr_I) except: pass
def add_refs(): global refs for (ea, target_addr, target_name) in refs: if target_name and len(target_name) != 0: idaapi.set_cmt(ea, "%s - 0x%X" % (target_name, ea + 4), False) else: idaapi.set_cmt(ea, "0x%X - 0x%X" % (target_addr, ea + 4), False) idaapi.add_dref(ea, target_addr, idc.dr_O)
def _fix_data_offsets(self): ea = 0 count = 0 print "Fixing unresolved offset xrefs...", while ea != idaapi.BADADDR: (ea, n) = idaapi.find_notype(ea, idaapi.SEARCH_DOWN) if idaapi.decode_insn(ea): for i in range(0, len(idaapi.cmd.Operands)): op = idaapi.cmd.Operands[i] if op.type == idaapi.o_imm and idaapi.getseg(op.value): idaapi.add_dref(ea, op.value, (idaapi.dr_O | idaapi.XREF_USER)) count += 1 print "created %d new data xrefs" % count
def new_operators_to_ida_db(marx_module): for new_op in marx_module.new_operators.itervalues(): comment = Comment(new_op.address) if new_op.class_hierarchy: # Check if there is already a comment, do nothing if there is already a comment if not comment: MakeComm( new_op.address, "New operator - Size: {:d}, ".format(new_op.size) + "ClassHierarchy_{:d}".format( new_op.class_hierarchy.number)) # For each vtable of an object which could be constructed by this new operator for vtable in new_op.class_hierarchy.vtables: # Add references from new operator address to vtable address add_dref(new_op.address, vtable.address, dr_O) else: # Check if there is already a comment, do nothing if there is already a comment if not comment: MakeComm( new_op.address, "New operator - Size: {:d}, no class info available". format(new_op.size))
def add_method_xref(self, xref): msg("Adding cross reference to method implementation for %s\n" % get_func_name(self.method_pointer)) #TODO: clean this up so it's more clear how we're parsing and patching the instruction #TODO: handle other potential instructions that could place a method selref into a register #TODO: sanity check what instruction we're actually working with before blindly deciding # it's a 7-byte mov instruction add_dref(xref.frm, self.method_pointer, dr_I | XREF_USER) #offset is a rip-relative offset that gets added to rip and dereferenced #when this instruction is executed, rip will be pointing to the next instruction #meaning it has been incremented by 7 (the length of the mov instruction) offset = self.method_pointer - xref.frm - self.X86_64_MOV_INSTRUCTION_SIZE #this replaces mov RSI, &selector with: # mov RSI, &method #xref.frm is the address of the mov instruction #+3 (4th byte of the instruction) #is where the RIP-relative operand is that #will get dereferenced as a pointer patch_dword(xref.frm + 3, offset) return ObjcMethodXref(xref.frm, self.method_pointer, xref.to)
def recoverBlock(F, startEA, need_trampolines): b = Block(startEA) curEA = startEA # TODO: link some metadata to any block to keep track # of this table, because the indirect jmp # may be in a follower block and not directly in # the block where the address is loaded likelyJmpTable = None while True: insn_t = idautils.DecodeInstruction(curEA) if insn_t is None: if idc.Byte(curEA) == 0xCC: b.endEA = curEA+1 return b else: sys.stdout.write("WARNING: Couldn't decode insn at: {0:x}. Ending block.\n".format(curEA)) b.endEA = curEA return b # check for xrefs j = 0 for op in insn_t: # if it is a MEM operand if op.type == idaapi.o_mem and inValidSegment(op.addr): if isCall(curEA): if isInternalCode(op.addr): idaapi.add_cref(curEA, op.addr, idaapi.fl_CN) else: idaapi.add_dref(curEA, op.addr, idaapi.dr_R) elif isUnconditionalJump(curEA) or isConditionalJump(curEA): if isInternalCode(op.addr): idaapi.add_cref(curEA, op.addr, idaapi.fl_JN) else: idaapi.add_dref(curEA, op.addr, idaapi.dr_R) else: if j == 0: idaapi.add_dref(curEA, op.addr, idaapi.dr_W) else: idaapi.add_dref(curEA, op.addr, idaapi.dr_R) j += 1 nextEA = curEA+insn_t.size crefs = idautils.CodeRefsFrom(curEA, 1) # get curEA follows follows = [cref for cref in crefs] if isJmpTable(curEA): # this is a jmptable (according to IDA) # XXX: we assume jmp tables found by IDA don't overlap # with others jmpentries = set() jmpt = handleJmpTable(None, F, curEA, jmpentries) follows = list(jmpentries.union(set(follows))) JMPTABLES.add(jmpt) elif isIndirectJmp(curEA) and likelyJmpTable is not None: # this is an indirect jmp and in the same block there # was a mov to take the address of a "likely" jmptable for ref in likelyJmpTable.entries(): need_trampolines.add(ref) follows = list(set(likelyJmpTable.entries() + follows)) JMPTABLES.add(likelyJmpTable) likelyJmpTable = None elif isLikeLoadJmpTable(curEA): # this is an instruction which take the address of a # switch table (or something we *think* is a jmp table) likelyJmpTable = handleLikeLoadJmpTable(curEA, F) if isRepPrefix(curEA): sys.stdout.write("Found rep prefix at {0:#x}\n".format(curEA)) b.succs.append(nextEA) b.succs.append(curEA) b.endEA = nextEA return b if isDataInst(curEA): sys.stdout.write("Found data in middle of code at {0:#x}\n".format(curEA)) b.endEA = curEA return b if isCall(curEA): sys.stdout.write("Found call\n") fcrefs = idautils.CodeRefsFrom(curEA, 0) ffollows = [cref for cref in fcrefs] if len(ffollows) == 0 or idaapi.func_does_return(ffollows[0]): b.succs.append(nextEA) b.endEA = nextEA return b if isInt(curEA): sys.stdout.write("Found int\n") b.endEA = nextEA b.succs.append(nextEA) return b if (follows == [nextEA] and not isUnconditionalJump(curEA)) or isCall(curEA): # read next instruction curEA = nextEA # check if we need to make a new block elif len(follows) == 0: # this is a ret, no follows b.endEA = nextEA return b else: # this block has several follow blocks b.endEA = nextEA for f in follows: # do not decode external code refs if not isExternalReference(f): b.succs.append(f) return b
def add_ref(frm, to): idaapi.add_dref(frm, to, idaapi.dr_R) idaapi.add_dref(to, frm, idaapi.dr_R)
def parse_str_ptr(addr): if idc.GetMnem(addr) != 'mov': return False # Validate that the string offset actually exists inside the binary if idc.get_segm_name(idc.GetOperandValue(addr, 1)) is None: return False # Check the operands' type: # - first one must be a register; # - second one must be a memory address if idc.GetOpType(addr, 0) != 1 or idc.GetOpType(addr, 1) != 2: return False addr_2 = idc.FindCode(addr, idaapi.SEARCH_DOWN) # same operands' type for addr_2 if idc.GetMnem(addr_2) != 'mov' or idc.GetOpType( addr_2, 0) != 1 or idc.GetOpType(addr_2, 1) != 2: return False opnd_val_1 = idc.GetOperandValue(addr, 1) opnd_val_2 = idc.GetOperandValue(addr_2, 1) opnd_diff = opnd_val_1 - opnd_val_2 # The 2 operands, one of addr of string length, another one is the addr of string pointer # and they must be side by side if opnd_diff != common.ADDR_SZ and opnd_diff != -common.ADDR_SZ: return False if opnd_diff > 0: str_len_addr, str_ptr_addr = opnd_val_1, opnd_val_2 else: str_len_addr, str_ptr_addr = opnd_val_2, opnd_val_1 str_len = common.read_mem(str_len_addr) str_ptr = common.read_mem(str_ptr_addr) str_addr = common.read_mem(str_ptr) # set max str len if str_len > 64: return False if 'rodata' not in idc.get_segm_name( str_ptr) and 'text' not in idc.get_segm_name(str_ptr): return False common._debug("------------------------------") common._debug("Possible str ptr:") common._debug("Code addr: 0x%x , str_ptr_addr: 0x%x , str_len_addr: 0x%x" % (addr, str_ptr_addr, str_len_addr)) common._debug("str_addr: 0x%x , str_len: 0x%x" % (str_ptr, str_len)) #if create_string(str_addr, str_len): if str_len > 1: if idc.MakeStr(str_ptr, str_ptr + str_len): idaapi.autoWait() if opnd_diff > 0: idc.MakeComm(addr, "length: %d" % str_len) idaapi.add_dref(addr_2, str_ptr, idaapi.dr_O) else: idc.MakeComm(addr_2, "length: %d" % str_len) idaapi.add_dref(addr, str_ptr, idaapi.dr_O) idaapi.autoWait() return True return False
def on_matched_item(self, item, ctx: PatternContext): obj = ctx.get_expr('xref_me') if obj.obj_ea >= 0 and obj.obj_ea <= 0x100000: idaapi.add_dref(obj.ea, obj.obj_ea, idaapi.dr_O) return False
def add_data(ea, target, write=False): flowtype = idaapi.dr_W if write else idaapi.dr_R idaapi.add_dref(ea, target, flowtype | idaapi.XREF_USER) return target in xref.data_down(ea)
if addr & 1: addr -= 1 idaapi.split_sreg_range(addr, idaapi.str2reg("T"), 1, idaapi.SR_user) else: idaapi.split_sreg_range(addr, idaapi.str2reg("T"), 0, idaapi.SR_user) if idaapi.create_insn(addr): if idc.add_func(addr): if name != "": idaapi.set_name(addr, name, idaapi.SN_FORCE) return True return False ea = here() i = 0 while True: func_ea = idaapi.get_dword(ea + 4 + i * 8) if not define_func(func_ea): break idaapi.add_dref(ea, func_ea, idaapi.dr_R) i += 1 print i