def set_ida_struct(struct: Struct, controller) -> bool: # first, delete any struct by the same name if it exists sid = ida_struct.get_struc_id(struct.name) if sid != 0xffffffffffffffff: sptr = ida_struct.get_struc(sid) ida_struct.del_struc(sptr) # now make a struct header ida_struct.add_struc(ida_idaapi.BADADDR, struct.name, False) sid = ida_struct.get_struc_id(struct.name) sptr = ida_struct.get_struc(sid) # expand the struct to the desired size # XXX: do not increment API here, why? Not sure, but you cant do it here. ida_struct.expand_struc(sptr, 0, struct.size) # add every member of the struct for off, member in struct.struct_members.items(): # convert to ida's flag system mflag = convert_size_to_flag(member.size) # create the new member ida_struct.add_struc_member( sptr, member.member_name, member.offset, mflag, None, member.size, ) return True
def add_struc_retry(name, max_attempts=100): i = 0 suggested_name = name sid = ida_struct.add_struc(BADADDR, suggested_name) while sid == BADADDR: suggested_name = name + "_" + str(i) sid = ida_struct.add_struc(BADADDR, suggested_name) i += 1 if i == max_attempts: return None, sid return suggested_name, sid
def create_vtable_struct(sptr, name, vtable_offset, parent_name=None): logging.debug("create_vtable_struct(%s, %d)", name, vtable_offset) vtable_details = find_vtable_at_offset(sptr, vtable_offset) parent_vtable_member = None parent_vtable_struct = None parent_name = None parents_chain = None if vtable_details is not None: logging.debug("Found parent vtable %s %d", name, vtable_offset) parent_vtable_member, parent_vtable_struct, parents_chain = vtable_details else: logging.debug("Couldn't found parent vtable %s %d", name, vtable_offset) if parent_vtable_member is not None: parent_name = ida_struct.get_struc_name(parent_vtable_struct.id) vtable_name = get_class_vtable_struct_name(name, vtable_offset) if vtable_offset == 0: this_type = utils.get_typeinf_ptr(name) else: this_type = utils.get_typeinf_ptr(parent_name) if vtable_name is None: logging.exception( "create_vtable_struct(%s, %d): vtable_name is" " None", name, vtable_offset ) vtable_id = ida_struct.add_struc(BADADDR, vtable_name, False) if vtable_id == BADADDR: logging.exception("Couldn't create struct %s", vtable_name) vtable_struct = ida_struct.get_struc(vtable_id) if parents_chain: for parent_name, offset in parents_chain: add_child_vtable(parent_name, name, vtable_id, offset) else: add_class_vtable(sptr, vtable_name, vtable_offset) return vtable_struct, this_type
def create_cmdref(): sid = ida_struct.add_struc(0, "cmd_ref",0) idc.add_struc_member(sid, "name", -1, ida_bytes.off_flag()|ida_bytes.FF_DATA|ida_bytes.FF_DWORD, -1, 4) idc.add_struc_member(sid, "reserve1", -1, ida_bytes.FF_DWORD, -1, 4) idc.add_struc_member(sid, "param", -1, ida_bytes.FF_WORD, -1, 4) idc.add_struc_member(sid, "id", -1, ida_bytes.FF_WORD, -1, 4) idc.add_struc_member(sid, "reserve2", -1, ida_bytes.FF_DWORD, -1, 4) return sid
def get_guid_tid(): tid = ida_struct.get_struc_id('GUID') if tid == idaapi.BADADDR: print("[*] create GUID struct") tid = ida_struct.add_struc(0xffffffff, 'GUID', 0) sptr = ida_struct.get_struc(tid) ida_struct.add_struc_member(sptr, 'Data1', 0x0, 0x20000000, None, 4) ida_struct.add_struc_member(sptr, 'Data2', 0x4, 0x10000000, None, 2) ida_struct.add_struc_member(sptr, 'Data3', 0x6, 0x10000000, None, 2) ida_struct.add_struc_member(sptr, 'Data4', 0x8, 0x00000000, None, 8) return tid
def defENTENT(): sid = ida_struct.get_struc_id("ENTENT") if sid != ida_idaapi.BADADDR: struc = ida_struct.get_struc(sid) ida_struct.del_struc(struc) sid = ida_struct.add_struc(ida_idaapi.BADADDR, "ENTENT", 0) struc = ida_struct.get_struc(sid) ida_struct.add_struc_member(struc, "flags", ida_idaapi.BADADDR, FF_BYTE, None, 1) ida_struct.add_struc_member(struc, "addr", ida_idaapi.BADADDR, FF_WORD, None, 2) return sid
def apply(cls, data): struct_id = ida_struct.add_struc(idaapi.BADADDR, data['name'], data['union']) if 'comment' in data and data['comment']: ida_struct.set_struc_cmt(struct_id, data['comment'], False) if 'repeatable_comment' in data and data['comment']: ida_struct.set_struc_cmt(struct_id, data['repeatable_comment'], True) if 'members' in data and data['members']: struct = ida_struct.get_struc(struct_id) for member_idx, member_data in data['members']: cls.apply_member(struct, member_data)
class RTTICompleteObjectLocator(RTTIStruc): # Init class statics msid = get_struc_id("RTTICompleteObjectLocator") if msid != BADADDR: del_struc(get_struc(msid)) msid = add_struc(0xFFFFFFFF, "RTTICompleteObjectLocator", False) add_struc_member(get_struc(msid), "signature", BADADDR, FF_DATA | FF_DWRD, None, 4) add_struc_member(get_struc(msid), "offset", BADADDR, FF_DATA | FF_DWRD, None, 4) add_struc_member(get_struc(msid), "cdOffset", BADADDR, FF_DATA | FF_DWRD, None, 4) add_struc_member(get_struc(msid), "pTypeDescriptor", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) add_struc_member(get_struc(msid), "pClassDescriptor", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) if u.x64: add_struc_member(get_struc(msid), "pSelf", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) tid = msid struc = get_struc(tid) size = get_struc_size(tid) print "Completed Registering RTTICompleteObjectLocator" def __init__(self, ea, vtable): do_unknown_range(ea, self.size, DOUNK_DELNAMES) if doStruct(ea, self.size, self.tid): # Get adress of type descriptor from CompleteLocator print "Complete Object Locator at: 0x%x" % ea offset = get_member_by_name(self.struc, "pTypeDescriptor").soff typeDescriptor = get_32bit(ea + offset) + u.x64_imagebase() print "Looking for type Descriptor at: 0x%x" % typeDescriptor rtd = RTTITypeDescriptor(typeDescriptor) if rtd.class_name: print "Type Descriptor at: 0x%x" % typeDescriptor offset = get_member_by_name(self.struc, "pClassDescriptor").soff classHierarchyDes = get_32bit(ea + offset) + u.x64_imagebase() rchd = RTTIClassHierarchyDescriptor(classHierarchyDes) # filter out None entries rchd.bases = filter(lambda x: x, rchd.bases) className = strip(rtd.class_name) classes[className] = [strip(b) for b in rchd.bases] vtables[className] = vtable MakeNameEx(vtable, "vtable__" + className, SN_NOWARN) else: # if the RTTITypeDescriptor doesn't have a valid name for us to # read, then this wasn't a valid RTTICompleteObjectLocator MakeUnknown(ea, self.size, DOUNK_SIMPLE)
def _prepare_ida_type(self): if hasattr(self, "tid") and self.tid is not None: raise RuntimeError("May not call _prepare_ida_type twice") # Find existing structure self.tid = ida_struct.get_struc_id(self.name) if self.tid != BADADDR: # Grab structure pointer self._get_sptr() # Struct with given name already exists, validate it if self._validate_ida_type(): self.log.info("Found struct '%s' with ID %d", self.name, self.tid) return # Successful # Existing struct not valid, ask user whether to overwrite query = ida_kernwin.ask_yn( ida_kernwin.ASKBTN_NO, "A structure named '{}' already exists but does not match the needed format. Do you wish to overwrite it?" .format(self.name)) if query != ida_kernwin.ASKBTN_YES: raise RuntimeError("User cancelled operation") # Delete existing struct if not ida_struct.del_struc(self.sptr): raise RuntimeError( "Could not delete existing structure '{}'".format( self.name)) self.log.info("Deleted struct '%s' (ID=%d)", self.name, self.tid) self.tid = None self.sptr = None # Create struct self.tid = ida_struct.add_struc(BADADDR, self.name) if self.tid is None or self.tid == BADADDR: raise RuntimeError("Could not create structure '{}'".format( self.name)) # Grab structure pointer self._get_sptr() # Create members for f in self.members_array: f._prepare_ida_type() self.log.info("Created struct '%s' of size %d", self.name, self.size)
class RTTIBaseClassDescriptor(RTTIStruc): msid = get_struc_id("RTTIBaseClassDescriptor") if msid != BADADDR: del_struc(get_struc(msid)) msid = add_struc(0xFFFFFFFF, "RTTIBaseClassDescriptor", False) add_struc_member(get_struc(msid), "pTypeDescriptor", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) add_struc_member(get_struc(msid), "numContainerBases", BADADDR, FF_DWRD | FF_DATA, None, 4) add_struc_member(get_struc(msid), "PMD", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) add_struc_member(get_struc(msid), "attributes", BADADDR, FF_DWRD | FF_DATA, None, 4) tid = msid struc = get_struc(tid) size = get_struc_size(tid) print "Completed Registering RTTIBaseClassDescriptor"
def update_idb(self): sid = ida_struct.get_struc_id(self._name) if sid != -1: sptr = ida_struct.get_struc(sid) ida_struct.del_struc(sptr) sid = ida_struct.add_struc(idc.BADADDR, self._name, 0) sptr = ida_struct.get_struc(sid) for f in self._fields: ida_struct.add_struc_member(sptr, f.name, idc.BADADDR, (idc.FF_BYTE | idc.FF_DATA) & 0xFFFFFFFF, None, 1) member_name = "{}.{}".format(self._name, f.name) idc.SetType( idaapi.get_member_by_fullname(member_name)[0].id, f.type) ida_auto.auto_wait()
def create_structs(self): self.struct_id = ida_struct.add_struc(BADADDR, self.name) self.struct_ptr = ida_struct.get_struc(self.struct_id) if self.struct_ptr is None: logging.exception("self.struct_ptr is None at %s", self.name) previous_parent_offset = 0 previous_parent_size = 0 previous_parent_struct_id = BADADDR for _, parent_name, parent_offset in self.parents: if ( parent_offset - previous_parent_offset > previous_parent_size and previous_parent_struct_id != BADADDR ): utils.expand_struct( previous_parent_struct_id, parent_offset - previous_parent_offset ) baseclass_id = ida_struct.get_struc_id(parent_name) baseclass_size = ida_struct.get_struc_size(baseclass_id) if baseclass_id == BADADDR or baseclass_size == 0: logging.warning( "bad struct id or size: %s(0x%x:%s) - %s, %d", self.name, parent_offset, parent_name, baseclass_id, baseclass_size, ) member_name = cpp_utils.get_base_member_name(parent_name, parent_offset) idc.add_struc_member( self.struct_id, member_name, parent_offset, idaapi.FF_STRUCT, baseclass_id, baseclass_size, ) previous_parent_offset = parent_offset previous_parent_size = baseclass_size previous_parent_struct_id = baseclass_id for _, parent_name, parent_offset in self.parents: ida_struct.get_member( self.struct_ptr, parent_offset ).props |= ida_struct.MF_BASECLASS
def load(infos): insn = ida_ua.insn_t() for info in infos: # Find or create struct. struct_id = ida_struct.get_struc_id(info['name']) if struct_id == BADADDR: print('[IDA-Sync] Creating new struct %s.' % info['name']) struct_id = ida_struct.add_struc(info['idx'], info['name']) struct = ida_struct.get_struc(struct_id) ida_struct.set_struc_idx(struct, info['idx']) # Create struct members. for member in info['members']: ida_struct.add_struc_member( struct, member['name'], member['offset'], # flag 0, # opinfo_t instance... maybe it should sometimes be # something? None, member['size'], ) # Create xrefs to members of the struct as offsets. for xref in info['xrefs']: typ = xref['type'] # Offset xref. if typ == 1: # TODO figure out what second argument does. idc.op_plain_offset(xref['from'], 1, xref['offset']) # Read/write xrefs. elif typ in [2, 3]: ida_ua.create_insn(xref['from'], insn) idc.op_stroff(insn, 1, struct.id, 0) # TODO do the other cases come up? else: pass
class RTTIClassHierarchyDescriptor(RTTIStruc): bases = None msid = get_struc_id("RTTIClassHierarchyDescriptor") if msid != BADADDR: del_struc(get_struc(msid)) msid = add_struc(0xFFFFFFFF, "RTTIClassHierarchyDescriptor", False) add_struc_member(get_struc(msid), "signature", BADADDR, FF_DWRD | FF_DATA, None, 4) add_struc_member(get_struc(msid), "attribute", BADADDR, FF_DWRD | FF_DATA, None, 4) add_struc_member(get_struc(msid), "numBaseClasses", BADADDR, FF_DWRD | FF_DATA, None, 4) add_struc_member(get_struc(msid), "pBaseClassArray", BADADDR, FF_DATA | FF_DWRD | FF_0OFF, u.mt_rva(), 4) tid = msid struc = get_struc(tid) print "Completed Registering RTTIClassHierarchyDescriptor" def __init__(self, ea): print "Processing Class Hierarchy Descriptor at 0x%x" % ea do_unknown_range(ea, get_struc_size(self.tid), DOUNK_DELNAMES) if doStruct(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 doDwrd(baseClasses + i * 4, 4) op_offset(baseClasses + i * 4, -1, u.REF_OFF | REFINFO_RVA, -1, 0, 0) doStruct(baseClass, RTTIBaseClassDescriptor.size, RTTIBaseClassDescriptor.tid) typeDescriptor = get_32bit(baseClass) + u.x64_imagebase() self.bases.append( RTTITypeDescriptor(typeDescriptor).class_name)
def update_idb(self, delete_existing_members=True): sid = ida_struct.get_struc_id(self._name) sptr = ida_struct.get_struc(sid) if sid == idc.BADADDR: sid = ida_struct.add_struc(idc.BADADDR, self._name, 0) sptr = ida_struct.get_struc(sid) else: if delete_existing_members: ida_struct.del_struc_members(sptr, 0, 0xffffffff) for f in self._fields: ida_struct.add_struc_member(sptr, f.name, f.offset, (idc.FF_BYTE | idc.FF_DATA) & 0xFFFFFFFF, None, 1) member_name = "{}.{}".format(self._name, f.name) idc.SetType( idaapi.get_member_by_fullname(member_name)[0].id, f.type) ida_auto.auto_wait()
def defSEGENT(): sid = ida_struct.get_struc_id("SEGENT") if sid != ida_idaapi.BADADDR: struc = ida_struct.get_struc(sid) ida_struct.del_struc(struc) sid = ida_struct.add_struc(ida_idaapi.BADADDR, "SEGENT", 0) struc = ida_struct.get_struc(sid) ida_struct.add_struc_member(struc, "flags", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "oSegment", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "nParagraphs", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "nReloc", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "minAlloc", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) ida_struct.add_struc_member(struc, "unused", ida_idaapi.BADADDR, ida_bytes.FF_WORD, None, 2) return sid
class RTTITypeDescriptor(RTTIStruc): class_name = None msid = get_struc_id("RTTITypeDescriptor") if msid != BADADDR: del_struc(get_struc(msid)) msid = add_struc(0xFFFFFFFF, "RTTITypeDescriptor", False) add_struc_member(get_struc(msid), "pVFTable", BADADDR, FF_DATA | u.PTR_TYPE | FF_0OFF, u.mt_address(), u.PTR_SIZE) add_struc_member(get_struc(msid), "spare", BADADDR, FF_DATA | u.PTR_TYPE, None, u.PTR_SIZE) add_struc_member(get_struc(msid), "name", BADADDR, FF_DATA | FF_ASCI, u.mt_ascii(), 0) tid = msid struc = get_struc(tid) size = get_struc_size(tid) print "Completed Registering RTTITypeDescriptor" def __init__(self, ea): name = ea + get_member_by_name(get_struc(self.tid), "name").soff strlen = u.get_strlen(name) if strlen is None: # not a real vtable return self.size = self.size + strlen mangled = get_ascii_contents(name, strlen, 0) if mangled is None: # not a real function name return print "Mangled: " + mangled demangled = demangle_name('??_R0' + mangled[1:], 0) if demangled: do_unknown_range(ea, self.size, DOUNK_DELNAMES) if doStruct(ea, self.size, self.tid): print " Made td at 0x%x: %s" % (ea, demangled) self.class_name = demangled return print " FAIL :(" return
def import_structures(structures): """ Import structures :param structures: Dict containing structure information """ curr_idx = ida_struct.get_last_struc_idx() + 1 for struct_name, struct_info in structures.items(): # Create structure tid = ida_struct.add_struc(curr_idx, struct_name) # Get struct object and add members struct = ida_struct.get_struc(tid) for member_name, member_info in struct_info['members'].items(): flag = get_flag_from_type(member_info['type']) ida_struct.add_struc_member( struct, member_name, member_info['offset'], flag, None, member_info['size'] ) curr_idx += 1
def create_cmdptr(): sid = ida_struct.add_struc(0, "cmd_ptr",0) idc.add_struc_member(sid, "id", -1, ida_bytes.FF_DWORD, -1, 4) idc.add_struc_member(sid, "ptr", -1, ida_bytes.off_flag()|ida_bytes.FF_DATA|ida_bytes.FF_DWORD, -1, 4) return sid
def __call__(self): ida_struct.add_struc(self.struc, Event.encode(self.name), self.is_union)
def implement(self): ida_struct.add_struc(long(self._id), self._name)
def __call__(self): ida_struct.add_struc(self.struc, self.name, self.is_union)
""" This file is part of Polichombr (c) ANSSI-FR 2018 Description: Semi automated test that add some data in the IDA database, that should be reflected in the second database """ import ida_name, ida_bytes, ida_struct import idc ida_name.set_name(0x401000, "TESTFUNCTION") ida_bytes.set_cmt(0x40100A, "TEST COMMENT", 0) ida_bytes.set_cmt(0x40100F, "TEST RPT COMMENT", 1) struct_1 = ida_struct.add_struc(0, "TESTSTRUCT1") struct_pointer = ida_struct.get_struc(struct_1) ida_struct.add_struc_member(struct_pointer, "TESTMEMBER", 0, 0, None, 0) idc.SetType(0x401000, "int __cdecl start(char *lpszTestArg);")
def implement(self): ida_struct.add_struc(self._id, self._name)
def create_class(class_name, has_vtable, parent_class=None): class_id = ida_struct.add_struc(BADADDR, class_name) class_ptr = ida_struct.get_struc(class_id) # if parent class -> # if has_vtable-> if not parent- create vtable, if parent - install vtable return class_ptr
# with members of different types. # # Author: Gergely Erdelyi <*****@*****.**> #--------------------------------------------------------------------- import ida_struct import ida_idaapi import ida_bytes import ida_nalt import idc sid = ida_struct.get_struc_id("mystr1") if sid != -1: idc.del_struc(sid) sid = ida_struct.add_struc(ida_idaapi.BADADDR, "mystr1", 0) print("%x" % sid) # Test simple data types simple_types_data = [ (ida_bytes.FF_BYTE, 1), (ida_bytes.FF_WORD, 2), (ida_bytes.FF_DWORD, 4), (ida_bytes.FF_QWORD, 8), (ida_bytes.FF_TBYTE, 10), (ida_bytes.FF_OWORD, 16), (ida_bytes.FF_FLOAT, 4), (ida_bytes.FF_DOUBLE, 8), (ida_bytes.FF_PACKREAL, 10), ] for i, tpl in enumerate(simple_types_data):
def get_or_create_struct_id(struct_name, is_union=False): struct_id = ida_struct.get_struc_id(struct_name) if struct_id != BADADDR: return struct_id struct_id = ida_struct.add_struc(BADADDR, struct_name, is_union) return struct_id
def __call__(self): ida_struct.add_struc(ida_idaapi.BADADDR, self.name, self.is_union)