def makeInterface(self, offset): idc.SetType(offset, "interfaceType") ifaceid = ida_struct.get_struc_id("interfaceType") meth_offs = idc.get_member_offset(ifaceid, "methods") slice_id = ida_struct.get_struc_id("slice") size_off = idc.get_member_offset(slice_id, "len") size = self.stepper.ptr(offset + meth_offs + size_off) if size != 0: addr = self.getPtr(slice_id, offset + meth_offs, "data") idc.SetType(addr, "imethod") sz = ida_struct.get_struc_size(ida_struct.get_struc_id("imethod")) self.make_arr(addr, size, sz, "imethod") names = self.processIMethods(addr, size) # For now only for go1.7 if names is None: return name = self.getName(offset) while name[0] == "*": name = name[1:] name = Utils.relaxName(name) name = "user_interface_" + name # TODO: this is for go1.7 need additional check for other versions fields = [("inter", "void *"), ("type", "void *"), ("link", "void *"), ("bad", "__int32"), ("unused", "__int32")] for i in names: fields.append((i, "void *")) itype = [(name, fields)] self.settings.structCreator.createTypes(itype)
def make_arr(self, addr, arr_size, struc_size, type): res = idc.make_array(addr, arr_size) if res == False: ida_bytes.del_items(addr, arr_size * struc_size, ida_bytes.DELIT_SIMPLE) idc.SetType(addr, type) idc.make_array(addr, arr_size)
def _get_function_tif_with_hex_rays(offset): """ Attempt to get the tinfo_t object of a function using the Hex-Rays decompiler plugin. :param offset: Offset of function. :raises: RuntimeError on failure. :returns: tinfo_t object on success. """ tif = ida_typeinf.tinfo_t() # This requires Hexrays decompiler, load it and make sure it's available before continuing. if not idaapi.init_hexrays_plugin(): idc.load_and_run_plugin("hexrays", 0) or idc.load_and_run_plugin("hexx64", 0) if not idaapi.init_hexrays_plugin(): raise RuntimeError("Unable to load Hexrays decompiler.") # Pull type from decompiled C code. try: decompiled = idaapi.decompile(offset) except idaapi.DecompilationFailure: decompiled = None if decompiled is None: raise RuntimeError("Cannot decompile function at 0x{:X}".format(offset)) decompiled.get_func_type(tif) # Save type for next time. fmt = decompiled.print_dcl() fmt = "".join(c for c in fmt if c in string.printable and c not in ("\t", "!")) set_type_result = idc.SetType(offset, "{};".format(fmt)) if not set_type_result: logger.warning("Failed to SetType for function at 0x{:X} with decompiler type {!r}".format(offset, fmt)) return tif
def fillStruct(self, sid, data): for i in data: new_type = None # (i1, i2, i3) = self.stepper.parseField(i[1]) name = i[1] if name[0] == "*": name = name[1:] if i[1] != "uintptr": i1, i2, i3 = (idc.FF_BYTE | idc.FF_DATA, -1, 1) else: i1, i2, i3 = self.uintptr if name == i[1]: new_type = i[1] else: new_type = name + " *" res = idc.add_struc_member(sid, i[0], -1, i1, i2, i3) use_name = i[0] if res == -1: # Bad name # print "Bad name %s for struct member" % i[0] use_name = i[0] + "_autogen_" + id_generator() idc.add_struc_member(sid, use_name, -1, i1, i2, i3) if new_type is not None: offset = idc.get_member_offset(sid, use_name) # print "Setting %s as %s" % (i[0], new_type) idc.SetType(idc.get_member_id(sid, offset), new_type)
def handle_offset(self, offset): #Check if we already parse this if offset in self.type_addr: return print ("Processing: %x" % offset) self.type_addr.append(offset) #Set type and get name idc.SetType(offset, "type") name = self.getName(offset) idc.set_cmt(offset, name, 0) #get kind name kind_name = self.getKindEnumName(offset) print (kind_name) if name[0] == "*" and kind_name != "PTR": name = name[1:] name = Utils.relaxName(name) Utils.rename(offset, name) self.betterTypePlease(offset) sid = ida_struct.get_struc_id("type") addr = self.getPtrToThis(sid, offset) if addr != 0: addr = self.getOffset(addr) self.handle_offset(addr) return if kind_name != "FUNC": self.processUncommon(sid, offset)
def yatest_create_struct_in_stack_vars_with_renaming(self): """ test creation of struct from stack vars used to find a bug (structure is correctly applied on var if renamed) """ # create structure ident, sida = self.get_function_sid_without_del( True, local_size=complex_struc3_size, count_from_first_var=True) self.assertNotEqual(sida, -1) sidb = idc.AddStrucEx(0, 'create_struct_in_stack_vars_with_renaming', 0) self.assertNotEqual(sidb, -1) size = self.create_complex2(sidb, complex_struc3) self.assertEqual(complex_struc3_size, size) # set first var prototype offset = idc.GetFirstMember(sida) member_id = idc.GetMemberId(sida, offset) self.assertNotEqual(member_id, -1) self.assertTrue( idc.SetType(member_id, "create_struct_in_stack_vars_with_renaming* x;")) self.assertEqual("create_struct_in_stack_vars_with_renaming *", idc.GetType(idc.GetMemberId(sida, offset))) idc.SetMemberName(sida, offset, "var1") yaunit.save("create_struct_in_stack_vars_with_renaming", sida) yaunit.save("create_struct_in_stack_vars_with_renaming_offset", offset)
def makeArrType(self, offset): idc.SetType(offset, "arrayType") sid = ida_struct.get_struc_id("arrayType") addr = self.getPtr(sid, offset, "elem") self.handle_offset(addr) addr = self.getPtr(sid, offset, "slice") self.handle_offset(addr)
def load(infos): idc.set_inf_attr(idc.INF_COMPILER, 6) for info in infos: type = info.get('type', None) ida_name.set_name(info['start'], info['name']) if type: idc.SetType(info['start'], type)
def make_names(self): ''' make names in idb ''' EFI_GUID = 'EFI_GUID *' EFI_GUID_ID = idc.get_struc_id('EFI_GUID') self.get_boot_services() self.get_protocols() self.get_prot_names() data = self.Protocols['all'] empty = True for element in data: try: idc.SetType(element['address'], EFI_GUID) self.apply_struct(element['address'], 16, EFI_GUID_ID) name = element['protocol_name'] + '_' + \ '{addr:#x}'.format(addr=element['address']) idc.set_name(element['address'], name) empty = False print('[ {ea} ] {name}'.format( ea='{addr:#010x}'.format(addr=element['address']), name=name)) except: continue if empty: print(' * list is empty')
def makeArrType(self, offset): idc.SetType(offset, "arrayType") sid = idc.GetStrucIdByName("arrayType") addr = self.getPtr(sid, offset, "elem") self.handle_offset(addr) addr = self.getPtr(sid, offset, "slice") self.handle_offset(addr)
def apply(self, data): # TODO: deserialize type info and apply it prototype = data['type_info'] if idc.SetType(self.offset, prototype) is None: log('annotation_prototype').warn( "Setting prototype failed at %s with " "%s", self.offset, data)
def _get_function_tif_with_guess_type(offset): """ Attempt to get the tinfo_t object of a function using the "guess_type" function. :param offset: Offset of function. :raises: RuntimeError on failure. :returns: tinfo_t object on success. """ tif = ida_typeinf.tinfo_t() guessed_type = idc.guess_type(offset) if guessed_type is None: raise RuntimeError( "Failed to guess function type for offset 0x{:X}".format(offset)) func_name = idc.get_func_name(offset) if func_name is None: raise RuntimeError( "Failed to get function name for offset 0x{:X}".format(offset)) # Documentation states the type must be ';' terminated, also the function name must be inserted guessed_type = re.sub(r"\(", " {}(".format(func_name), "{};".format(guessed_type)) set_type_result = idc.SetType(offset, guessed_type) if not set_type_result: logger.warning( "Failed to SetType for function at 0x{:X} with guessed type {!r}". format(offset, guessed_type)) # Try one more time to get the tinfo_t object if not ida_nalt.get_tinfo(tif, offset): raise RuntimeError( "Failed to obtain tinfo_t object for offset 0x{:X}".format(offset)) return tif
def getName(self, offset): sid = idc.GetStrucIdByName("type") string_addr = offset + idc.GetMemberOffset(sid, "string") ptr = self.stepper.ptr(string_addr) idc.SetType(ptr, "string") name = self.stepper.ptr(ptr) return idc.GetString(name)
def getName(self, offset): sid = ida_struct.get_struc_id("type") string_addr = offset + idc.get_member_offset(sid, "string") ptr = self.stepper.ptr(string_addr) idc.SetType(ptr, "string") name = self.stepper.ptr(ptr) return idc.GetString(name)
def _get_tif_with_guess_type(address: int) -> Optional[ida_typeinf.tinfo_t]: """ Attempt to get the tinfo_t object for the function using the "guess_type" function. :raises: RuntimeError on failure. :returns: tinfo_t object on success. """ guessed_type = idc.guess_type(address) if guessed_type is None: return None func_name = idc.get_func_name(address) if func_name is None: return None # Documentation states the type must be ';' terminated, also the function name must be inserted guessed_type = re.sub(r"\(", f" {func_name}(", f"{guessed_type};") set_type_result = idc.SetType(address, guessed_type) if not set_type_result: logger.warning( f"Failed to SetType for function at 0x{address:X} with guessed type {guessed_type!r}" ) tif = ida_typeinf.tinfo_t() if not ida_nalt.get_tinfo(tif, address): return None return tif
def parseFuncType(self, offset): return sid = ida_struct.get_struc_id("funcType") in_size = idc.Word(offset + idc.get_member_offset(sid, "incount")) out_size = idc.Word(offset + idc.get_member_offset(sid, "outcount")) sz = ida_struct.get_struc_size(sid) for i in xrange(in_size + out_size): idc.SetType(offset + sz + i * self.stepper.size, "type *")
def build_struct(self): ''' Creates an IDA structure for this Type. ''' if self.struct is not None: return for p in self.parents: p.build_struct() self.struct = idc.AddStrucEx(-1, self.name, 0) if as_signed(self.struct, TARGET_ADDRESS_SIZE) == -1: raise RuntimeError("Unable to make struct `{}`".format(self.name)) else: #TODO: either come up with another way of showing this, or # sync it with the actual function names cmt = "constructors: " for c in self.constructors(): cmt += "{}(0x{:02x}), ".format(idc.Name(c), c) cmt = cmt.strip(", ") idaapi.set_struc_cmt(self.struct, cmt, False) if TARGET_ADDRESS_SIZE == 8: mask = idc.FF_QWRD else: mask = idc.FF_DWRD # Only bases get the magic _vptr member if len(self.parents) == 0: idc.AddStrucMember(self.struct, "_vptr", 0, idc.FF_DATA | mask, -1, TARGET_ADDRESS_SIZE) idc.SetType(idc.GetMemberId(self.struct, 0), "_vfunc**") for i, parent in enumerate(self.parents): try: #TODO: for non-itanium ABI, this may not be available # when RTTI is disabled offset = self.tablegroup.tables[i].offset_to_top except: break idc.AddStrucMember(self.struct, "parent_{}".format(i), -offset, idc.FF_DATA, -1, idc.GetStrucSize(parent.struct)) idc.SetType(idc.GetMemberId(self.struct, -offset), parent.name)
def parseFuncType(self, offset): return sid = idc.GetStrucIdByName("funcType") in_size = idc.Word(offset + idc.GetMemberOffset(sid, "incount")) out_size = idc.Word(offset + idc.GetMemberOffset(sid, "outcount")) sz = idc.GetStrucSize(sid) for i in xrange(in_size + out_size): idc.SetType(offset + sz + i * self.stepper.size, "type *")
def yatest_set_field_prototype(self): for field_type, name, prototype in set_field_prototype: sid = idc.AddStrucEx(-1, name, 0) self.assertNotEqual(sid, -1) self.assertEqual(idc.AddStrucMember(sid, 'field', 0, field_type | idaapi.FF_DATA, -1, get_size(field_type, -1)), 0) mid = idc.GetMemberId(sid, 0) self.assertNotEqual(mid, -1) self.assertTrue(idc.SetType(mid, prototype))
def set_type_single(address, type_): if isinstance(type_, fa_types.FaStruct) or \ isinstance(type_, fa_types.FaEnum): type_str = type_.get_name() else: type_str = type_ idc.SetType(address, type_str) ida_auto.auto_wait()
def makeMap(self, offset): idc.SetType(offset, "mapType") sid = ida_struct.get_struc_id("mapType") addr = self.getPtr(sid, offset, "key") self.handle_offset(addr) addr = self.getPtr(sid, offset, "elem") self.handle_offset(addr) addr = self.getPtr(sid, offset, "bucket") self.handle_offset(addr)
def makeStructType(self, offset): idc.SetType(offset, "structType") sid = idc.GetStrucIdByName("structType") slice_id = idc.GetStrucIdByName("slice") offset_elem = idc.GetMemberOffset(sid, "fields") inner_offset = idc.GetMemberOffset(slice_id, "data") addr = self.stepper.ptr(offset_elem + offset + inner_offset) inner_offset = idc.GetMemberOffset(slice_id, "len") size = self.stepper.ptr(offset + offset_elem + inner_offset) if size == 0: return idc.SetType(addr, "structField") sz = idc.GetStrucSize(idc.GetStrucIdByName("structField")) self.make_arr(addr, size, sz, "structField") sid_type = idc.GetStrucIdByName("type") size_new_struct = self.getPtr(sid_type, offset, "size") for i in xrange(size): self.processStructField(addr, i * sz)
def make_strings_const(): s = idautils.Strings(False) s.setup(strtypes=idautils.Strings.STR_UNICODE | idautils.Strings.STR_C) for v in s: gt = idc.GetType(v.ea) if not gt: gt = idc.GuessType(v.ea) if gt and not gt.startswith("const "): idc.SetType(v.ea, "const " + gt)
def processStructField(self, addr, index): offset = addr + index sid = ida_struct.get_struc_id("structField") ptr = self.getPtr(sid, offset, "Name") if ptr != 0: idc.SetType(ptr, "string") fieldName = idc.GetString(self.stepper.ptr(ptr)) Utils.rename(ptr, fieldName) ptr = self.getPtr(sid, offset, "typ") self.handle_offset(ptr)
def set_function_type(name, TypeString, print_ERROR=False): ea = idaapi.get_name_ea(-1, str(name)) if ea == idaapi.BADADDR: return ok = idc.SetType(ea, str(TypeString)) if not ok and print_ERROR: print( "Could not add function type {name} at {ea:#x} : {TypeString}". format(name=name, ea=ea, TypeString=TypeString))
def set_global_data(name, TypeString): ea = idaapi.get_name_ea(-1, str(name)) if ea == idaapi.BADADDR: return ok = idc.SetType(ea, str(TypeString)) if not ok: print("Could not add global type {name} at {ea:#x} : {TypeString}". format(name=name, ea=ea, TypeString=TypeString))
def set_types(self): ''' handle (EFI_BOOT_SERVICES *) type and (EFI_SYSTEM_TABLE *) for x64 images ''' RAX = 0 O_REG = 1 O_MEM = 2 EFI_BOOT_SERVICES = 'EFI_BOOT_SERVICES *' EFI_SYSTEM_TABLE = 'EFI_SYSTEM_TABLE *' empty = True for service in self.gBServices: for address in self.gBServices[service]: ea = address num_of_attempts = 10 for _ in range(num_of_attempts): ea = idc.prev_head(ea) if (idc.print_insn_mnem(ea) == 'mov' and idc.get_operand_type(ea, 1) == O_MEM): if (idc.get_operand_type(ea, 0) == O_REG and idc.get_operand_value(ea, 0) == RAX): gvar = idc.get_operand_value(ea, 1) gvar_type = idc.get_type(gvar) ''' if (EFI_SYSTEM_TABLE *) ''' if ((gvar_type != 'EFI_SYSTEM_TABLE *') and \ (idc.print_operand(address, 0).find('rax') == 1) ): if self._find_est(gvar, ea, address): print( '[ {0} ] Type ({type}) successfully applied' .format( '{addr:#010x}'.format(addr=gvar), type=EFI_SYSTEM_TABLE)) empty = False break ''' otherwise it (EFI_BOOT_SERVICES *) ''' if (gvar_type != 'EFI_BOOT_SERVICES *' and gvar_type != 'EFI_SYSTEM_TABLE *'): if idc.SetType(gvar, EFI_BOOT_SERVICES): empty = False idc.set_name( gvar, 'gBs_{addr:#x}'.format(addr=gvar)) print( '[ {0} ] Type ({type}) successfully applied' .format( '{addr:#010x}'.format(addr=gvar), type=EFI_BOOT_SERVICES)) break if empty: print(' * list is empty')
def makeMap(self, offset): idc.SetType(offset, "mapType") sid = idc.GetStrucIdByName("mapType") addr = self.getPtr(sid, offset, "key") self.handle_offset(addr) addr = self.getPtr(sid, offset, "elem") self.handle_offset(addr) addr = self.getPtr(sid, offset, "bucket") self.handle_offset(addr) addr = self.getPtr(sid, offset, "hmap") self.handle_offset(addr)
def get_data_guids(self): """rename GUIDs in idb""" EFI_GUID = "EFI_GUID" EFI_GUID_ID = idc.get_struc_id("EFI_GUID") segments = [".text", ".data"] for segment in segments: seg_start, seg_end = 0, 0 for seg in idautils.Segments(): if idc.get_segm_name(seg) == segment: seg_start = idc.get_segm_start(seg) seg_end = idc.get_segm_end(seg) break ea = seg_start while ea <= seg_end - 15: prot_name = str() if "unk" in idc.get_name(ea, ida_name.GN_VISIBLE): find = False cur_guid = list() cur_guid.append(idc.get_wide_dword(ea)) cur_guid.append(idc.get_wide_word(ea + 4)) cur_guid.append(idc.get_wide_word(ea + 6)) for addr in range(ea + 8, ea + 16, 1): cur_guid.append(idc.get_wide_byte(addr)) if cur_guid == [0] * 11: ea += 1 continue for guid_place in [ "ami_guids", "asrock_guids", "dell_guids", "edk_guids", "edk2_guids", "lenovo_guids", ]: for name in self.Protocols[guid_place]: if self.Protocols[guid_place][name] == cur_guid: prot_name = f"{name}_{ea:016X}" record = { "address": ea, "service": "unknown", "guid": cur_guid, "protocol_name": name, "protocol_place": guid_place, } find = True break if find: break if find and (idc.get_name(ea, ida_name.GN_VISIBLE) != prot_name): idc.SetType(ea, EFI_GUID) self.apply_struct(ea, 16, EFI_GUID_ID) idc.set_name(ea, prot_name) self.Protocols["data"].append(record) ea += 1
def get_data_guids(self): ''' rename GUIDs in idb ''' EFI_GUID = 'EFI_GUID *' EFI_GUID_ID = idc.get_struc_id('EFI_GUID') segments = ['.text', '.data'] for segment in segments: seg_start, seg_end = 0, 0 for seg in idautils.Segments(): if idc.get_segm_name(seg) == segment: seg_start = idc.get_segm_start(seg) seg_end = idc.get_segm_end(seg) break ea = seg_start while (ea <= seg_end - 15): prot_name = '' if idc.get_name(ea, ida_name.GN_VISIBLE).find('unk_') != -1: find = False cur_guid = [] cur_guid.append(idc.get_wide_dword(ea)) cur_guid.append(idc.get_wide_word(ea + 4)) cur_guid.append(idc.get_wide_word(ea + 6)) for addr in range(ea + 8, ea + 16, 1): cur_guid.append(idc.get_wide_byte(addr)) if cur_guid == [0] * 11: ea += 1 continue for guid_place in [ 'ami_guids', 'asrock_guids', 'dell_guids', 'edk_guids', 'edk2_guids', 'lenovo_guids' ]: for name in self.Protocols[guid_place]: if self.Protocols[guid_place][name] == cur_guid: prot_name = name + '_' + \ '{addr:#x}'.format(addr=ea) record = { 'address': ea, 'service': 'unknown', 'guid': cur_guid, 'protocol_name': name, 'protocol_place': guid_place } find = True break if find: break if find and (idc.get_name(ea, ida_name.GN_VISIBLE) != prot_name): idc.SetType(ea, EFI_GUID) self.apply_struct(ea, 16, EFI_GUID_ID) idc.set_name(ea, prot_name) self.Protocols['data'].append(record) ea += 1