def renameDword(self): proc_addr = self._import_table.item(self._import_table.currentRow(), 3).text() proc_name = str(self._import_table.item(self._import_table.currentRow(), 2).text()) renamed = 0 if proc_addr: try: proc_addr = int(proc_addr, 16) proc_bin_str = " ".join([x.encode("hex") for x in struct.pack("<I", proc_addr)]) next_dword = idc.FindBinary(idc.MinEA(), idc.SEARCH_DOWN|idc.SEARCH_NEXT, proc_bin_str) while next_dword != idc.BADADDR: log.debug("Trying to fix-up 0x{:08x}".format(next_dword)) # DWORDs can be "inaccessible" for many reasons and it requires "breaking up" the data blobs # and manually fixing them # Reason 1: In a dword array in an unknown section if idc.isUnknown(next_dword): idc.MakeUnkn(next_dword, idc.DOUNK_EXPAND) idc.MakeDword(next_dword) # Reason 2: In a dword array in a data section elif idc.isData(next_dword): hd = idc.ItemHead(next_dword) idc.MakeDword(hd) idc.MakeDword(next_dword) # Reason 3: In a dword array in a code section (validate via "dd <dword>,") elif idc.isCode(next_dword) and idc.GetDisasm(next_dword).startswith("dd "): hd = idc.ItemHead(next_dword) idc.MakeDword(hd) idc.MakeDword(next_dword) # Only perform if idc.Name(next_dword).startswith(("off_", "dword_")) or idc.Name(next_dword) == "": success = idc.MakeNameEx(next_dword, proc_name, idc.SN_NOWARN|idc.SN_NON_AUTO) i = 0 new_proc_name = proc_name while not success and i < 10: new_proc_name = "{}{}".format(proc_name, i) success = idc.MakeNameEx(next_dword, new_proc_name, idc.SN_NOWARN|idc.SN_NON_AUTO) i += 1 if success: renamed += 1 item = self._import_table.item(self._import_table.currentRow(), 5) item.setText("{}, {}".format(str(item.text()), new_proc_name)) log.debug("DWORD @ 0x{:08x} now has name {}".format(next_dword, new_proc_name)) else: log.error("Unable to auto-rename successfully, terminating search") break else: log.debug("Value at 0x{:08x} does not meet renaming requirements".format(next_dword)) next_dword = idc.FindBinary(next_dword+4, idc.SEARCH_DOWN|idc.SEARCH_NEXT, proc_bin_str) except Exception, e: log.error("Error encountered: {}".format(e)) log.debug("Renamed {:d} instances of {}".format(renamed, proc_name))
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 make_dwords_in_handlers_tab(handlers_tab, count): ea = handlers_tab for i in range(count): undefDword(ea) idc.MakeDword(ea) ea += 4
def readDefinition(self, ea): # Read all the fields from the stream. self.fields_address = MakeAndGetDword(ea, "fields address") self.index = MakeAndGetDword(ea + 4, "index") self.upgrade_proc = MakeAndGetDword(ea + 8, "upgrade function") idc.MakeDword(ea + 12) self.size_of = MakeAndGetDword(ea + 16, "size of field set")
def parse_hdr(self): ''' Refer: function [go12Init()] in https://golang.org/src/debug/gosym/pclntab.go ''' magic = idc.Dword(self.start_addr) & 0xFFFFFFFF if magic != Pclntbl.MAGIC: print magic, Pclntbl.MAGIC common._error("Invalid pclntbl header magic number!") idc.Exit(1) #raise Exception("Invalid pclntbl header magic number!") idc.MakeDword(self.start_addr) idc.MakeComm(self.start_addr, "Magic Number") idc.MakeNameEx(self.start_addr, "runtime_symtab", flags=idaapi.SN_FORCE) idaapi.autoWait() if idc.Word(self.start_addr + 4) & 0xFFFF != 0: raise Exception("Invalid pclntbl header") idc.MakeWord(self.start_addr + 4) self.min_lc = idc.Byte(self.start_addr + 6) & 0xFF if (self.min_lc != 1) and (self.min_lc != 2) and (self.min_lc != 4): raise Exception("Invalid pclntbl minimum LC!") idc.MakeComm(self.start_addr + 6, "instruction size quantum") idaapi.autoWait() self.ptr_sz = idc.Byte(self.start_addr + 7) & 0xFF if (self.ptr_sz != 4) and (self.ptr_sz != 8): raise Exception("Invalid pclntbl pointer size!") idc.MakeComm(self.start_addr + 7, "ptr size") idaapi.autoWait()
def makeDQWord(self, api): match = re.search(r"\((?P<bitness>..)bit\)", api[2]) if match: bitness = int(match.group("bitness")) if bitness == 32: idc.MakeDword(api[0]) elif bitness == 64: idc.MakeQword(api[0])
def MakeReg(name, offset, size, count=0): idc.MakeNameEx(offset, name, idc.SN_NOCHECK | idc.SN_NOWARN) if (size == 1): idc.MakeByte(offset) elif size == 2: idc.MakeWord(offset) elif size == 4: idc.MakeDword(offset) else: raise NotImplementedError("Register size invalid! Name: " + name) if (count != 0): idc.make_array(offset, count)
def make_data(addr, index, name, classname): if index == 0: print(' %s[%d] = %X' % (name, index, addr)) print(' :') if addr == 0: return if classname == 'int': idc.MakeDword(addr) else: idc.MakeStruct(addr, classname) idc.MakeNameEx(addr, 'g_%s_%X' % (name, addr), idc.SN_NOWARN | idc.SN_AUTO)
def rngmkd(start_ea, end_ea): """ Turns the data in the range to words. If not aligned with words, turns into bytes instead :param start_ea: start of the range :param end_ea: end of the range """ ea = start_ea while ea % 4 != 0: print('%07X: -> byte' % ea) idc.MakeByte(ea) ea += 1 while ea < end_ea: print('%07X: -> word' % ea) idc.MakeDword(ea) ea += 4
def main(): for segstart, segend, segname in enum_segments(): if segname not in ('.text', '.data'): continue for src, dst in find_pointers(segstart, segend): if is_code(src): # ignore instructions like: # # call ds:__vbaGenerateBoundsError #print('code pointer: 0x%x -> 0x%x' % (src, dst)) continue # TODO: fix this: just look at the few previous bytes and ensure they are ASCII/Unicode if is_in_string(src): # for example, the following contains 0x444974 (a common valid offset): # # text:004245B0 aRequestid db 'requestID', # # enable or disable this behavior as you wish print('string pointer: 0x%x -> 0x%x' % (src, dst)) pass #continue print('pointer from 0x%x to 0x%x' % (src, dst)) if is_unknown(dst): print('destination unknown, making byte: 0x%x' % (dst)) idc.MakeByte(dst) elif is_head(dst): # things are good pass else: # need to undefine head, and make byte head_va = get_head(dst) print('destination overlaps with head: 0x%x' % (head_va)) idc.MakeUnkn(head_va, dst - head_va) idc.MakeByte(head_va) idc.MakeByte(dst) idc.MakeUnkn(src, 4) idc.MakeDword(src) # this doesn't seem to always work :-( # ref: https://reverseengineering.stackexchange.com/questions/17798/how-can-i-mark-a-global-variable-as-an-offset-using-idapython #idc.OpOffset(src, 0) ida_offset.op_offset(src, 0, idc.REF_OFF32)
def MakeN(addr, size): ''' Make a integer with the given size at the given address. Args: addr (int): effective address. size (int): the size of the integer, one of 1, 2, 4, or 8. ''' if size == 1: idc.MakeByte(addr) elif size == 2: idc.MakeWord(addr) elif size == 4: idc.MakeDword(addr) elif size == 8: idc.MakeQword(addr)
def datify(self): ea = self.get_start_ea(self.DATA) if ea == idc.BADADDR: ea = idc.FirstSeg() print "Converting remaining data to DWORDs...", while ea != idc.BADADDR: flags = idc.GetFlags(ea) if idc.isUnknown(flags) or idc.isByte(flags): idc.MakeDword(ea) idc.OpOff(ea, 0, 0) ea = idc.NextAddr(ea) print "done."
def MakeAndGetDword(ea, comment=None): """ Creates a dword at the specified address and returns the dword value. :param ea: address to make dword at :param comment: optional comment to place at the specified address :return: the value of the dword at the specified address """ # Make the dword. idc.MakeDword(ea) # Check if the comment is valid and if so place it at the address. if comment is not None: idc.MakeComm(ea, comment) # Get the dword value. return idc.Dword(ea)
def main(): for segstart, segend, segname in enum_segments(): if segname not in ('.text', '.data'): continue for src, dst in find_pointers(segstart, segend): if is_code(src): # ignore instructions like: # # call ds:__vbaGenerateBoundsError #print('code pointer: 0x%x -> 0x%x' % (src, dst)) continue if is_in_string(src): # for example, the following contains 0x444974 (a common valid offset): # # text:004245B0 aRequestid db 'requestID', # # enable or disable this behavior as you wish print('string pointer: 0x%x -> 0x%x' % (src, dst)) pass #continue print('pointer from 0x%x to 0x%x' % (src, dst)) if is_unknown(dst): print('destination unknown, making byte: 0x%x' % (dst)) idc.MakeByte(dst) elif is_head(dst): # things are good pass else: # need to undefine head, and make byte head_va = get_head(dst) print('destination overlaps with head: 0x%x' % (head_va)) idc.MakeUnkn(head_va, dst - head_va) idc.MakeByte(head_va) idc.MakeByte(dst) idc.MakeUnkn(src, 4) idc.MakeDword(src) # this doesn't seem to always work :-( idc.OpOffset(src, 0)
def datify(self): ea = self.get_start_ea(self.DATA) if ea == idc.BADADDR: ea = idc.FirstSeg() self.say("Converting remaining data to DWORDs...", ) while ea != idc.BADADDR: flags = idc.GetFlags(ea) if (idc.isUnknown(flags) or idc.isByte(flags)) and ((ea % 4) == 0): idc.MakeDword(ea) idc.OpOff(ea, 0, 0) ea = idc.NextAddr(ea) self.say("done.") self._fix_data_offsets()
def arr2dword(pointerRange): d = Data.Data(pointerRange[0]) outputStatus = True while (d.ea < pointerRange[1]): content = d.getContent() # case: byte array that's 4 elements. Likely a word if type(content) == list and len(content) == 4 and (d.getSize() / len(content) == 1): # transform to dword status = idc.del_items(d.ea) status = status and idc.MakeDword(d.ea) outputStatus = outputStatus and status if status: print('[OK] %07X: u8[4] -> u32 %07X' % (d.ea, d.getContent())) else: print('[FAIL] %07X: u8[4] -> u32' % d.ea) # advance 4 bytes d = Data.Data(d.ea + 4) else: d = Data.Data(d.ea + d.getSize()) return outputStatus
def annotate_vector_table(self, vtoffset=0x0000000000): ''' Name the vector table entries according to docs: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABIFJFG.html Vector tables can appear in mulitple places in device flash Functions are not renamed because multiple vectors might point to a single function Append the address of the VT entry to the name from self.annotations to keep unique names ''' for annotation_index in range(len(self.annotations)): entry_addr = vtoffset + 4 * annotation_index entry_name = "%s_%08x" % (self.annotations[annotation_index], entry_addr) idc.MakeDword(entry_addr) ida_name.set_name(entry_addr, entry_name, 0) # get the bytes of the vt entry dword = idc.Dword(entry_addr) if dword != 0: # print "ea %08x = 0x%08x" % (ea, dword) idc.MakeCode(dword - 1) idc.MakeFunction(dword - 1) # TODO fix the offsets created here # for thumb, they show to be off by a byte # one of the end args controls stuff about this idc.OpOffEx(entry_addr, 0, idaapi.REF_OFF32, -1, 0, 0) instruction = idc.Word(dword - 1) # functions like this are common if instruction == 0xe7fe: idc.SetFunctionCmt(dword - 1, 'Infinite Loop', 1)
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
def ida_make_offset(f, ea): if f.armv7: idc.MakeDword(ea) else: idc.MakeQword(ea) idc.OpOff(ea, 0, 0)
idc.set_name(ea, memory_region, idc.SN_PUBLIC) else: idc.set_name(ea, "MR_" + memory_region, idc.SN_PUBLIC) # for iLO5 1.30.35 START_ADDR = 0x410CCC74 # for iLO5 1.20.33 START_ADDR = 0x410CBC74 # for iLO5 1.37.06 START_ADDR = 0x410CCC84 ea = START_ADDR mod_base = START_ADDR print "> parsing memory region entries:\n" while True: idc.MakeDword(ea) struct_addr = idc.Dword(ea) if struct_addr == 0: break x = idc.SetType(ea, "MEMORY_REGION *") dump_memory_region(struct_addr) ea += 4 print "[+] job done captain!"
def readDefinition(self, ea): # Read all the fields from the stream. self.address = ea self.display_name_address = MakeAndGetDword(ea) self.name_address = MakeAndGetDword(ea + 4) self.flags = MakeAndGetDword(ea + 8, "flags") self.maximum_element_count = MakeAndGetDword(ea + 12, "maximum element count") self.maximum_element_count_string_address = MakeAndGetDword( ea + 16, "maximum element count string") self.field_sets_address = MakeAndGetDword(ea + 20, "field sets") self.field_set_count = MakeAndGetDword(ea + 24, "number of field sets") self.field_set_latest_address = MakeAndGetDword( ea + 28, "latest field set") idc.MakeDword(ea + 32) self.postprocess_proc = MakeAndGetDword(ea + 36, "postprocessing function") self.format_proc = MakeAndGetDword(ea + 40, "format function") self.generate_default_proc = MakeAndGetDword( ea + 44, "generate default function") self.dispose_element_proc = MakeAndGetDword( ea + 48, "dispose element function") # Read the strings. self.display_name_str = ReadString(self.display_name_address) self.name_str = ReadString(self.name_address) self.maximum_elements_count_str = ReadString( self.maximum_element_count_string_address) # Name the definition address. idc.MakeNameEx(self.address, self.name_str, idc.SN_NON_PUBLIC) # Check if we should comment the display name. if self.display_name_address < g_BaseAddress: idc.MakeComm(ea, self.display_name_str) # Check if we should comment the name. if self.name_address < g_BaseAddress: idc.MakeComm(ea + 4, self.name_str) # Check if we should comment the maximum elements count. if self.maximum_element_count_string_address < g_BaseAddress: idc.MakeComm(ea + 12, self.maximum_elements_count_str) # Create the postprocess function. if self.postprocess_proc != 0: idc.MakeNameEx(self.postprocess_proc, "%s_postprocess" % self.name_str, idc.SN_NON_PUBLIC) # Create the format proc. if self.format_proc != 0: idc.MakeNameEx(self.format_proc, "%s_format" % self.name_str, idc.SN_NON_PUBLIC) # Create the generate default proc. if self.generate_default_proc != 0: idc.MakeNameEx(self.generate_default_proc, "%s_generate_default" % self.name_str, idc.SN_NON_PUBLIC) # Create the dispose element proc. if self.dispose_element_proc != 0: idc.MakeNameEx(self.dispose_element_proc, "%s_dispose_element" % self.name_str, idc.SN_NON_PUBLIC) # Check for the special case sound_block. if self.name_str == "sound_block": return # Loop through all of the field sets and read each one. for i in range(self.field_set_count): # Get the address of the current field set. fieldSetAddress = self.field_sets_address + (i * tag_field_set.kSizeOf) # Read the current field set. fieldSet = tag_field_set() fieldSet.readDefinition(fieldSetAddress) # Check if this is the latest version field set. if fieldSetAddress == self.field_set_latest_address: idc.MakeNameEx(fieldSetAddress, "%s_latest" % self.name_str, idc.SN_NON_PUBLIC) else: idc.MakeNameEx(fieldSetAddress, "%s_v%d" % (self.name_str, i), idc.SN_NON_PUBLIC) # Add the field set to the field set list. self.field_sets.append(fieldSet)
def main(): print("[*] loading crypto constants") for const in non_sparse_consts: const["byte_array"] = convert_to_byte_array(const) for start in idautils.Segments(): print("[*] searching for crypto constants in %s" % idc.SegName(start)) ea = start while ea < idc.SegEnd(start): bbbb = list( struct.unpack("BBBB", idc.GetManyBytes(ea, 4) or "AAAA")) for const in non_sparse_consts: if bbbb != const["byte_array"][:4]: continue if map( lambda x: ord(x), idc.GetManyBytes(ea, len(const["byte_array"])) or list()) == const["byte_array"]: print(("0x%0" + str(digits) + "X: found const array %s (used in %s)") % (ea, const["name"], const["algorithm"])) idc.MakeName(ea, const["name"]) if const["size"] == "B": idc.MakeByte(ea) elif const["size"] == "L": idc.MakeDword(ea) elif const["size"] == "Q": idc.MakeQword(ea) MakeArray(ea, len(const["array"])) ea += len(const["byte_array"]) - 4 break ea += 4 #print "ea: 0x%x " % ea ea = start if idc.GetSegmentAttr(ea, SEGATTR_TYPE) == 2: while ea < idc.SegEnd(start): d = idc.Dword(ea) for const in sparse_consts: if d != const["array"][0]: continue tmp = ea + 4 for val in const["array"][1:]: for i in range(8): if idc.Dword(tmp + i) == val: tmp = tmp + i + 4 break else: break else: print(("0x%0" + str(digits) + "X: found sparse constants for %s") % (ea, const["algorithm"])) cmt = idc.GetCommentEx(idc.prev_head(ea), 0) if cmt: idc.CommentEx(idc.prev_head(ea), cmt + ' ' + const["name"], 0) else: idc.CommentEx(idc.prev_head(ea), const["name"], 0) ea = tmp break ea += 1 print("[*] finished")
def MakeDWord(self, ea): if idaapi.IDA_SDK_VERSION < 700: return idc.MakeDword(ea) else: return ida_bytes.create_data(ea, FF_DWORD, 4, idaapi.BADADDR)
def locateLocalConstants(self, scs, sds): """Locate and define all of the local strings / numeric constants, that match our observed pattern. Args: scs (list): List of (sark) code segments. sds (list): List of (sark) data segments. """ self._analyzer.logger.info( "Locating local strings / constants in the code sections") for sc in scs: cur_ea = pad(sc.startEA, self._local_alignment) while cur_ea < sc.endEA: # check for a data constant if self.isDataConstant(cur_ea): # check for a string (refs already checked) if self._analyzer.str_identifier.isLocalAsciiString( cur_ea, check_refs=False): length = self._analyzer.str_identifier.defineAsciiString( cur_ea) padded_length = pad(length, self._local_alignment) if padded_length != length: idc.MakeUnknown(cur_ea + length, padded_length - length, 0) idc.MakeData(cur_ea + length, 0, padded_length - length, 0) cur_ea += padded_length # This means it is a constant else: if self._local_pad is None: idc.MakeData(cur_ea, 0, self._local_alignment, 0) else: # check the size of the constant using the byte padding for offset in xrange(self._local_alignment - 1, -1, -1): if idc.Byte(cur_ea + offset) != self._local_pad: break # prepare the bytes idc.MakeUnknown(cur_ea, self._local_alignment, 0) # the data constant - try to make it pretty if offset + 1 == 2: idc.MakeWord(cur_ea) elif offset + 1 == 4: idc.MakeDword(cur_ea) elif offset + 1 == 8: idc.MakeQword(cur_ea) else: idc.MakeData(cur_ea, 0, offset + 1, 0) # the padding idc.MakeData(cur_ea + offset + 1, 0, self._local_alignment - offset + 1, 0) # Now check for a pointer (only supports code pointers for now) if offset + 1 == self._analyzer.addressSize(): value = self._analyzer.parseAdderss(cur_ea) # only support pointers inside our local segment (more probable) if sc.startEA <= value and value < sc.endEA: self._analyzer.markCodePtr( cur_ea, value, aggressive=False) # try a pointer to a declared string else: for sd in sds: if sd.startEA <= value and value <= sd.endEA: line = sark.Line(value) if line.is_string and line.startEA == value: self._analyzer.markDataPtr( cur_ea, value, aggressive=False) break # now move onward cur_ea += self._local_alignment # found nothing, move on else: cur_ea += self._local_alignment
if (xr2.type == 19) and (xr2.to == next_next): db = head + idaapi.get_item_size(head) if idc.Byte(head) == 0x0F: idaapi.patch_byte(head, 0x90) idaapi.patch_byte(head + 1, 0xE9) else: idaapi.patch_byte(head, 0xEB) idc.MakeUnknown(db, xr.to - db + 0x10, idaapi.DOUNK_SIMPLE) idc.MakeCode(xr.to) i = db while i < xr.to: if (i + 4) < xr.to: idc.MakeDword(i) i += 4 else: idc.MakeByte(i) i += 1 idaapi.analyze_area(head - 0x40, head + 0x40) idaapi.analyze_area(xr.to - 0x40, xr.to + 0x40) for head in idautils.Heads(): if idc.Byte(head) == 0xE8: for xr in idautils.XrefsFrom(head, 0): # Find direct call targets if not (xr.type == 21): idc.MakeFunction(xr.to)
def map_metadata(file, addr): flags = 0 flags |= 0x0001 # NEF_SEGS size = os.stat(file).st_size li = idaapi.open_linput(file, False) #print('li = %s' % str(li)) rc = idaapi.load_binary_file(file, li, flags, 0, 0, addr, size) #print('rc = %d' % rc) names = [ 'stringLiteral', 'stringLiteralData', 'strings', 'events', 'properties', 'methods', 'parameterDefaultValues', 'fieldDefaultValues', 'fieldAndParameterDefaultValueData', 'fieldMarshaledSizes', 'parameters', 'fields', 'genericParameters', 'genericParameterConstraints', 'genericContainers', 'nestedTypes', 'interfaces', 'vtableMethods', 'interfaceOffsets', 'typeDefinitions', 'rgctxEntries', 'images', 'assemblies', 'metadataUsageLists', 'metadataUsagePairs', 'fieldRefs', 'referencedAssemblies', 'attributesInfo', 'attributeTypes', ] baseaddr = addr idc.MakeDword(addr + 0) idc.MakeNameEx(addr + 0, 'META_Sig', idc.SN_NOWARN | idc.SN_AUTO) idc.MakeDword(addr + 4) idc.MakeNameEx(addr + 0, 'META_Version', idc.SN_NOWARN | idc.SN_AUTO) for i in range(len(names)): descaddr = baseaddr + 8 + i * 8 idc.MakeStruct(descaddr, 'OffsetAndCount') idc.MakeNameEx(descaddr, 'META_%sDesc' % names[i], idc.SN_NOWARN | idc.SN_AUTO) dataaddr = baseaddr + idc.Dword(descaddr + 0) datasize = idc.Dword(descaddr + 4) idc.MakeNameEx(dataaddr, 'META_%s' % names[i], idc.SN_NOWARN | idc.SN_AUTO) # string literal descaddr = idc.LocByName('META_stringLiteralDesc') size1 = idc.Dword(descaddr + 4) addr1 = idc.LocByName('META_stringLiteral') addr1end = addr1 + size1 addr2 = idc.LocByName('META_stringLiteralData') #print('addr1: %X' % (addr1)) #print('addr2: %X' % (addr2)) while addr1 < addr1end: strsize = idc.Dword(addr1 + 0) stroff = idc.Dword(addr1 + 4) #print('%X - %X' % (addr2 + stroff, addr2 + stroff + strsize)) idc.MakeStr(addr2 + stroff, addr2 + stroff + strsize) addr1 += 8 idc.Jump(baseaddr)
def load_file(f, neflags, format): ''' load the given file into the current IDA Pro database. Args: f (file): the file-like object to load. neflags (Any): unused format (Any): unused Returns: int: 1 on success, 0 on failure ''' # compute file size, then read the entire contents f.seek(0x0, os.SEEK_END) flen = f.tell() f.seek(0x0) buf = f.read(flen) # mark the proc type, so IDA can invoke the correct disassembler/processor. # this must match `processor.wasm_processor_t.psnames` idaapi.set_processor_type('wasm', idaapi.SETPROC_ALL) f.seek(0x0) # load the entire file directly at address zero. f.file2base(0, 0, len(buf), True) p = 0 sections = wasm.decode.decode_module(buf) for i, section in enumerate(sections): if i == 0: sname = 'header' else: if section.data.id == 0: # fetch custom name sname = '' else: sname = idawasm.const.WASM_SECTION_NAMES.get( section.data.id, 'unknown') if sname != 'header' and section.data.id in ( wasm.wasmtypes.SEC_CODE, wasm.wasmtypes.SEC_GLOBAL): stype = 'CODE' else: stype = 'DATA' # add IDA segment with type, name, size as appropriate slen = sum(section.data.get_decoder_meta()['lengths'].values()) idaapi.add_segm(0, p, p + slen, sname, stype) if sname != 'header': loader = SECTION_LOADERS.get(section.data.id) if loader is not None: loader(section, p) load_section(section, p) p += slen # magic idc.MakeDword(0x0) idc.MakeName(0x0, 'WASM_MAGIC') # version idc.MakeDword(0x4) idc.MakeName(0x4, 'WASM_VERSION') return 1