def make_xref(from_ea, to_ea, xref_constructor, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.GetFlags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format(from_ea, to_ea)) return make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. if not make_head(from_ea + xref_size): assert idc.BADADDR == idc.SegStart(from_ea + xref_size) idaapi.do_unknown_range(from_ea, xref_size, idc.DOUNK_EXPAND) xref_constructor(from_ea) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER|idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format(from_ea, to_ea))
def make_xref(from_ea, to_ea, xref_constructor, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.GetFlags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format( from_ea, to_ea)) return make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. if not make_head(from_ea + xref_size): assert idc.BADADDR == idc.SegStart(from_ea + xref_size) idaapi.do_unknown_range(from_ea, xref_size, idc.DOUNK_EXPAND) xref_constructor(from_ea) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER | idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format( from_ea, to_ea))
def markDataPtr(self, src, dest, aggressive=True): """Mark a data pointer from src to dest. Args: src (int): effective address for the pointer's location dest (int): effective address for the pointed data address aggressive (bool, optional): True iff should redefine the src (True by default) """ if aggressive: ida_bytes.del_items(src, 0, self.addressSize()) if self.makeAddress(src): idc.add_dref(src, dest, idc.XREF_USER | idc.dr_O) ida_offset.op_offset(src, 0, idc.REF_OFF32)
def make_xref(from_ea, to_ea, data_type, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.get_full_flags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format( from_ea, to_ea)) return False make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. # or in the middle of structure. Return False in such case # # NOTE(artem): Commenting out since this breaks recovery of C++ applications # with IDA7. The failure occurs when processign references in .init_array # when the below code is enabled, those references are not treated as # references because make_head fails. # #if not make_head(from_ea + xref_size): # return False ida_bytes.del_items(from_ea, idc.DELIT_EXPAND, xref_size) if data_type == idc.FF_QWORD: data_size = 8 elif data_type == idc.FF_DWORD: data_size = 4 else: raise ValueError("Invalid data type") idc.create_data(from_ea, data_type, data_size, idaapi.BADADDR) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER | idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format( from_ea, to_ea)) return True
def markCodePtr(self, src, dest, aggressive=True): """Mark a code pointer from src to dest. Args: src (int): effective address for the pointer's location dest (int): effective address for the pointed code address aggressive (bool, optional): True iff should redefine the src & dest (True by default) """ clean_dest = self.cleanPtr(dest) if aggressive: ida_bytes.del_items(src, 0, self.addressSize()) if self.makeAddress(src): idc.add_dref(src, clean_dest, idc.XREF_USER | idc.dr_O) idc.add_cref(src, clean_dest, idc.XREF_USER | idc.dr_O) ida_offset.op_offset(src, 0, idc.REF_OFF32) if aggressive: ida_bytes.del_items(dest, 0, self.addressSize()) idc.create_insn(self.cleanPtr(dest))
def make_xref(from_ea, to_ea, data_type, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.get_full_flags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format(from_ea, to_ea)) return False make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. # or in the middle of structure. Return False in such case # # NOTE(artem): Commenting out since this breaks recovery of C++ applications # with IDA7. The failure occurs when processign references in .init_array # when the below code is enabled, those references are not treated as # references because make_head fails. # #if not make_head(from_ea + xref_size): # return False ida_bytes.del_items(from_ea, idc.DELIT_EXPAND, xref_size) if data_type == idc.FF_QWORD: data_size = 8 elif data_type == idc.FF_DWORD: data_size = 4 else: raise ValueError("Invalid data type") idc.create_data(from_ea, data_type, data_size, idaapi.BADADDR) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER|idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format(from_ea, to_ea)) return True
def make_xref(from_ea, to_ea, data_type, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.get_full_flags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format( from_ea, to_ea)) return False make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. # or in the middle of structure. Return False in such case if not make_head(from_ea + xref_size): return False ida_bytes.del_items(from_ea, idc.DELIT_EXPAND, xref_size) if data_type == idc.FF_QWORD: data_size = 8 elif data_type == idc.FF_DWORD: data_size = 4 else: raise ValueError("Invalid data type") idc.create_data(from_ea, data_type, data_size, idaapi.BADADDR) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER | idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format( from_ea, to_ea)) return True
def find_pairs(): ea = idc.MinEA() movh = [None] * MAX_REGISTERS while ea < idc.MaxEA(): insn = idautils.DecodeInstruction(ea) if insn: mnem = insn.get_canon_mnem() reg1 = insn.Op1.reg reg2 = insn.Op2.reg val1 = insn.Op2.value val2 = insn.Op3.value size = insn.size if mnem == "movh" and insn.Op2.type == o_imm: movh[reg1] = (val1, insn.ea) elif movh[reg1] is not None: other = movh[reg1] if mnem == "add3" and reg1 == reg2: target = (other[0] << 16) + val2 print "Found a add3 pointer pair to ", hex(target), " at ", hex(insn.ea) idc.add_dref(insn.ea, target, dr_O) idc.add_dref(other[1], target, dr_O) idaapi.set_refinfo(insn.ea, 2, REF_LOW16, target, 0, 0) idaapi.set_refinfo(other[1], 1, REF_HIGH16, target, 0, 0) elif mnem == "or3" and reg1 == reg2: target = (other[0] << 16) | val2 print "Found a or3 pointer pair to ", hex(target), " at ", hex(insn.ea) idc.add_dref(insn.ea, target, dr_O) idc.add_dref(other[1], target, dr_O) idaapi.set_refinfo(insn.ea, 2, REF_LOW16, target, 0, 0) idaapi.set_refinfo(other[1], 1, REF_HIGH16, target, 0, 0) movh[reg1] = None if insn.get_canon_feature() & (idaapi.CF_STOP | idaapi.CF_CALL): movh = [None] * MAX_REGISTERS else: size = 2 ea += size
def export(self, vtables): """ @vtables: List of tuples with vtable information [(ins_addr, vtable), ... ] There is a small mistake. Some .data references will be tagged as being vtables. This is due to the way we detect them on pin. In IDA pro it should be easy to mark just only the ones that refer to .text but I could not find a way to get that information from idapython. """ # We build a dictionary with the ins addr referencing the vtable as the key dict_ = {} for vtable in vtables: # Add all the vtable references found while tracing to the set dict_.setdefault(vtable[0], set()).add(vtable[1]) for (key, val) in dict_.iteritems(): prev_comment = idc.GetCommentEx(vtable[0], False) # Check if we already have commented this line. This will avoid duplicating info. if not prev_comment or "VTables found:" in prev_comment: prev_comment = "VTables found:\n" prev_comment += "\n".join(map(lambda x: "0x%.8x" % x, val)) # vtable[0] == instruction address idc.MakeComm(key, prev_comment) # Check if we already have a cross reference for v in val: if key in [ref.frm for ref in XrefsTo(v, 0)]: continue # Add a data reference if add_dref(key, v, dr_R) != True: idaapi.msg( "Could not create cross reference from %x to %x\n" % (key, v))
def scanDataForRelocs(M, D, start, end, new_eas, seg_offset): i = start while i < end: more_dref = [d for d in idautils.DataRefsFrom(i)] dref_size = idc.ItemSize(i) or 1 if len(more_dref) == 0 and dref_size == 1: dword = readDword(i) DEBUG("Testing address: {0:x}... ".format(i)) # check for unmakred references if isInData(dword, dword+1): idc.MakeDword(i) idc.add_dref(i, dword, idc.XREF_USER|idc.dr_O) DEBUG("making New Data Reference at: {0:x} => {1:x}\n".format(i, dword)) dref_size = 4 elif isInternalCode(dword): idc.MakeDword(i) idc.AddCodeXref(i, dword, idc.XREF_USER|idc.fl_F) DEBUG("making New Code Reference at: {0:x} => {1:x}\n".format(i, dword)) dref_size = 4 else: DEBUG("not code or data ref\n") i += dref_size def insertReference(M, D, ea, pointsto, seg_offset, new_eas): # do not make code references for mid-function code accessed via a JMP -- # they will be found via the jumptable code. This prevents the insertion # of lots of extra code, but could be wrong for some cases if ea in ACCESSED_VIA_JMP and not isStartOfFunction(pointsto): # bail only if we are access via JMP and not the start # of a function DEBUG("\t\tNOT ADDING REF: {:08x} -> {:08x}\n".format(ea, pointsto)) return DEBUG("\t\tFound a probable ref from: {0:x} => {1:x}\n".format(ea, pointsto)) real_size = idc.ItemSize(pointsto) DEBUG("\t\tReal Ref: {0:x}, size: {1}\n".format(pointsto, real_size)) insertRelocatedSymbol(M, D, pointsto, ea, seg_offset, new_eas, real_size) def checkIfJumpData(ea, size): """ Loop through ea to ea+size, and if every dword there points to code, this is a jump data section returns true or false and list of recovered ea => destination mappings """ table_map = {} for jea in xrange(ea, ea+size, 4): dword = readDword(jea) if not isInternalCode(dword): DEBUG("Dword {:x} does not point to code, not a table\n".format(dword)) return False, table_map table_map[jea] = dword return True, table_map i = start while i < end: DEBUG("Checking address: {:x}\n".format(i)) dref_size = idc.ItemSize(i) or 1 if dref_size > 4 and dref_size % 4 == 0: DEBUG("Possible table data at {:x}; size: {:x}\n".format(i, dref_size)) (is_table, addrs) = checkIfJumpData(i, dref_size) if is_table: DEBUG("Its a table, adding {} references\n".format(len(addrs))); for ta in sorted(addrs.keys()): insertReference(M, D, ta, addrs[ta], seg_offset, new_eas) else: DEBUG("Its not a table\n"); elif dref_size == 4: more_cref = [c for c in idautils.CodeRefsFrom(i,0)] more_dref = [d for d in idautils.DataRefsFrom(i)] more_dref.extend(more_cref) if len(more_dref) > 0: DEBUG("\t\tFound a probable ref from: {0:x} => {1:x}\n".format(i, more_dref[0])) if len(more_dref) == 1: insertReference(M, D, i, more_dref[0], seg_offset, new_eas) else: DEBUG("\t\tWARNING: Possible data ref problem\n"); insertReference(M, D, i, more_dref[0], seg_offset, new_eas) i += dref_size