def createUserTypeStruct(self, addr, name, size, self_size): fields = [] sid = ida_struct.get_struc_id("structField") sz = ida_struct.get_struc_size(sid) sid_type = ida_struct.get_struc_id("type") fields = [] curr_offset = 0 idc.set_cmt(addr, name, 0) for i in range(size): fieldname = self.nameFromOffset(self.getPtr(sid, addr+i*sz,"Name")) type_addr = self.getPtr(sid, addr+i*sz, "typ") typename = self.getType(type_addr) size = self.getPtr(sid_type, type_addr, "size") if fieldname == "" or fieldname is None: fieldname = "unused_"+Utils.id_generator() offset = self.getStructFieldOffset(sid, addr+i*sz) print(f"Get offset: {offset:x}") if offset != curr_offset: print("Offset missmatch.Got %d expected %d. Adding padding..." % (curr_offset, offset)) if offset < curr_offset: raise("Too many bytes already") while offset != curr_offset: fields.append(("padding", "char")) curr_offset += 1 curr_offset += size if size != 0: offset_kind = idc.get_member_offset(sid_type, "kind") kind_of_type = self.getKindEnumName(type_addr) print(kind_of_type) if kind_of_type == "STRUCT_": #Disabled for now name_type = self.getName(type_addr) while name_type[0] == "*": name_type = name_type[1:] name_type = Utils.relaxName(name_type) name_type = "ut_" + name_type #print("setting type %s" % name_type) fields.append((fieldname, name_type)) elif kind_of_type == "STRING": fields.append((fieldname, "string")) elif kind_of_type == "SLICE": fields.append((fieldname, "slice")) elif kind_of_type == "INTERFACE": fields.append((fieldname, "__iface")) else: fields.append((fieldname, "char [%d]" % size)) if curr_offset != self_size: print("%x: Structure size mismatch: %x" % (addr, curr_offset)) if self_size < curr_offset: raise("Too many bytes already") while self_size != curr_offset: fields.append(("padding", "char")) curr_offset += 1 new_type = [(name, fields)] self.settings.structCreator.createTypes(new_type) new_type_sid = ida_struct.get_struc_id(name) sz = ida_struct.get_struc_size(new_type_sid) if sz != self_size: print("%x" % addr ) raise("Error at creating structure")
def expand_struct(struct_id, new_size): struct = ida_struct.get_struc(struct_id) if struct is None: logging.warning("Struct id 0x%x wasn't found", struct_id) return logging.debug( "Expanding struc %s 0x%x -> 0x%x", ida_struct.get_struc_name(struct_id), ida_struct.get_struc_size(struct_id), new_size, ) if ida_struct.get_struc_size(struct_id) > new_size - WORD_LEN: return fix_list = [] xrefs = idautils.XrefsTo(struct.id) for xref in xrefs: if xref.type == ida_xref.dr_R and xref.user == 0 and xref.iscode == 0: member, full_name, x_struct = ida_struct.get_member_by_id(xref.frm) if x_struct is not None: old_name = ida_struct.get_member_name(member.id) offset = member.soff marker_name = "marker_%d" % random.randint(0, 0xFFFFFF) idc.add_struc_member( x_struct.id, marker_name, member.soff + new_size, idaapi.FF_DATA | idaapi.FF_BYTE, -1, 0, ) logging.debug( "Delete member (0x%x-0x%x)", member.soff, member.soff + new_size - 1 ) ida_struct.del_struc_members( x_struct, member.soff, member.soff + new_size - 1 ) fix_list.append( [ x_struct.id, old_name, offset, idaapi.FF_STRUCT | idaapi.FF_DATA, struct_id, new_size, ] ) else: logging.warning("Xref wasn't struct_member 0x%x", xref.frm) ret = push_ptr_member_to_struct( ida_struct.get_struc(struct_id), None, None, new_size - WORD_LEN ) logging.debug("Now fix args:") for fix_args in fix_list: ret = idc.add_struc_member(*fix_args) logging.debug("%s = %d", fix_args, ret) x_struct_id = fix_args[0] idc.del_struc_member(x_struct_id, ida_struct.get_struc_size(x_struct_id))
def data(self): # if idx is None this is called for the pre-apply data identity validation # we'll return None so data will definitely not match if self.idx is None: return None struc_id = ida_struct.get_struc_by_idx(self.idx) struct = ida_struct.get_struc(struc_id) # Skip TIL structures if struct.from_til(): return None # Skip empty structures if not struct.memqty: return None d = {} d['name'] = ida_struct.get_struc_name(struc_id) d['comment'] = ida_struct.get_struc_cmt(struc_id, False) d['repeatable_comment'] = ida_struct.get_struc_cmt(struc_id, False) d['size'] = ida_struct.get_struc_size(struct) d['union'] = ida_struct.is_union(struc_id) # TODO: struct alignment, hidden, listed d['members'] = {} member_idx = 0 while member_idx != idaapi.BADADDR: member = struct.get_member(member_idx) d['members'][member_idx] = self.member_data(member) member_idx = ida_struct.get_next_member_idx(struct, member.soff) # TODO: FIX issue with looping over members member_idx = idaapi.BADADDR return d
def main(): tid = get_guid_tid() for type_name, type_prefix, filepath in GUID_LIST: print('[*] scanning {}'.format(type_name)) fp = open(filepath, 'r') for line in fp.readlines(): line = line.strip() if line == "": continue guid, guid_name = line.split(' ') guid_name = type_prefix + guid_name binary_pattern = make_binary_pattern(guid) ea = 0 while True: ea = idc.find_binary( ea, ida_search.SEARCH_DOWN | ida_search.SEARCH_NEXT | ida_search.SEARCH_NOSHOW, binary_pattern) if ea == idaapi.BADADDR: break idc.del_items(ea, 16, 0) ida_bytes.create_struct(ea, ida_struct.get_struc_size(tid), tid) if idc.set_name(ea, guid_name, ida_name.SN_NOWARN) != 1: for i in range(0, 100): if idc.set_name(ea, guid_name + "_" + str(i), ida_name.SN_NOWARN) == 1: break else: print("[!] 0x{:X}: failed to apply {}".format( ea, guid_name)) print("[*] 0x{:X}: {}".format(ea, guid_name)) print("[*] finished")
def set_all_structures(dictionary, overwrite=False, conflicts=None, retry_len=-1): retry = {} for name, new_struct_def in dictionary.iteritems(): cur_sid = ida_struct.get_struc_id(name) if cur_sid != idc.BADADDR: # A structure exists with this name cur_struct = ida_struct.get_struc(cur_sid) cur_struct_size = ida_struct.get_struc_size(cur_sid) cur_struct_def = psida_common.get_struct_def(cur_struct.ordinal) if cur_struct_def == new_struct_def: #Skip if they're the same continue else: # Otherwise create a conflict conflicts[name] = (cur_struct.ordinal, cur_struct_size, new_struct_def) continue success = psida_common.create_struct(name, new_struct_def) if not success: retry[name] = new_struct_def if retry and retry_len != len(retry.keys()): print "Retrying structures: {}".format(retry.keys()) set_all_structures(retry, overwrite, conflicts, retry_len=len(retry.keys()))
def force_make_struct(ea, struct_name): sptr = get_sptr_by_name(struct_name) if sptr == BADADDR: return False s_size = ida_struct.get_struc_size(sptr) ida_bytes.del_items(ea, ida_bytes.DELIT_SIMPLE, s_size) return ida_bytes.create_struct(ea, s_size, sptr.id)
def _read_struct_member(struct, sid, union, ea, offset, name, size, asobject): """Read a member into a struct for read_struct.""" flags = idc.get_member_flag(sid, offset) assert flags != -1 # Extra information for parsing a struct. member_sid, member_ssize = None, None if ida_bytes.is_struct(flags): member_sid = idc.get_member_strid(sid, offset) member_ssize = ida_struct.get_struc_size(member_sid) # Get the address of the start of the member. member = ea if not union: member += offset # Now parse out the value. array = [] processed = 0 while processed < size: value, read = _read_struct_member_once(member + processed, flags, size, member_sid, member_ssize, asobject) assert size % read == 0 array.append(value) processed += read if len(array) == 1: value = array[0] else: value = array struct[name] = value
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 processIMethods(self, offst, size): sz = ida_struct.get_struc_size(ida_struct.get_struc_id("imethod")) comm = [] for i in xrange(size): comm.append(self.processIMethod(offst + i * sz)) idc.set_cmt(offst, "\n".join(comm), 0) return comm
def fix_member_idx(self, idx_cexpr): num = 0 if idx_cexpr: # wrong vtable*, so it might be too short struct, like: # .vtable.PdmAcqServiceIf[1].___cxa_pure_virtual_2 if idx_cexpr.y.op != ida_hexrays.cot_num: logging.debug( "0x%x: idx doesn't contains a num but %s", self.cfunc.entry_ea, idx_cexpr.y.opname, ) return -1 num = idx_cexpr.y.get_const_value() if not (idx_cexpr.type and idx_cexpr.type.is_struct()): logging.debug("0x%x idx type isn't struct %s", self.cfunc.entry_ea, idx_cexpr.type) return -1 idx_struct = utils.get_struc_from_tinfo(idx_cexpr.type) if idx_struct is None: logging.debug( "0x%x idx type isn't pointing to struct %s", self.cfunc.entry_ea, idx_cexpr.type, ) return -1 struct_size = ida_struct.get_struc_size(idx_struct) num *= struct_size return num
def _populate_wrapper_struct__slices(sid, classinfo): """Fill in the members of the wrapper struct.""" # First add the vtable pointer. offset = 0 vtable_ptr_type = '{}::vtable *'.format(classinfo.classname) ret = idau.struct_add_ptr(sid, 'vtable', offset, type=vtable_ptr_type) if ret not in (0, idc.STRUC_ERROR_MEMBER_OFFSET): _log(0, 'Could not create {}.vtable: {}', classinfo.classname, ret) return False # Now add all the ::fields structs. offset += idau.WORD_SIZE for ci in classinfo.ancestors(inclusive=True): # Get the sid of the ::fields struct. fields_sid = idau.struct_open(ci.classname + '::fields') if fields_sid is None: _log(0, 'Could not find {}::fields', ci.classname) return False # If this is a 0-length struct (no fields), skip it. size = ida_struct.get_struc_size(fields_sid) if size == 0: continue # If this is already in the wrapper struct, skip it. This avoids weird # STRUC_ERROR_MEMBER_VARLAST errors. if idc.get_member_offset(sid, ci.classname) != -1: continue # Add the ::fields struct to the wrapper. ret = idau.struct_add_struct(sid, ci.classname, offset, fields_sid) if ret != 0: _log(0, 'Could not create {}.{}: {}', classinfo.classname, ci.classname, ret) return False offset += size return True
def struct_add_struct(sid, name, offset, msid, count=1): """Add a structure member to a structure. If sid is a union, offset must be -1. """ size = ida_struct.get_struc_size(msid) return idc.add_struc_member(sid, name, offset, idc.FF_DATA | idc.FF_STRU, msid, size * count)
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 push_ptr_member_to_struct( struct, member_name, member_type, offset=BADADDR, overwrite=False ): mt = None flag = idaapi.FF_DWORD member_size = WORD_LEN if member_type is not None and (member_type.is_struct() or member_type.is_union()): logging.debug("Is struct!") substruct = extract_struct_from_tinfo(member_type) if substruct is not None: flag = idaapi.FF_STRUCT mt = ida_nalt.opinfo_t() mt.tid = substruct.id logging.debug( f"Is struct: {ida_struct.get_struc_name(substruct.id)}/{substruct.id}" ) member_size = ida_struct.get_struc_size(substruct.id) member_type = None elif WORD_LEN == 4: flag = idaapi.FF_DWORD elif WORD_LEN == 8: flag = idaapi.FF_QWORD new_member_name = member_name if overwrite and ida_struct.get_member(struct, offset): logging.debug("Overwriting!") ret_val = ida_struct.set_member_name(struct, offset, member_name) i = 0 while ret_val == ida_struct.STRUC_ERROR_MEMBER_NAME: new_member_name = "%s_%d" % (member_name, i) i += 1 if i > 250: return ret_val = ida_struct.set_member_name(struct, offset, new_member_name) else: ret_val = ida_struct.add_struc_member( struct, new_member_name, offset, flag, mt, member_size ) i = 0 while ret_val == ida_struct.STRUC_ERROR_MEMBER_NAME: new_member_name = "%s_%d" % (member_name, i) i += 1 if i > 250: return ret_val = ida_struct.add_struc_member( struct, new_member_name, offset, flag, mt, member_size ) if ret_val != 0: logging.debug(f"ret_val: {ret_val}") member_ptr = ida_struct.get_member_by_name(struct, new_member_name) if member_ptr is None: logging.debug("member is None") if member_type is not None and member_ptr is not None: ida_struct.set_member_tinfo( struct, member_ptr, 0, member_type, idaapi.TINFO_DEFINITE ) return member_ptr
def main(): is_selected, sel_start, sel_end = ida_kernwin.read_selection() if not is_selected: logger.error('range must be selected') return -1 sel_end = ida_bytes.next_head(sel_end) buf = ida_bytes.get_bytes(sel_start, sel_end - sel_start) if buf is None: logger.error('failed to fetch instruction bytes') return -1 f = ida_funcs.get_func(sel_start) if f != ida_funcs.get_func(sel_end): logger.error('range must be within a single function') return -1 # find mappings from "$localN" to "custom_name" regvars = {} for i in range(0x1000): regvar = ida_frame.find_regvar(f, sel_start, '$local%d' % i) if regvar is None: continue regvars[regvar.canon] = regvar.user if len(regvars) >= f.regvarqty: break globals_ = {} for i, offset in netnode.Netnode('$ wasm.offsets').get('globals', {}).items(): globals_['$global' + i] = ida_name.get_name(offset) frame = {} if f.frame != ida_idaapi.BADADDR: names = set([]) for i in range(ida_struct.get_struc_size(f.frame)): s = ida_struct.get_struc(f.frame) if not s: continue m = ida_struct.get_member(s, i) if not m: continue name = ida_struct.get_member_name(m.id) if name in names: continue frame[i] = name names.add(name) emu = Emulator(buf) emu.run() print( emu.render(ctx={ 'regvars': regvars, 'frame': frame, 'globals': globals_, }))
def structs(): _structs = {} for struct_item in idautils.Structs(): idx, sid, name = struct_item[:] sptr = ida_struct.get_struc(sid) size = ida_struct.get_struc_size(sptr) _structs[name] = Struct(name, size, {}) return _structs
def ida_struct_changed(self, sid: int, old_name=None, new_name=None, deleted=False): """ A utility function to catch all changes that can happen to a struct: 1. Renames 2. Member Changes 3. Deletes Currently, any change to a struct will cause the main-thread to re-copy the entire struct from the local state into the remote state. This is done so we don't need to have multiple cases for single member changes. @param sid: Struct ID (IDA Thing) @param old_name: Old struct name (before rename) @param new_name: New struct name (after rename) @param deleted: True only when the entire struct has been deleted. @return: """ # parse the info of the current struct s_name = new_name if new_name else ida_struct.get_struc_name(sid) # back out if a stack variable snuck in if s_name.startswith("$"): return 0 sptr = ida_struct.get_struc(sid) s_size = ida_struct.get_struc_size(sptr) # if deleted, finish early if deleted: self.binsync_state_change(self.controller.push_artifact, Struct(s_name, None, {})) return 0 # convert the ida_struct into a binsync_struct binsync_struct = Struct(s_name, s_size, {}) for mptr in sptr.members: mid = mptr.id m_name = ida_struct.get_member_name(mid) m_off = mptr.soff m_type = ida_typeinf.idc_get_type(mptr.id) if mptr.has_ti() else "" m_size = ida_struct.get_member_size(mptr) binsync_struct.add_struct_member(m_name, m_off, m_type, m_size) # make the controller update the local state and push old_s_name = old_name if old_name else s_name self.binsync_state_change(self.controller.push_artifact, binsync_struct) return 0
def get_structs(): """ Get structures from IDA database :return: Dict containing structure info """ structs = OrderedDict() for idx, sid, name in idautils.Structs(): struct = ida_struct.get_struc(sid) structs[name] = {} structs[name]['size'] = ida_struct.get_struc_size(struct) structs[name]['members'] = get_struct_members(struct, sid) return structs
def create_struct(name, fields, size): struct_id = idaapi.get_struc_id(name) # print struct_id if struct_id != idaapi.BADADDR: i = ida_kernwin.ask_yn( 0, "A class structure for %s already exists. Are you sure you want to remake it?" % name) if i == idaapi.BADADDR: return if i == 1: idaapi.del_struc_members(idaapi.get_struc(struct_id), 0, idaapi.get_struc_size(struct_id)) # struct_id = idc.AddStrucEx(idaapi.BADADDR, name + "_vtbl", 0) else: struct_id = idaapi.add_struc(idaapi.BADADDR, name, 0) if struct_id == idaapi.BADADDR: Warning( "Could not create the class structure!.\nPlease check something.") return sptr = idaapi.get_struc(struct_id) for off in fields: off, type_name, type_kind, field_name = fields[off] print( "Process field. Off = 0x%04X, type_name = %s (%d: %s), field_name = %s" % (off, type_name, type_kind, type_sizes[type_kind][0], field_name)) type_size = type_sizes[type_kind][1] ret = ida_struct.add_struc_member(sptr, field_name.decode(), off, flags_dict[type_size], None, type_size) if ret != 0: ida_kernwin.warning("Unknown error! Err = %d" % ret) return mptr = ida_struct.get_member(sptr, off) ida_struct.set_member_cmt( mptr, " --> %s (%d: %s)" % (type_name.decode(), type_kind, type_sizes[type_kind][0]), False) struct_size = ida_struct.get_struc_size(sptr) if size < struct_size: ida_kernwin.warning( "Struct create error! final size (%d) > instanse size (%d)" % (struct_size, size)) elif size > struct_size: for i in range(size - struct_size): ida_struct.add_struc_member(sptr, "dummy%d" % i, idaapi.BADADDR, idaapi.FF_BYTE, None, 1)
def add_child_vtable(parent_name, child_name, child_vtable_id, offset): logging.debug( "add_child_vtable (%s, %s, %s)", parent_name, child_name, child_vtable_id, ) parent_vtable_member = ida_struct.get_member( utils.get_sptr_by_name(parent_name), offset ) vtable_member_tinfo = utils.get_member_tinfo(parent_vtable_member) parent_vtable_struct = utils.get_sptr_by_name( get_class_vtable_struct_name(parent_name, offset) ) if parent_vtable_struct is None: return None pointed_struct = utils.extract_struct_from_tinfo(vtable_member_tinfo) logging.debug("pointed_struct: %s", str(pointed_struct)) if ( (pointed_struct is None) or (not is_struct_vtable(pointed_struct)) or (parent_vtable_struct.id != pointed_struct.id) ): parent_vtable_member = None logging.debug("Not a struct vtable: %s", str(vtable_member_tinfo)) # TODO: Check that struct is a valid vtable by name if not parent_vtable_struct.is_union(): logging.debug("%s vtable isn't union -> unionize it!", parent_name) parent_vtable_struct = install_vtables_union( parent_name, parent_vtable_member, vtable_member_tinfo, offset ) child_vtable_name = ida_struct.get_struc_name(child_vtable_id) child_vtable = utils.get_typeinf(child_vtable_name) logging.debug( "add_to_struct %s %s", parent_vtable_struct.id, str(child_vtable) ) if ida_struct.get_struc_size(child_vtable_id) == 0: utils.add_to_struct( ida_struct.get_struc(child_vtable_id), "dummy", None ) new_member = utils.add_to_struct( parent_vtable_struct, get_class_vtables_field_name(child_name), child_vtable ) ida_xref.add_dref( new_member.id, child_vtable_id, ida_xref.XREF_USER | ida_xref.dr_O )
def struct(name): sid = ida_struct.get_struc_id(name) if sid == 0xffffffffffffffff: return None sptr = ida_struct.get_struc(sid) size = ida_struct.get_struc_size(sptr) _struct = Struct(name, size, {}, last_change=int(time())) for mptr in sptr.members: mid = mptr.id m_name = ida_struct.get_member_name(mid) m_off = mptr.soff m_type = ida_typeinf.idc_get_type(mptr.id) if mptr.has_ti() else "" m_size = ida_struct.get_member_size(mptr) _struct.add_struct_member(m_name, m_off, m_type, m_size) return _struct
def read_struct(ea, struct=None, sid=None, members=None, asobject=False): """Read a structure from the given address. This function reads the structure at the given address and converts it into a dictionary or accessor object. Arguments: ea: The linear address of the start of the structure. Options: sid: The structure ID of the structure type to read. struct: The name of the structure type to read. members: A list of the names of the member fields to read. If members is None, then all members are read. Default is None. asobject: If True, then the struct is returned as a Python object rather than a dict. One of sid and struct must be specified. """ # Handle sid/struct. if struct is not None: sid2 = ida_struct.get_struc_id(struct) if sid2 == idc.BADADDR: raise ValueError('Invalid struc name {}'.format(struct)) if sid is not None and sid2 != sid: raise ValueError('Invalid arguments: sid={}, struct={}'.format( sid, struct)) sid = sid2 else: if sid is None: raise ValueError('Invalid arguments: sid={}, struct={}'.format( sid, struct)) if ida_struct.get_struc_name(sid) is None: raise ValueError('Invalid struc id {}'.format(sid)) # Iterate through the members and add them to the struct. union = idc.is_union(sid) struct = {} for offset, name, size in idautils.StructMembers(sid): if members is not None and name not in members: continue _read_struct_member(struct, sid, union, ea, offset, name, size, asobject) if asobject: struct = objectview(struct, ea, ida_struct.get_struc_size(sid)) return struct
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 __process_structs(self): structs = [] st_idx = ida_struct.get_first_struc_idx() while st_idx != ida_idaapi.BADADDR: st_id = ida_struct.get_struc_by_idx(st_idx) st_obj = ida_struct.get_struc(st_id) st_name = ida_struct.get_struc_name(st_id) structs.append({ 'type': self.__describe_struct_type(st_obj.props), 'name': st_name, 'size': int(ida_struct.get_struc_size(st_obj)), 'members': self.__process_struct_members(st_obj) }) st_idx = ida_struct.get_next_struc_idx(st_idx) return structs
def create_structs(self): self.struct_id = utils.add_struc_retry(self.name) if self.struct_id == BADADDR: return False self.name = idc.get_struc_name(self.struct_id) self.struct_ptr = ida_struct.get_struc(self.struct_id) if self.struct_ptr is None: log.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.updated_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: log.warning( "bad struct id or size: %s(0x%X:%s) - 0x%X, %d", self.name, parent_offset, parent_name, baseclass_id, baseclass_size, ) cpp_utils.add_baseclass(self.name, parent_name, parent_offset) previous_parent_offset = parent_offset previous_parent_size = baseclass_size previous_parent_struct_id = baseclass_id if self.updated_parents: utils.refresh_struct(self.struct_ptr) return True
def get_member_params(member_tif, is_offs): """@return: tuple(flag, mt, member_size)""" substruct_ptr = get_struc_from_tinfo(member_tif) if substruct_ptr: flag = idaapi.FF_STRUCT mt = ida_nalt.opinfo_t() mt.tid = substruct_ptr.id member_size = ida_struct.get_struc_size(substruct_ptr.id) else: flag = idaapi.FF_QWORD if WORD_LEN == 8 else idaapi.FF_DWORD mt = None member_size = WORD_LEN if is_offs: flag |= idaapi.FF_0OFF mt = ida_nalt.opinfo_t() r = ida_nalt.refinfo_t() r.init(ida_nalt.get_reftype_by_size(WORD_LEN) | ida_nalt.REFINFO_NOBASE) mt.ri = r return flag, mt, member_size
def _get_frame(self): result = False sp = get_sp_val() ip = get_ip_val() if ip and sp: f = get_func(ip) if f: frame = get_frame(f) if frame: self.framesize = get_struc_size(frame) n = frame.memqty frame_offs = f.frregs + f.frsize self.ea = sp - get_spd(f, ip) - frame_offs for i in xrange(n): m = frame.get_member(i) if m: lvar_name = get_member_name(m.id) lvar_ea = self.ea + m.soff lvar_size = m.eoff - m.soff self.members[lvar_ea] = (lvar_name, m.soff, lvar_size, frame_offs) result = True return result
def makeStructType(self, offset): idc.SetType(offset, "structType") sid = ida_struct.get_struc_id("structType") slice_id = ida_struct.get_struc_id("slice") offset_elem = idc.get_member_offset(sid, "fields") inner_offset = idc.get_member_offset(slice_id, "data") addr = self.stepper.ptr(offset_elem + offset + inner_offset) inner_offset = idc.get_member_offset(slice_id, "len") size = self.stepper.ptr(offset+offset_elem+inner_offset) if size == 0: return idc.SetType(addr, "structField") sz = ida_struct.get_struc_size(ida_struct.get_struc_id("structField")) self.make_arr(addr, size, sz, "structField") sid_type = ida_struct.get_struc_id("type") size_new_struct = self.getPtr(sid_type, offset, "size") for i in xrange(size): self.processStructField(addr, i*sz) name = self.getName(offset) name = Utils.relaxName(name) name = "ut_" + name self.createUserTypeStruct(addr, name, size, size_new_struct)
def _validate_ida_type(self): # type ID if self.tid is None or self.tid is BADADDR: self.log.warn("validate_ida_type: tid=%s is invalid", str(self.tid)) return False # struc_t pointer ida_sptr = ida_struct.get_struc(self.tid) if ida_sptr.id != self.sptr.id: self.log.warn( "validate_ida_type: sptr.id mismatch. Got %s but expected %s", str(ida_sptr.id), str(self.sptr.id)) return False # Size ida_size = ida_struct.get_struc_size(ida_sptr) if ida_size != self.size: self.log.warn( "validate_ida_type: size mismatch. Got %s but expected %s", str(ida_size), str(self.size)) return False # members count = 0 ida_memb = self.sptr.members # first member while True: found = False ida_name = ida_struct.get_member_name(ida_memb.id) for memb in self.members_array: if memb.name != ida_name: continue found = True memb._set_mptr(ida_memb) if not memb._validate_ida_type(): self.log.warn( "validate_ida_type: field '%s' failed validation", memb.name) return False if not found: self.log.warn( "validate_ida_type: found unexpected member '%s'", str(ida_name)) return False count += 1 next_idx = ida_struct.get_next_member_idx( self.sptr, ida_memb.soff) # next member index if next_idx == -1: break ida_memb = self.sptr.get_member(next_idx) # next member # member count if count != len(self.members_array): self.log.warn( "validate_ida_type: incorrect number of members. Got %d, expected %d", count, len(self.members_array)) return False self.log.debug("validate_ida_type: found match for '%s'", self.hierarchy) return True
def update_vtable_struct( functions_ea, vtable_struct, class_name, this_type=None, get_next_func_callback=get_vtable_line, vtable_head=None, ignore_list=None, add_dummy_member=False, pure_virtual_name=None, parent_name=None, add_func_this=True, force_rename_vtable_head=False, # rename vtable head even if it is already named by IDA # if it's not named, then it will be renamed anyway ): # pylint: disable=too-many-arguments,too-many-locals,too-many-branches # TODO: refactor if this_type is None: this_type = utils.get_typeinf_ptr(class_name) if not add_func_this: this_type = None func_ea, next_func = get_next_func_callback( functions_ea, ignore_list=ignore_list, pure_virtual_name=pure_virtual_name, ) dummy_i = 1 offset = 0 while func_ea is not None: new_func_name, _ = update_func_name_with_class(func_ea, class_name) func_ptr = None if ida_hexrays.init_hexrays_plugin(): fix_userpurge(func_ea, idc.TINFO_DEFINITE) update_func_this(func_ea, this_type, idc.TINFO_DEFINITE) func_ptr = utils.get_typeinf_ptr(utils.get_func_tinfo(func_ea)) else: func_ptr = make_funcptr_pt(func_ea, this_type) # TODO: maybe try to get or guess type? if add_dummy_member: utils.add_to_struct(vtable_struct, "dummy_%d" % dummy_i, func_ptr) dummy_i += 1 offset += utils.WORD_LEN ptr_member = utils.add_to_struct( vtable_struct, new_func_name, func_ptr, offset, overwrite=True, is_offs=True ) if ptr_member is None: log.error( "Couldn't add %s(%s) to vtable struct 0x%X at offset 0x%X", new_func_name, str(func_ptr), vtable_struct.id, offset, ) offset += utils.WORD_LEN if not ida_xref.add_dref(ptr_member.id, func_ea, ida_xref.XREF_USER | ida_xref.dr_I): log.warn( "Couldn't create xref between member %s and func %s", ida_struct.get_member_name(ptr_member.id), idc.get_name(func_ea), ) func_ea, next_func = get_next_func_callback( next_func, ignore_list=ignore_list, pure_virtual_name=pure_virtual_name, ) vtable_size = ida_struct.get_struc_size(vtable_struct) if vtable_head is None: vtable_head = functions_ea # ida_bytes.del_items(vtable_head, ida_bytes.DELIT_SIMPLE, vtable_size) ida_bytes.create_struct(vtable_head, vtable_size, vtable_struct.id) if not idc.hasUserName(idc.get_full_flags(vtable_head)) or force_rename_vtable_head: if parent_name is None and this_type: parent = utils.deref_struct_from_tinfo(this_type) parent_name = ida_struct.get_struc_name(parent.id) if parent_name == class_name: parent_name = None idc.set_name( vtable_head, get_vtable_instance_name(class_name, parent_name), ida_name.SN_CHECK | ida_name.SN_FORCE, )