def build_gcc(): for item in class_list: attribute = idc.Dword(class_list[item]["addr"] + 0x10) num = idc.Dword(class_list[item]["addr"] + 0x14) if (0 <= attribute <= 4) and (0 < num < 100): i = 0 while i < num: symbol = idc.GetOpnd( class_list[item]["addr"] + 0x18 + i * 0x10, 0) symbol = re.sub(r'^offset ', '', symbol) class_list[item]["base"].append(symbol) virtual_attri = idc.Qword(class_list[item]["addr"] + 0x18 + i * 0x10 + 8) if struct.unpack('q', struct.pack('Q', virtual_attri))[0] < 0: if "virtual_inherit" in class_list[item]: class_list[item]["virtual_inherit"].append(symbol) else: class_list[item]["virtual_inherit"] = list() class_list[item]["virtual_inherit"].append(symbol) i += 1 else: symbol = idc.GetOpnd(class_list[item]["addr"] + 0x10, 0) symbol = re.sub(r'^offset ', '', symbol) addr = idc.Qword(class_list[item]["addr"] + 0x10) # 排除类定义到其他文件的 extern if (symbol[:4] == "_ZTI") and ((addr < extern_start) or (addr > extern_end)): class_list[item]["base"].append(symbol)
def getExtraDataByType(self, extraDataType): flag = idc.Qword(self.addr + BSExtraData.Offset.field_10) if flag == 0: return None var1 = extraDataType >> 3 if var1 < 0x1B: return None var2 = 1 << ((extraDataType & 0x7) & 0b11111111) if (idc.byte(var1 + flag) & var2) == 0: return None vftable = idc.Qword(self.addr + BSExtraData.Offset.vftable) if vftable == 0: return None current_extra_data_addr = self.addr while True: if idc.byte(current_extra_data_addr + BSExtraData.Offset.Type) == extraDataType: return current_extra_data_addr current_extra_data_addr = idc.Qword(current_extra_data_addr + BSExtraData.Offset.PtrNext) if current_extra_data_addr == 0: return None
def extract_info_from_IDA(self): prots = ida_bytes.get_qword(self.ea + 0x10) if prots: count = ida_bytes.get_qword(prots) entrysize = 0x8 p_ea = prots + 8 for i in range(count): proto_ea = idc.get_qword(p_ea) self.prots.append(proto_ea) p_ea += entrysize type_info = ida_bytes.get_qword(self.ea + 0x48) for idx in range(0, 4): # 0: inst_meths # 1: class_meths # 2: opt_inst_meths # 3: opt_class_meths meth_list = ida_bytes.get_qword(self.ea + 0x18 + idx * 8) if meth_list: entrysize = ida_bytes.get_dword(meth_list) count = ida_bytes.get_dword(meth_list + 4) ea = meth_list + 8 for i in range(0, count): sel = idc.get_bytes(idc.Qword(ea), idc.get_item_size(idc.Qword(ea)) - 1) meth_type = idc.get_bytes(idc.Qword(type_info), idc.get_item_size(idc.Qword(type_info)) - 1) self.meths[sel] = meth_type ea += entrysize type_info += 8
def find_vftable_msvc(seg): seg_start = idc.SegStart(seg) seg_end = idc.SegEnd(seg) cur_addr = seg symbol = "" while cur_addr <= seg_end - 8: #32 is 4 data = idc.Qword(cur_addr) #32 is Dword # 检测data是否在.text段 # check if the data in .text if text_start <= data < text_end: xrefs = list(idautils.XrefsTo(cur_addr)) rttiptr = idc.Qword(cur_addr - 8) nameptr = idaapi.get_imagebase() + idc.Dword(rttiptr + 0x10) if (len(xrefs) != 0) and (rdata_start <= rttiptr < rdata_end) and ( nameptr not in rtti_list): symbol = idc.GetOpnd(rttiptr + 0x10, 0) symbol = re.sub(r'^rva ', '', symbol) class_hierarchy_addr = nameptr class_list[symbol] = dict() class_list[symbol]["addr"] = class_hierarchy_addr class_list[symbol]["base"] = list() class_list[symbol]["function_list"] = [hex(data).strip("L")] rtti_list.append(nameptr) elif symbol != "": class_list[symbol]["function_list"].append( hex(data).strip("L")) cur_addr += 8 #32 is 4
def IsInstrumentIns(ea): ''' is ea instrument instruction? ''' if idc.__EA64__: # 64bit ''' .text:00000000005AC870 48 8D A4 24 68 FF FF FF lea rsp, [rsp-98h] .text:00000000005AC878 48 89 14 24 mov [rsp+48h+var_48], rdx .text:00000000005AC87C 48 89 4C 24 08 mov [rsp+48h+var_40], rcx .text:00000000005AC881 48 89 44 24 10 mov [rsp+48h+var_38], rax .text:00000000005AC886 48 C7 C1 6C 1A 00 00 mov rcx, 1A6Ch .text:00000000005AC88D E8 DE 0E 00 00 call __afl_maybe_log_10 .text:00000000005AC892 48 8B 44 24 10 mov rax, [rsp+48h+var_38] .text:00000000005AC897 48 8B 4C 24 08 mov rcx, [rsp+48h+var_40] .text:00000000005AC89C 48 8B 14 24 mov rdx, [rsp+48h+var_48] .text:00000000005AC8A0 48 8D A4 24 98 00 00 00 lea rsp, [rsp+98h] ''' if 0xFFFFFF6824A48D48 == idc.Qword( ea) and 0x244C894824148948 == idc.Qword(ea + 8): return True else: # 32bit ''' 52 push edx 51 push ecx 50 push eax B9 8A 7D 00 00 mov ecx, 7D8Ah E8 53 10 00 00 call __afl_maybe_log 58 pop eax 59 pop ecx 5A pop edx ''' if 0xB9505152 == idc.Dword(ea) and 0x5A595800 == idc.Dword(ea + 12): return True return False
def stval(self, addr, ofs, sz=8): if addr < 20: """ argument """ if addr < 4: regs = ["rcx", "rdx", "r8", "r9"] addr = idc.GetRegValue(regs[addr]) else: rsp = idc.GetRegValue('rsp') addr = idc.Qword(rsp + addr * 8 + 8) if isinstance(ofs, basestring): sf = ofs.split('.') st = struct.Struct(sf[0]) res = st.readInst(addr) while len(sf) > 2: res = st.subInst(res, sf[1]) sf = sf[1:] if len(sf) > 1: res = res[sf[1]] return str(res) if sz == 8: return idc.Qword(addr + ofs) if sz == 4: return idc.Dword(addr + ofs) if sz == 2: return idc.Word(addr + ofs) return idc.Byte(addr + ofs)
def __PltResolver(jmprel, strtab, symtab): idx = 0 while True: r_off = idc.Qword(jmprel + 0x18 * idx) r_info1 = idc.Dword(jmprel + 0x18 * idx + 0x8) r_info2 = idc.Dword(jmprel + 0x18 * idx + 0xc) r_addend = idc.Qword(jmprel + 0x18 * idx + 0x10) if r_off > 0x7fffffff: return if r_info1 == 7: st_name = idc.Dword(symtab + r_info2 * 0x18) name = idc.GetString(strtab + st_name) # rename got idc.set_name(r_off, name + '_ptr') plt_func = idc.Qword(r_off) # rename plt idc.set_name(plt_func, 'j_' + name) SetFuncFlags(plt_func) # rename plt.sec for addr in idautils.DataRefsTo( r_off): # 新版本gcc中got表的ref只在.plt.sec段出现 plt_sec_func = idaapi.get_func(addr).startEA idc.set_name(plt_sec_func, '_' + name) # 其实重点是.plt.sec设置为 _xxx 即可正常解析 ParseTypes(plt_sec_func) SetFuncFlags(plt_sec_func) idx += 1
def __PltResolver(jmprel,strtab,symtab): idx=0 while True: r_off = idc.Qword(jmprel+0x18*idx) r_info1 = idc.Dword(jmprel+0x18*idx+0x8) r_info2 = idc.Dword(jmprel+0x18*idx+0xc) r_addend = idc.Qword(jmprel+0x18*idx+0x10) if r_off > 0x7fffffff: return if r_info1 == 7: st_name = idc.Dword(symtab+r_info2*0x18) name = idc.GetString(strtab+st_name) # rename got idc.set_name(r_off,name+'_ptr') plt_func = idc.Qword(r_off) # rename plt idc.set_name(plt_func,'j_'+name) SetFuncFlags(plt_func) # rename plt.sec for addr in idautils.DataRefsTo(r_off): plt_sec_func = idaapi.get_func(addr) if plt_sec_func: plt_sec_func_addr = plt_sec_func.startEA idc.set_name(plt_sec_func_addr,'_'+name) SetFuncFlags(plt_sec_func_addr) else: print "[!] idaapi.get_func({}) failed".format(hex(addr)) idx+=1
def find_type_of_meth(imp): for xref in idautils.XrefsTo(imp): if idc.SegName(xref.frm) == '__objc_const': if idc.Qword(xref.frm + 16) == imp: type = idc.GetDisasm(idc.Qword(xref.frm + 8)) m = re.search('DCB (?P<def_type>.+),0', type) if m: return m.group('def_type')
def GetDyn(): phoff = idc.Qword(idc.MinEA() + 0x20) + idc.MinEA() phnum = idc.Word(idc.MinEA() + 0x38) phentsize = idc.Word(idc.MinEA() + 0x36) for i in range(phnum): p_type = idc.Dword(phoff + phentsize * i) if p_type == 2: # PY_DYNAMIC dyn_addr = idc.Qword(phoff + phentsize * i + 0x10) return dyn_addr
def parse_cfstring(ea): """ Parse cfstring. :param ea: address at __cfstring segment. :return: String. """ data = idc.Qword(ea + 0x10) length = idc.Qword(ea + 0x18) return idaapi.get_many_bytes(data, length)
def ParseDyn(dyn,tag): idx=0 while True: v1,v2 = idc.Qword(dyn+idx*0x10),idc.Qword(dyn+idx*0x10+8) if v1 == 0 and v2 == 0: return if v1 == tag: return v2 idx+=1
def __init__(self, ea): self.ea = ea # ea: objc_data address self.info = ida_bytes.get_qword(ea + 0x20) self.superclass = ida_bytes.get_qword( ida_bytes.get_qword(ea) + 0x08) # idc.Name(self.superclass): _OBJC_METACLASS_$_UIView self.name = idc.get_bytes(idc.Qword(self.info + 0x18), idc.get_item_size(idc.Qword(self.info + 0x18)) - 1) self.classref = None self.superref = None self.prots = [] self.ivars = dict() self.props = dict()
def getPropVal(self, addr, cnt=1): cnt = cnt or 1 res = "" mp = MapiEnum() for x in range(cnt): tp = idc.Dword(addr) v1 = idc.Qword(addr + 8) v2 = idc.Qword(addr + 0x10) data = self.getPropValue(tp & 0xFFFF, v1, v2) res += str(x) + ": type " + hex(tp) + " " + mp.name( tp) + " = " + str(data) + "\n" addr += 0x18 return res
def is_method_a_getter(self, sel, f=None): base_props = ida_bytes.get_qword(self.info + 0x40) if not base_props: return False entrysize = ida_bytes.get_dword(base_props) count = ida_bytes.get_dword(base_props + 4) p_ea = base_props + 8 for i in range(count): p_name = idc.get_bytes(idc.Qword(p_ea), idc.get_item_size(idc.Qword(p_ea)) - 1) if p_name == sel: return True p_ea += entrysize return False
def read_mem(addr, forced_addr_sz=None, read_only=False): global ADDR_SZ if not read_only: if forced_addr_sz: idc.MakeUnknown(addr, forced_addr_sz, idc.DOUNK_SIMPLE) else: idc.MakeUnknown(addr, ADDR_SZ, idc.DOUNK_SIMPLE) idaapi.autoWait() if forced_addr_sz == 2: if not read_only: idc.MakeWord(addr) idaapi.autoWait() return idc.Word(addr) if forced_addr_sz == 4 or ADDR_SZ == 4: if not read_only: idc.MakeDword(addr) idaapi.autoWait() return idc.Dword(addr) if forced_addr_sz == 8 or ADDR_SZ == 8: if not read_only: idc.MakeQword(addr) idaapi.autoWait() return idc.Qword(addr)
def assign_kmdf_structure_types(address): # Get the jmp to de import jmp_import_ea = idautils.XrefsTo(address).next().frm # There is only one XREF to WdfVersionBind call_wdfVersionBind = idautils.XrefsTo(jmp_import_ea).next().frm print(hex(call_wdfVersionBind)) argument_WdfBindInfo = find_function_arg(call_wdfVersionBind, "lea", "r8", 0) if argument_WdfBindInfo is None: print("Error: Argument WdfBindInfo wasn't found!") return wdfBindInfo = idc.GetOperandValue(argument_WdfBindInfo, 1) idc.MakeName(wdfBindInfo, '_WdfBindInfo') print("WdfBindInfo Struct: ", hex(wdfBindInfo)) if not assign_struct_to_address(wdfBindInfo, "_WDF_BIND_INFO"): print("The _WDF_BIND_INFO struct wasn't found in the database") return g_vars["_WDF_BIND_INFO"] = wdfBindInfo # Assign ComponentGlobals Name argument_WdfComponentGlobals = find_function_arg(call_wdfVersionBind, "lea", "r9", 0) wdfComponentGlobals = idc.GetOperandValue(argument_WdfComponentGlobals, 1) g_vars["_WDF_COMPONENT_GLOBALS"] = wdfComponentGlobals idc.MakeName(wdfComponentGlobals, '_WdfComponentGlobals') # Now assign the WDFFUNCTIONS to FuncTable wdfFunctions = idc.Qword(wdfBindInfo + 0x20) g_vars["_WDFFUNCTIONS"] = wdfFunctions assign_struct_to_address(wdfFunctions, "_WDFFUNCTIONS") idc.MakeName(wdfFunctions, 'g_WdfF_Functions')
def readValue(self): if self.value != None: return self.value operandType = self.parser.getOperandType() regName = self.parser.getRegName() regValue = idc.GetRegValue(regName) if regName != None else None if operandType == OperandType.Value64OfRegisterPlusOffset: self.value = idc.Qword(regValue + self.opValue) elif operandType == OperandType.Value32OfRegisterPlusOffset: self.value = idc.Dword(regValue + self.opValue) elif operandType == OperandType.Value16OfRegisterPlusOffset: self.value = idc.Word(regValue + self.opValue) elif operandType == OperandType.Value8OfRegisterPlusOffset: self.value = idc.Byte(regValue + self.opValue) elif (operandType == OperandType.Register64) or (operandType == OperandType.Register32): self.value = regValue elif (operandType == OperandType.Register16) or (operandType == OperandType.Register8): self.value = regValue elif operandType == OperandType.ImmediateUnkown: self.value = self.opValue else: raise Exception("Unknown operand type") return self.value
def update(self, **kwargs): tp = self.currentType(self.CHECK_VTBL, **kwargs) tp = self.checkVtblStruct(tp) Logger.debug("Updating class %s", str(tp)) ea = tp['vtblea'] nm = None funcs = [] while (not nm): ofs = idc.Qword(ea) if not ofs or ofs == idc.BADADDR: break func = FuncDescr.fromEA(ofs) if self.untouchedFunc(func.name): func.checkThis(tp['name'] + '*') Logger.debug("found vtbl function: %s", str(func)) name = func.name i = 2 while name in funcs: name = func.name + "_" + str(i) i += 1 self.setStrucPntr(tp['vtblid'], ea - tp['vtblea'], name, func.buildType(True)) funcs += [name] ea += 8 nm = idc.Name(ea)
def GetRelocTables(): reloc_dict = dict() sid = idc.GetStrucIdByName('Elf64_Rela') for xref in idautils.XrefsTo(sid): addr = xref.frm # r_offset(8 bytes) + r_info(8 bytes) + r_addend(8 bytes) r_offset = idc.Qword(addr + 0) r_info = idc.Qword(addr + 8 * 1) r_addend = idc.Qword(addr + 8 * 2) # we only interested in r_info with 8 if r_info != 8: continue reloc_dict[r_offset] = r_addend return reloc_dict
def getCStrFromBSFixedString(bs_fixed_string): if bs_fixed_string is None: return 0 strCacheEntry = idc.Qword(bs_fixed_string + BSFixedString.ptrEntry.value) #print("EntryData: 0x%x" % (strCacheEntry)) if strCacheEntry is None: return 0 entry_state = idc.Dword(strCacheEntry + StringCache_Entry.state.value) #print("EntryState: 0x%x" % (entry_state)) hasCStrValue = StringCache_Entry_State_HasCStrValue(entry_state) #print("hasCStrValue: %s" % (hasCStrValue)) if hasCStrValue: return (strCacheEntry + StringCache_Entry.data.value) % UInt64MaxValue extern_data_entry = idc.Qword(strCacheEntry + StringCache_Entry.ptrExternDataEntry.value) #print("ExternDataEntry: 0x%x" % (extern_data_entry)) return getCStrFromBSFixedStringExternDataRecursively(extern_data_entry)
def mem_read_integer(addr, read_size=4): if read_size == 2: return idc.Word(addr) % 0xFFFF elif read_size == 4: # 32bit Default return idc.Dword(addr) & 0xFFFFFFFF else: # Read Size is 8 Byte (for 64bit) return idc.Qword(addr) & 0xFFFFFFFFFFFFFFFF
def __init__(self, addr, deepness=0): super(TESObjectREFR, self).__init__(addr, deepness) inventoryListAddr = idc.Qword(addr + TESObjectREFR.Offset.InventoryList.value) if (deepness >= max_deepness): self.InventoryList = inventoryListAddr else: self.InventoryList = BGSInventoryList(inventoryListAddr, deepness + 1)
def scan_register(reg_str_name): regValue = idc.GetRegValue(reg_str_name) if pdbg: print("Reg scan: %s" % (reg_str_name)) # TODO: iterate over scanners # scanners = AnalyserBase.__subclasses__() scanners = [TESObjectAnalyser(), VFTableAnalyser(), FuncAnalyser(), StringAnalyser()] if pvrb: print("Found %s scanners." % (len(scanners))) # build override list: override_list = { "overriden_by": {}, "overriden_by_all": [], "overrides_all": [] } for scanner in scanners: override_list["overriden_by"].update(scanner.override_list["horizontal"]["overriden_by"]) # dict override_list["overriden_by_all"] = override_list["overriden_by_all"] + scanner.override_list["horizontal"]["overriden_by_all"] # list override_list["overrides_all"] = override_list["overrides_all"] + scanner.override_list["horizontal"]["overrides_all"] # list # scan registers results = scan_value(scanners, regValue) results = filter_results(override_list, results) print_results("{} is ".format(reg_str_name.upper()) + "{}", results) if pdbg: print("scanning ptr..") ptr = idc.Qword(regValue) if pdbg: print("PTR0: 0x%X" % (ptr)) prevResults = results results = scan_value(scanners, ptr) results = filter_results(override_list, results, prevResults) print_results("{} points to ".format(reg_str_name.upper()) + "{}", results) ptrPtr = idc.Qword(ptr) if pdbg: print("PTR1: 0x%X" % (ptrPtr)) prevResults = prevResults + results results = scan_value(scanners, ptrPtr) results = filter_results(override_list, results, prevResults) print_results("{} points to 0x{:X} -> ".format(reg_str_name.upper(), ptr) + "{}", results)
def __init__(self, addr, deepness=0): super(BGSInventoryItem, self).__init__(addr, deepness) formAddr = idc.Qword(addr + BGSInventoryItem.Offset.form.value) stackAddr = idc.Qword(addr + BGSInventoryItem.Offset.stack.value) if stackAddr == 0: self.stack = NullObject() else: if deepness >= max_deepness: self.stack = stackAddr else: self.stack = Stack(stackAddr, deepness + 1) if formAddr == 0: self.form = NullObject() else: if deepness >= max_deepness: self.form = formAddr else: self.form = TESForm(formAddr, deepness + 1)
def __init__(self, addr, deepness=0): super(Stack, self).__init__(addr, deepness) nextStackAddr = idc.Qword(addr + Stack.Offset.PtrNextStack.value) if nextStackAddr == 0: self.NextStack = NullObject() else: if deepness >= max_deepness: self.NextStack = nextStackAddr else: self.NextStack = Stack(nextStackAddr, deepness + 1) extraDataListAddr = idc.Qword(addr + Stack.Offset.PtrExtraDataList.value) if extraDataListAddr == 0: self.ExtraDataList = NullObject() else: if deepness >= max_deepness: self.ExtraDataList = extraDataListAddr else: self.ExtraDataList = ExtraDataList(extraDataListAddr, deepness + 1) self.count = idc.Dword(addr + Stack.Offset.Count.value) self.flags = idc.Byte(addr + Stack.Offset.Flags.value)
def __init__(self, addr, deepness=0): super(StringCache.Ref, self).__init__(addr, deepness) self.entryAddr = idc.Qword(addr + StringCache.Ref.Offset.Entry.value) if self.entryAddr == 0: self.entry = NullObject() else: if deepness >= max_deepness: self.entry = self.entryAddr else: self.entry = StringCache.Entry(self.entryAddr, deepness + 1)
def subclass(self, sup=None, **kwargs): tp = self.currentType(self.CHECK_VTBL, **kwargs) tp = self.checkVtblStruct(tp) cnm = tp['name'] if not sup: sup = idc.AskStr('', "Subclass " + cnm + " from:") if not sup or sup == cnm: Logger.debug("Subclasssing cancelled") return idc.Til2Idb(-1, sup + 'Vtbl') s = MODS.struct.Struct(sup + 'Vtbl') Logger.debug("Subclassing class %s from %s", str(tp), sup) ea = tp['vtblea'] nm = None funcs = [] while (not nm): ofs = idc.Qword(ea) if not ofs or ofs == idc.BADADDR: break try: func = FuncDescr.fromEA(ofs) except FuncDescr.NotFunctionError as e: func = None if not kwargs.get('force'): raise funcs += [func] ea += 8 nm = idc.Name(ea) flds = s.fields() if len(funcs) != len(flds) and (not kwargs.get('force')): raise self.WrongTypeError("Functions count doesn't match", s.name) for i, fofs in enumerate(sorted(flds.keys())): fld = flds[fofs] f = funcs[i] if f is None: continue refcnt = len(MODS.util.refsFromSeg(f.ea, ".rdata")) if self.untouchedFunc(f.name): nm = cnm if refcnt == 1 else sup was = str(f) f.clearType() f.parseType(fld['type'][0]) f.name = nm + "::" + fld['name'] ni = 1 while idaapi.get_name_ea(idc.BADADDR, f.name) != idc.BADADDR: ni += 1 f.name = nm + "::" + fld['name'] + "_" + str(ni) f.changeParam(0, 'this', nm + '*') f.update(True) Logger.debug("Converted func %s to type %s", was, str(f)) self.update()
def __init__(self, addr, deepness=0): super(VFTable, self).__init__(addr, deepness) ptrRttiCol = self.addr + VFTable.Offset.RTTICompleteObjectLocator.value rttiCOLAddr = idc.Qword(ptrRttiCol) if deepness >= max_deepness: self.RTTICompleteObjectLocator = rttiCOLAddr else: self.RTTICompleteObjectLocator = RTTICompleteObjectLocator( rttiCOLAddr, deepness + 1) # short names self.col = self.RTTICompleteObjectLocator
def IsInstrumentIns(ea): ''' is ea instrument instruction? ''' if idc.__EA64__: # 64bit ''' .text:0000000000412450 48 8D 64 24 80 lea rsp, [rsp-80h] .text:0000000000412455 53 push rbx .text:0000000000412456 51 push rcx .text:0000000000412457 68 30 E2 00 00 push 0E230h // z .text:000000000041245C 48 C7 C1 00 00 00+mov rcx, 0 // x .text:0000000000412463 48 C7 C3 19 D6 00+mov rbx, 0D619h .text:000000000041246A E8 51 44 00 00 call __afl_maybe_log_fun_3 .text:000000000041246F 59 pop rcx .text:0000000000412470 59 pop rcx .text:0000000000412471 5B pop rbx .text:0000000000412472 48 8D A4 24 80 00+lea rsp, [rsp+80h] ''' if 0x6851538024648D48 == idc.Qword(ea) and 0xC748 == idc.Word( ea + 0xc) and 0xC748 == idc.Word( ea + 0x13) and 0x0000008024A48D48 == idc.Qword(ea + 0x22): return True else: # 32bit ''' 52 push edx 51 push ecx 50 push eax B9 8A 7D 00 00 mov ecx, 7D8Ah E8 53 10 00 00 call __afl_maybe_log 58 pop eax 59 pop ecx 5A pop edx ''' if 0xB9505152 == idc.Dword(ea) and 0x5A595800 == idc.Dword(ea + 12): return True return False