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 memToLvl(address, levelId = None): refTableAddr = idc.LocByName("levelReferenceTable") if refTableAddr == BADADDR: print("Can't get level reference table address. Make sure its name is levelReferenceTable.") return if levelId == None: endTableAddr = idc.LocByName("levelEndTable") if endTableAddr == BADADDR: print("Can't get level end table address. Make sure its name is levelEndTable.") return lvl0StartAddr = idc.Dword(refTableAddr) lvl1StartAddr = idc.Dword(refTableAddr + 4) lvl0EndAddr = idc.Dword(endTableAddr) lvl1EndAddr = idc.Dword(endTableAddr + 4) if address >= lvl0StartAddr and address <= lvl0EndAddr: fileRelativeAddr = address - lvl0StartAddr idc.Message("Fix.lvl relative address: 0x" + format(fileRelativeAddr, '02X') + "\n") return if address >= lvl1StartAddr and address <= lvl1EndAddr: fileRelativeAddr = address - lvl1StartAddr idc.Message("Actual level relative address: 0x" + format(fileRelativeAddr, '02X') + "\n") return idc.Message("ERROR: This address does not belong to any level file.") else: lvlStartAddr = idc.Dword(refTableAddr + levelId * 4) fileRelativeAddr = address - lvlStartAddr idc.Message("Address relative to file: 0x" + format(fileRelativeAddr, '02X') + "\n")
def __init__(self, addr, deepness=0): super(RTTICompleteObjectLocator, self).__init__(addr, deepness) self.thisOffset = idc.Dword( self.addr + RTTICompleteObjectLocator.Offset.this.value) self.ctorDisplacement = idc.Dword( self.addr + RTTICompleteObjectLocator.Offset.ctorDisplacement.value) descriptorAddr = RVA( idc.Dword( self.addr + RTTICompleteObjectLocator.Offset.rvaTypeDescriptor.value)) hierarchyAddr = RVA( idc.Dword(self.addr + RTTICompleteObjectLocator.Offset.rvaTypeHierarchy.value)) if deepness >= max_deepness: self.RTTITypeDescriptor = descriptorAddr self.RTTIClassHierarchyDescriptor = hierarchyAddr else: self.RTTITypeDescriptor = RTTITypeDescriptor( descriptorAddr, deepness + 1) self.RTTIClassHierarchyDescriptor = RTTIClassHierarchyDescriptor( hierarchyAddr, deepness + 1) # TODO: add self.ObjectBase #short names self.rtd = self.RTTITypeDescriptor self.rhd = self.RTTIClassHierarchyDescriptor
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 decrypt_data(xref, cfunc, xref_args): print("%s: " % hex(int(xref)), end='') args = convert_args_to_long(xref_args) if args: try: key = idaapi.get_many_bytes( args[2], args[3] if idc.Dword(args[3]) == 0xffffffff else idc.Dword(args[3])) data = idaapi.get_many_bytes( args[0], args[1] if idc.Dword(args[1]) == 0xffffffff else idc.Dword(args[1])) except TypeError: print("Couldn't retrieve the cipher or the key.") print(xref_args) else: key = null_pad(key, 0x20) if args[4] == 1: data = custom_b64decode(data) plain = PKCS7_unpad( AES.new(key, AES.MODE_CBC, "\x00" * 16).decrypt(data)) #add_comment(cfunc, plain, xref) print(plain) else: print("Not all args are numbers") print(xref_args)
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 LocateStringLiterals(): seg = idc.FirstSeg() initArrayAddr = 0 while seg != idc.BADADDR: seg = idc.NextSeg(seg) segName = idc.SegName(seg) if segName == ".data.rel.ro": data_rel_ro = idc.SegStart(seg) break addr = data_rel_ro referedVars = [] while idc.SegName(addr) == ".data.rel.ro": for r in idautils.XrefsTo(addr, 0): referedVars.append(addr) break addr += 4 candidateMetadaUsages = [] for idx, var in enumerate(referedVars): if idx < (len(referedVars) - 1) and (referedVars[idx + 1] - referedVars[idx]) >= 1024: if idc.Dword(var) == 0x0: continue if IsDataFollowing(var) and idc.SegName(idc.Dword(var)) == '.bss': candidateMetadaUsages.append(var) for candidate in candidateMetadaUsages: for referedVar in referedVars: if referedVar == candidate: nextVar = referedVars[referedVars.index(referedVar) + 1] print "candidate: 0x%x, candidate end: 0x%x, data numbers: %d" % ( candidate, nextVar, (nextVar - candidate) / 4) break
def find_first_moduledata_addr(): first_moduledata_addr = idc.BADADDR if not is_stripped(): # not stripped, find firstmoduledata by symbol name common._debug("Binary file is not stripped") for addr, name in idautils.Names(): if name == "runtime.firstmoduledata": first_moduledata_addr = addr break else: # is stripped, find firstmodule data by bruteforce searching common._debug("Binary file is stripped") magic_num = pclntbl.Pclntbl.MAGIC # firstmoduledata is contained in segment [.noptrdata] mdata_seg_addr = get_mdata_seg_addr() if mdata_seg_addr == None: raise Exception("Invalid address of segment [.noptrdata]") if mdata_seg_addr == 0: common._error("Failed to find valid segment [.noptrdata]") curr_addr = mdata_seg_addr while curr_addr <= idc.BADADDR: if idc.Dword( idc.Dword(curr_addr) & 0xFFFFFFFF ) & 0xFFFFFFFF == magic_num: # possible firstmoduledata if test_firstmoduledata(curr_addr): break curr_addr += 4 if curr_addr >= idc.BADADDR: raise Exception("Failed to find firstmoduledata address!") first_moduledata_addr = curr_addr return first_moduledata_addr
def parse_function_tables(self): count = 0 for pattern in self.search(): name2func = {} ea = pattern.start while ea < pattern.stop: string_address = idc.Dword(ea + (pattern.name_element * pattern.element_size)) function_address = idc.Dword(ea + (pattern.function_element * pattern.element_size)) new_function_name = idc.GetString(string_address) current_function_name = idc.Name(function_address) if not self.valid_function_name(new_function_name): print "ERROR: '%s' is not a valid function name. This is likely not a function table, or I have parsed it incorrectly!" % new_function_name print " Ignoring all entries in the structures between 0x%X and 0x%X.\n" % ( pattern.start, pattern.stop) name2func = {} break elif current_function_name.startswith("sub_"): name2func[new_function_name] = function_address ea += (pattern.num_elements * pattern.element_size) for (name, address) in name2func.iteritems(): print "0x%.8X => %s" % (address, name) idc.MakeName(address, name) count += 1 print "Renamed %d functions!" % count
def get_typeinfo_by_metareg(typeaddr): global metadata value1 = idc.Dword(typeaddr + 0) value2 = idc.Dword(typeaddr + 4) attrs = (value2 >> 0) & 0xFFFF type = (value2 >> 16) & 0xFF num_mods = (value2 >> 24) & 0x3F byref = (value2 >> 30) & 0x1 pinned = (value2 >> 31) & 0x1 # IL2CPP_TYPE_CLASS, IL2CPP_TYPE_VALUETYPE if type == 0x12 or type == 0x11: #print(' type is class: index = %d' % value1) typedef = metadata.typeDefinitions[value1] return (True, typedef.name, value1, value2, attrs, type, num_mods, byref, pinned) # IL2CPP_TYPE_GENERICINST if type == 0x15: #print(' type is generic: index = %X' % value1) typename = get_generic_typename(value1) return (True, typename, value1, value2, attrs, type, num_mods, byref, pinned) if type >= len(primitive_types): return (True, '**type_%d' % type, value1, value2, attrs, type, num_mods, byref, pinned) return (False, primitive_types[type], value1, value2, attrs, type, num_mods, byref, pinned)
def get_count_addr(name, addr): n = idc.Dword(addr) addr = idc.Dword(addr + 4) #print(' %X: %d - %s' % (addr, n, name)) return (n, addr)
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 GetDyn(): phoff = idc.Dword(idc.MinEA() + 0x1c) + idc.MinEA() phnum = idc.Word(idc.MinEA() + 0x2c) phentsize = idc.Word(idc.MinEA() + 0x2a) for i in range(phnum): p_type = idc.Dword(phoff + phentsize * i) if p_type == 2: # PY_DYNAMIC dyn_addr = idc.Dword(phoff + phentsize * i + 8) return dyn_addr
def ParseDyn(dyn, tag): idx = 0 while True: v1, v2 = idc.Dword(dyn + idx * 0x8), idc.Dword(dyn + idx * 0x8 + 4) if v1 == 0 and v2 == 0: return if v1 == tag: return v2 idx += 1
def __init__(self, addr, deepness=0): super(InventoryInterface.Entry, self).__init__(addr, deepness) self.handleId = idc.Dword( self.addr + InventoryInterface.Entry.Offset.HandleId.value) self.ownerHandle = idc.Dword( self.addr + InventoryInterface.Entry.Offset.OwnerHandle.value) self.itemPosition = idc.Word( self.addr + InventoryInterface.Entry.Offset.ItemPosition.value) self.count = idc.Word(self.addr + InventoryInterface.Entry.Offset.Count.value)
def getPropTagArray(self, addr): cnt = idc.Dword(addr) if cnt == idc.BADADDR: return '' arr = [] for i in range(cnt): addr += 4 arr += [idc.Dword(addr)] return 'count:{0}\n[{1}]\n'.format(cnt, self.arrFormat(arr, '04X', ', '))
def get_handlers(ea): handlers = [] dw = idc.Dword(ea) hi_word = dw & 0xffff0000 while True: handlers.append(dw) ea += 4 dw = idc.Dword(ea) if dw & 0xffff0000 != hi_word: break return handlers
def dump_all(tab): while True: id = idc.Dword(tab) start = idc.Dword(tab + 4) end = idc.Dword(tab + 8) tab += 16 id = decode_id(id) print hex(id), hex(start), hex(end) if id == 0xFFFF: break dump_one(id, start, end)
def valid_count_and_addr(addr, count_min, count_max, addr_min, addr_max, nozero): count = idc.Dword(addr + 0) addr = idc.Dword(addr + 4) if nozero and (count == 0 or addr == 0): return False if count == 0 and addr == 0: return True return count >= count_min and count <= count_max and addr >= addr_min and addr < addr_max
def instrument(origin_op, origin_address): if origin_op.startswith('call'): if 1 == 1: op_length = idaapi.decode_insn(origin_address) if op_length == 6: ori_op.append(origin_op) ori_address.append(origin_address) args0.append(origin_address + 6) jump_add = (idc.Dword(origin_address + 2)) args1.append(jump_add) print("ori_address:", hex(origin_address), "call6") args2.append('call6') if op_length == 5: ori_op.append(origin_op) ori_address.append(origin_address) args0.append(origin_address + 5) jump_add = (idc.Dword(origin_address + 1) + 5 + origin_address) & 0xffffffff args1.append(jump_add) print("ori_address:", hex(origin_address), "call5") args2.append('call5') if origin_op.startswith('mov'): if idc.GetOpType(origin_address, 0) == 1 and idc.GetOpType( origin_address, 1) == 5: op_length = idaapi.decode_insn(origin_address) if op_length != 5: return ori_op.append(origin_op) ori_address.append(origin_address) ori_length.append(op_length) args0.append(idc.GetOpnd(origin_address, 0)) args1.append(int(idc.Dword(origin_address + 1))) args2.append('mov') print("ori_address:", hex(origin_address), "mov") #call address if origin_op.startswith('jz'): if 1 == 1: op_length = idaapi.decode_insn(origin_address) if op_length != 6: return ori_op.append(origin_op) ori_address.append(origin_address) args0.append(origin_address + 6) jump_add = (idc.Dword(origin_address + 2) + 6 + origin_address) & 0xffffffff args1.append(jump_add) args2.append('jz') print("ori_address:", hex(origin_address), "jz")
def make_func_table(enable, defaddr, name): n = idc.Dword(defaddr + 0) addr = idc.Dword(defaddr + 4) print(' %X/%d: %s' % (addr, n, name)) if enable and addr != 0: idc.MakeNameEx(addr, 'g_%s' % name, idc.SN_NOWARN | idc.SN_AUTO) for i in range(n): make_func(idc.Dword(addr + i * 4), i, name) return defaddr + 8
def resolveDispatcher(code): major = (code & 0x00ff0000) >> 0x10 minor = code & 0xff00ffff res = getMajorDispatchTableAddress() + major * 8 majorFlag = idc.Dword(res) majorAddress = idc.Dword(res + 4) if majorFlag != 0: return majorAddress + (minor * 0x10) #print "%x"% getMinorDispatchTableAddress(majorAddress) #print "resolved by 0x%x(%x)"% (majorAddress, minor) return majorAddress
def fixupSysctlSet(): ''' fixupSysctlSet: Fixes up the '__sysctl_set' segment, ensures the targets are actually 'sysctl_oid' structures and adds the correct function type to the handler. ''' segm = idaapi.get_segm_by_name("__DATA:__sysctl_set") if not segm: segm = idaapi.get_segm_by_name("__sysctl_set") if not segm: print "Could not find kernel __sysctl_set section" return segea = segm.startEA segend = segm.endEA sid = get_struc_id("sysctl_oid") ssize = get_struc_size(sid) stru = get_struc(sid) if ssize == 0: print "Could not load information about 'sysctl_oid' struct" return # clear whole range of sysctl_set segment idaapi.do_unknown_range(segea, segend - segea, DOUNK_DELNAMES) # idapython oldschool - we work with the structure offset oid_handler = get_member_by_name(stru, "oid_handler") # loop through sysctl_set segment while segea < segend: # Ensure pointer is a pointer idaapi.op_offset(segea, 0, idaapi.REF_OFF32, 0xffffffff, 0, 0) ptr = idc.Dword(segea) # Mark structure as sysctl_oid structure idaapi.do_unknown_range(ptr, ssize, DOUNK_DELNAMES) x = doStruct(ptr, ssize, sid) handler = idc.Dword(ptr + oid_handler.soff) # We have to support ARM THUMB code addr = handler & 0xFFFFFFFE # Set correct function type for oid_handler idc.SetType( addr, "int *oid_handler(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);" ) segea += 4
def __init__(self, ea): self.property_list = list() # print '%08x: Parsing properties' % ea entry_size = idc.Dword(ea) num_entries = idc.Dword(ea + 4) ea = ea + 8 for i in range(num_entries): var_name = idc.GetString(idc.Dword(ea), -1, idc.ASCSTR_C) var_type = idc.GetString(idc.Dword(ea + 4), -1, idc.ASCSTR_C) self.property_list.append({'name': var_name, 'type': var_type}) ea = ea + entry_size return
def parse(self): self.arg1 = idc.Dword(self.ea) self.arg2 = idc.Dword(self.ea + 4) func_addr = idc.Dword(self.ea + 8) self.rel_func = get_rel(func_addr) if self.rel_func not in node_funcs: print("*"*40) print("Did not find the following function") print(hex(func_addr)) print("*"*40) self.t = node_funcs[self.rel_func] if self.is_arr: self.num_child = idc.Dword(self.ea + 12) self.parse_children()
def __PltResolver(jmprel,strtab,symtab,pltgot): seg_sec = idc.SegByName('.plt.sec') sec_start = idc.SegByBase(seg_sec) sec_end = idc.SegEnd(sec_start) if sec_start == idaapi.BADADDR: print "[-] can't find .plt.sec segment" return idx=0 while True: r_off = idc.Dword(jmprel+0x8*idx) r_info1 = idc.Byte(jmprel+0x8*idx+0x4) r_info2 = idc.Byte(jmprel+0x8*idx+0x5) if r_off > 0x7fffffff: return if r_info1 == 7: st_name = idc.Dword(symtab+r_info2*0x10) name = idc.GetString(strtab+st_name) # rename got idc.set_name(r_off,name+'_ptr') plt_func = idc.Dword(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)) got_off = r_off-pltgot target = '+{}h'.format(hex(got_off).lower().replace('0x','').replace('l','').rjust(2,'0')) for func_ea in idautils.Functions(sec_start,sec_end): func = idaapi.get_func(func_ea) cur = func.startEA end = func.endEA find=False while cur <= end: code = idc.GetDisasm(cur).lower().replace(' ','') if target in code: find=True break cur = idc.NextHead(cur, end) if find: idc.set_name(func_ea,'_'+name) SetFuncFlags(func_ea) idx+=1
def __init__(self, ea): self.method_list = list() # print '%08x: Parsing methods' % ea entry_size = idc.Dword(ea) num_entries = idc.Dword(ea + 4) ea = ea + 8 for i in range(num_entries): method_name = idc.GetString(idc.Dword(ea), -1, idc.ASCSTR_C) method_type = idc.GetString(idc.Dword(ea + 4), -1, idc.ASCSTR_C) method_ea = idc.Dword(ea + 8) self.method_list.append({'name': method_name, 'type':method_type, 'addr':method_ea}) ea = ea + entry_size return
def __init__(self, addr, deepness=0): super(RTTIClassHierarchyDescriptor, self).__init__(addr, deepness) signatureAddr = addr + RTTIClassHierarchyDescriptor.Offset.signature.value attributesAddr = addr + RTTIClassHierarchyDescriptor.Offset.attributes.value numberOfItemsAddr = addr + RTTIClassHierarchyDescriptor.Offset.numberOfItems.value baseClassHierarchyArrAddr = RVA( idc.Dword( addr + RTTIClassHierarchyDescriptor.Offset.rvaBaseClassArrRef.value)) self.signature = idc.Dword(signatureAddr) self.attributes = idc.Dword(attributesAddr) self.numberOfItems = idc.Dword(numberOfItemsAddr) self.baseClassHierarchyArray = baseClassHierarchyArrAddr
def dump_memory_region(ea): idc.MakeStruct(ea, "MEMORY_REGION") id = idc.Dword(ea) low = idc.Dword(ea + 8) high = idc.Dword(ea + 0xC) intv = idc.Dword(ea + 0x14) name = idc.Dword(ea + 0x20) memory_region = idc.GetString(name, -1, idc.ASCSTR_C) print " flags: 0x%04x - int 0x%x- reg: %10s - low 0x%08x / high 0x%08x" % ( id, intv, memory_region, low, high) if memory_region.startswith("MR"): idc.set_name(ea, memory_region, idc.SN_PUBLIC)
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)