def load_file(f, neflags, format): idaapi.set_processor_type("arm:armv8", idaapi.SETPROC_LOADER) f.seek(-0x20, os.SEEK_END) nseg, = struct.unpack("<12xI16x", f.read(0x20)) print(f"Number of segments: {nseg}") for sno in range(nseg): f.seek(-0x20-0x20*(nseg-sno), os.SEEK_END) mem_addr, file_addr, size, name = struct.unpack("<QII8x8s", f.read(0x20)) name, _, _ = name.partition(b'\0') name = name.decode() print(f"Segment {sno}: {name} at mem={hex(mem_addr)} file={hex(file_addr)} size={hex(size)}") ida_seg_type = None if name == "__TEXT": ida_seg_type = "CODE" if name == "__DATA": ida_seg_type = "DATA" idaapi.add_segm(0, mem_addr, mem_addr + size, name, ida_seg_type) f.file2base(file_addr, mem_addr, mem_addr + size, True) f.seek(-0x20-0x20*nseg, os.SEEK_END) footer_start = f.tell() footer_end = footer_start + 0x20 + 0x20 * nseg idaapi.add_segm(0, footer_start, footer_end, "__FOOTER", "DATA") f.file2base(footer_start, footer_start, footer_end, True) header_start = footer_start + 0x20 * nseg idaapi.add_extra_line(header_start, True, "") idaapi.add_extra_cmt(header_start, True, f"File Header") idaapi.create_strlit(header_start, 4, 0) idaapi.set_cmt(header_start, "Magic", False) idaapi.create_dword(header_start + 4, 4) idaapi.set_cmt(header_start + 4, "Version?", False) idaapi.create_dword(header_start + 8, 4) idaapi.set_cmt(header_start + 8, "File length minus headers", False) idaapi.create_dword(header_start + 12, 4) idaapi.set_cmt(header_start + 12, "Section count", False) for sno in range(nseg): header_start = footer_start + 0x20 * sno idaapi.add_extra_line(header_start, True, "") idaapi.add_extra_cmt(header_start, True, f"Segment {sno + 1}") idaapi.create_qword(header_start, 8) idaapi.set_cmt(header_start, "Memory Address", False) idaapi.create_dword(header_start + 8, 4) idaapi.set_cmt(header_start + 8, "File Offset", False) idaapi.create_dword(header_start + 12, 4) idaapi.create_qword(header_start + 16, 8) idaapi.set_cmt(header_start + 12, "Segment Length", False) idaapi.create_strlit(header_start + 24, 8, 0) idaapi.set_cmt(header_start + 24, "Segment Name", False) idaapi.add_entry(0, 0, "start", 1) return 1
def create_dword_and_name(offset, name): """ Apply dword type to offset and name it :param offset: Offset of word :param name: Name to apply """ idaapi.create_dword(offset, 4) idaapi.set_name(offset, name, idaapi.SN_NOWARN|idaapi.SN_NOLIST|idaapi.SN_NOCHECK)
def do_dll_imports(dll, iatCurr, hashes): idaapi.msg("%lx: processing import hashes for dll %s\n" % (iatCurr, dll)) hash2name = HashExportNames(dll) for h in hashes: if h in hash2name: idaapi.create_dword(iatCurr, 4) idaapi.set_name( iatCurr, hash2name[h], idaapi.SN_NOWARN | idaapi.SN_NOLIST | idaapi.SN_NOCHECK) else: idaapi.msg( "%lx: hash value %lx for dll %s could not be found\n" % iatCurr, h, dll) iatCurr += 4
def __init__(self, ea): print("Processing Class Hierarchy Descriptor at 0x%x" % ea) del_items(ea, get_struc_size(self.tid), DELIT_DELNAMES) if create_struct(ea, get_struc_size(self.tid), self.tid): baseClasses = get_32bit( ea + get_member_by_name(get_struc( self.tid), "pBaseClassArray").soff) + u.x64_imagebase() nb_classes = get_32bit( ea + get_member_by_name(get_struc(self.tid), "numBaseClasses").soff) print("Baseclasses array at 0x%x" % baseClasses) # Skip the first base class as it is itself (could check) self.bases = [] for i in range(1, nb_classes): baseClass = get_32bit(baseClasses + i * 4) + u.x64_imagebase() print("base class 0x%x" % baseClass) create_dword(baseClasses + i * 4, 4) op_offset(baseClasses + i * 4, -1, u.REF_OFF | REFINFO_RVA, -1, 0, 0) create_struct(baseClass, RTTIBaseClassDescriptor.size, RTTIBaseClassDescriptor.tid) typeDescriptor = get_32bit(baseClass) + u.x64_imagebase() self.bases.append( RTTITypeDescriptor(typeDescriptor).class_name)
def make_dword(self, offset): """Create a dword at the given offset in the IDB""" self.ret = idaapi.create_dword(offset, 4) return self.ret
def add_port_4(ea, name): idaapi.set_name(ea, name) idaapi.create_dword(ea, 4)
def load_file(li, neflags, format): # Not clear why this is necessary given the return value from accept_file, # but IDA will quit if you don't include this. idaapi.set_processor_type("metapc", idaapi.SETPROC_LOADER) # This boolean will be set if IDA is "reloading" the file as opposed to # loading it for the first time, i.e., File->Load File->Reload Input File. # We just ignore requests to reload. bReload = (neflags & idaapi.NEF_RELOAD) != 0 if bReload: return 1 # Parse the header again li.seek(0) rawData = li.read(HBHEADER_SIZE) head = HBHeader._make(struct.unpack(HBHEADER_FMT, rawData)) # Add a code segment seg = idaapi.segment_t() seg.start_ea = 0 seg.end_ea = head.mod_size seg.bitness = 1 idaapi.add_segm_ex(seg, HBSEGNAME, "CODE", 0) # Read the contents of the file into the code segment we just created li.seek(0) li.file2base(0, 0, head.mod_size, False) # Create data items for the header fields and give them names idaapi.create_dword(0x00, 4) idaapi.set_name(0x00, "HBHDR_Magic", idaapi.SN_NOWARN | idaapi.SN_NOLIST | idaapi.SN_NOCHECK) idaapi.create_word(0x04, 2) idaapi.set_name(0x04, "HBHDR_DllList", idaapi.SN_NOWARN | idaapi.SN_NOLIST | idaapi.SN_NOCHECK) idaapi.create_word(0x06, 2) idaapi.set_name(0x06, "HBHDR_IAT", idaapi.SN_NOWARN | idaapi.SN_NOLIST | idaapi.SN_NOCHECK) idaapi.create_dword(0x08, 4) idaapi.set_name(0x08, "HBHDR_EntryPoint", idaapi.SN_NOWARN | idaapi.SN_NOLIST | idaapi.SN_NOCHECK) idaapi.create_dword(0x0C, 4) idaapi.set_name(0x0C, "HBHDR_ModuleSize", idaapi.SN_NOWARN | idaapi.SN_NOLIST | idaapi.SN_NOCHECK) idaapi.create_dword(0x10, 4) idaapi.set_name(0x10, "HBHDR_RelocationsSize", idaapi.SN_NOWARN | idaapi.SN_NOLIST | idaapi.SN_NOCHECK) idaapi.create_dword(0x14, 4) idaapi.set_name(0x14, "HBHDR_Relocations", idaapi.SN_NOWARN | idaapi.SN_NOLIST | idaapi.SN_NOCHECK) # Add the module's entrypoint as an entrypoint in IDA idaapi.add_entry(head.ep, head.ep, "start", 1) # Load a type library so that the imports will show proper names and types. # I'm not sure why idaapi.load_til doesn't do what I want, but it doesn't. idc.LoadTil("mssdk_win7") # Parse the import table in a loop. dllEntryPos = head.dll_list iatCurr = head.iat dllNumFuncsOpt = wordAt(li, dllEntryPos) # For each DLL entry, where the DLL entry list is terminated by an entry # specifying zero imports... while dllNumFuncsOpt[0] and dllNumFuncsOpt[1] != 0: if dllNumFuncsOpt[1] * 4 + head.iat > head.mod_size: idaapi.msg( "[E] Hidden Bee Loader: IAT entry outside of module boundary %#x. Aborting import parsing.\n" % (dllNumFuncsOpt[1], head.mod_size)) break # Get the DLL name dllName = li.getz(idaapi.MAXSTR, dllEntryPos + 2) # Get the specified number of DWORD hashes hashes = dwordsAt(li, iatCurr, dllNumFuncsOpt[1]) if hashes is None: idaapi.msg( "[E] Hidden Bee Loader: could not read %d API hashes beginning at %#x. Aborting import parsing.\n" % (dllNumFuncsOpt[1], iatCurr)) break # Look up the hashes, rename their addresses after the corresponding API do_dll_imports(dllName, iatCurr, hashes) # Move on to next DLL iatCurr += 4 * dllNumFuncsOpt[1] dllEntryPos += 2 + len(dllName) + 1 dllNumFuncsOpt = wordAt(li, dllEntryPos) # Check that the last DLL entry read correctly if not dllNumFuncsOpt[0]: idaapi.msg( "[E] Hidden Bee Loader: could not read IAT DLL entry at %#x. Aborting import parsing.\n" % dllEntryPos) # Read the relocations relocs = dwordsAt(li, head.relocs, head.relocs_size / 4) if not relocs: idaapi.msg( "[E] Hidden Bee Loader: could not read relocation data. Aborting relocation parsing.\n" ) return 1 idaapi.msg("[I] Processing relocations\n") for reloc in relocs: if reloc > head.mod_size: idaapi.msg( "[E] Hidden Bee Loader: relocation entry %#x outside of module boundary %#x, skipping.\n" % (reloc, head.mod_size)) else: do_reloc(reloc, 0) # Store a copy of the relocation data in a global netnode in case the user # messes with it in the database. Needed so we can relocate the database if # the user requests it. gNode = idaapi.netnode() gNode.create(NETNODE_NAME) gNode.setblob(idaapi.get_bytes(head.relocs, head.relocs_size), 0, 'D') return 1
def name_long(ea, name): idaapi.set_name(ea, name) idaapi.create_dword(ea, 4) idaapi.set_offset(ea, 0, 0)