def add_ida_type(self, typ: "ida_typeinf.tinfo_t", worklist: t.Optional[t.Set[str]] = None) -> None: """Adds an element to the TypeLib by parsing an IDA tinfo_t object""" if worklist is None: worklist = set() if typ.dstr() in worklist or typ.is_void(): return worklist.add(typ.dstr()) new_type: TypeInfo = self.parse_ida_type(typ) # If this type isn't a duplicate, break down the subtypes if not self._data[new_type.size].add(new_type): if typ.is_decl_ptr() and not (typ.is_funcptr() or "(" in typ.dstr()): self.add_ida_type(typ.get_pointed_object(), worklist) elif typ.is_array(): self.add_ida_type(typ.get_array_element(), worklist) elif typ.is_udt(): udt_info = ida_typeinf.udt_type_data_t() typ.get_udt_details(udt_info) name = typ.dstr() size = udt_info.total_size nmembers = typ.get_udt_nmembers() for n in range(nmembers): member = ida_typeinf.udt_member_t() # To get the nth member set OFFSET to n and tell find_udt_member # to search by index. member.offset = n typ.find_udt_member(member, ida_typeinf.STRMEM_INDEX) self.add_ida_type(member.type, worklist)
def _convert_ida_type(tinfo, cache, depth, context): """Convert an IDA `tinfo_t` instance into a `Type` instance.""" assert isinstance(tinfo, ida_typeinf.tinfo_t) if 0 < depth: context = TYPE_CONTEXT_NESTED tinfo_str = str(tinfo) if tinfo_str in cache and context in (TYPE_CONTEXT_NESTED, TYPE_CONTEXT_FUNCTION): return cache[tinfo_str] # Void type. elif tinfo.empty() or tinfo.is_void(): return VoidType() # Pointer, array, or function. elif tinfo.is_paf(): if tinfo.is_ptr(): ret = PointerType() cache[tinfo_str] = ret ret.set_element_type( _convert_ida_type(tinfo.get_pointed_object(), cache, depth + 1, context) ) return ret elif tinfo.is_func(): ret = FunctionType() cache[tinfo_str] = ret ret.set_return_type( _convert_ida_type(tinfo.get_rettype(), cache, depth + 1, context) ) i = 0 max_i = tinfo.get_nargs() while i < max_i: ret.add_parameter_type( _convert_ida_type(tinfo.get_nth_arg(i), cache, depth + 1, context) ) i += 1 if tinfo.is_vararg_cc(): ret.set_is_variadic() if tinfo.is_purging_cc(): ret.set_num_bytes_popped_off_stack(tinfo.calc_purged_bytes()) if TYPE_CONTEXT_NESTED == context or TYPE_CONTEXT_FUNCTION == context: return ret func_ptr = PointerType() func_ptr.set_element_type(ret) return func_ptr elif tinfo.is_array(): num_elems = tinfo.get_array_nelems() if 0 == num_elems: # Strings in IDA will have a type of `char[]`. if TYPE_CONTEXT_GLOBAL_VAR == context: return _convert_ida_type( tinfo.get_array_element(), cache, depth + 1, context ) else: ret = PointerType() cache[tinfo_str] = ret ret.set_element_type( _convert_ida_type( tinfo.get_array_element(), cache, depth + 1, context ) ) return ret else: ret = ArrayType() cache[tinfo_str] = ret ret.set_element_type( _convert_ida_type( tinfo.get_array_element(), cache, depth + 1, context ) ) ret.set_num_elements(num_elems) return ret else: raise UnhandledTypeException( "Unhandled pointer, array, or function type: {}".format(tinfo.dstr()), tinfo, ) # Vector types. elif tinfo.is_sse_type(): ret = VectorType() cache[tinfo_str] = ret size = tinfo.get_size() # TODO(pag): Do better than this. ret.set_element_type(IntegerType(1, False)) ret.set_num_elements(size) return ret # Structure, union, or enumerator. elif tinfo.is_sue(): if tinfo.is_udt(): # Structure or union type. ret = tinfo.is_struct() and StructureType() or UnionType() cache[tinfo_str] = ret i = 0 max_i = tinfo.get_udt_nmembers() while i < max_i: udt = ida_typeinf.udt_member_t() udt.offset = i if not tinfo.find_udt_member(udt, ida_typeinf.STRMEM_INDEX): break # TODO(pag): bitfields # TODO(pag): padding ret.add_element_type( _convert_ida_type(udt.type, cache, depth + 1, context) ) i += 1 return ret elif tinfo.is_enum(): ret = EnumType() cache[tinfo_str] = ret base_type = ida_typeinf.tinfo_t(tinfo.get_enum_base_type()) ret.set_underlying_type(_convert_ida_type(base_type, cache, depth, context)) return ret else: raise UnhandledTypeException( "Unhandled struct, union, or enum type: {}".format(tinfo.dstr()), tinfo ) # Boolean type. elif tinfo.is_bool(): return BoolType() # Integer type. elif tinfo.is_integral(): return IntegerType(tinfo.get_unpadded_size(), tinfo.is_signed()) # Floating point. elif tinfo.is_floating(): size = tinfo.get_unpadded_size() if size in _FLOAT_SIZES: return FloatingPointType(size) elif tinfo.is_ldouble(): return FloatingPointType(10) elif tinfo.is_double(): return FloatingPointType(8) elif tinfo.is_float(): return FloatingPointType(4) else: raise UnhandledTypeException( "Unhandled floating point type: {}".format(tinfo.dstr()), tinfo ) elif tinfo.is_complex(): raise UnhandledTypeException( "Complex numbers are not yet handled: {}".format(tinfo.dstr()), tinfo ) # Type alias/reference. # # NOTE(pag): We return the underlying type because it may be void. elif tinfo.is_typeref(): ret = TypedefType() cache[tinfo_str] = ret utype = _convert_ida_type( ida_typeinf.tinfo_t(tinfo.get_realtype(True)), cache, depth, context ) ret.set_underlying_type(utype) cache[tinfo_str] = utype return utype else: raise UnhandledTypeException("Unhandled type: {}".format(tinfo.dstr()), tinfo)
def qword_mem(name): m = ida_typeinf.udt_member_t() m.name = name if ti.find_udt_member (m, ida_typeinf.STRMEM_NAME) == -1: raise Exception ('unknown DBMeta member {}'.format (name)) return butil.get_uint64(ea + m.offset // 8)
def dword_mem(name): m = ida_typeinf.udt_member_t() m.name = name if ti.find_udt_member(m, ida_typeinf.STRMEM_NAME) == -1: raise Exception('unknown DBMeta member {}'.format(name)) return idc.Dword(ea + m.offset / 8)
def _convert_ida_type(tinfo, cache): """Convert an IDA `tinfo_t` instance into a `Type` instance.""" assert isinstance(tinfo, ida_typeinf.tinfo_t) if tinfo in cache: return cache[tinfo] # Void type. if tinfo.empty() or tinfo.is_void(): return VoidType() # Pointer, array, or function. elif tinfo.is_paf(): if tinfo.is_ptr(): ret = PointerType() cache[tinfo] = ret ret.set_element_type( _convert_ida_type(tinfo.get_pointed_object(), cache)) return ret elif tinfo.is_func(): ret = FunctionType() cache[tinfo] = ret ret.set_return_type(_convert_ida_type(tinfo.get_rettype(), cache)) i = 0 max_i = tinfo.get_nargs() while i < max_i: ret.add_parameter_type( _convert_ida_type(tinfo.get_nth_arg(i), cache)) i += 1 if tinfo.is_vararg_cc(): ret.set_is_vararg() if tinfo.is_purging_cc(): ret.set_num_bytes_popped_off_stack(tinfo.calc_purged_bytes()) return ret elif tinfo.is_array(): ret = ArrayType() cache[tinfo] = ret ret.set_element_type( _convert_ida_type(tinfo.get_array_element(), cache)) ret.set_num_elements(tinfo.get_array_nelems()) return ret else: raise UnhandledTypeException( "Unhandled pointer, array, or function type: {}".format( tinfo.dstr()), tinfo) # Vector types. elif tinfo.is_sse_type(): ret = VectorType() cache[tinfo] = ret size = tinfo.get_size() # TODO(pag): Do better than this. ret.set_element_type(IntegerType(1, False)) ret.set_num_elements(size) return ret # Structure, union, or enumerator. elif tinfo.is_sue(): if tinfo.is_udt(): # Structure or union type. ret = tinfo.is_struct() and StructureType() or UnionType() cache[tinfo] = ret i = 0 max_i = tinfo.get_udt_nmembers() while i < max_i: udt = ida_typeinf.udt_member_t() udt.offset = i if not tinfo.find_udt_member(udt, ida_typeinf.STRMEM_INDEX): break # TODO(pag): bitfields # TODO(pag): padding ret.add_element_type(_convert_ida_type(udt.type, cache)) i += 1 return ret elif tinfo.is_enum(): ret = EnumType() cache[tinfo] = ret base_type = ida_typeinf.tinfo_t(tinfo.get_enum_base_type()) ret.set_underlying_type(_convert_ida_type(base_type, cache)) return ret else: raise UnhandledTypeException( "Unhandled struct, union, or enum type: {}".format( tinfo.dstr()), tinfo) # Boolean type. elif tinfo.is_bool(): return BoolType() # Integer type. elif tinfo.is_integral(): return IntegerType(tinfo.get_unpadded_size(), tinfo.is_signed()) # Floating point. elif tinfo.is_floating(): if tinfo.is_ldouble(): return FloatingPointType(tinfo.get_unpadded_size()) elif tinfo.is_double(): return FloatingPointType(8) elif tinfo.is_float(): return FloatingPointType(4) else: raise UnhandledTypeException( "Unhandled floating point type: {}".format(tinfo.dstr()), tinfo) elif tinfo.is_complex(): raise UnhandledTypeException( "Complex numbers are not yet handled: {}".format(tinfo.dstr()), tinfo) # Type alias/reference. elif tinfo.is_typeref(): ret = TypedefType() cache[tinfo] = ret ret.set_underlying_type(_convert_ida_type(tinfo.get_realtype(), cache)) return ret else: raise UnhandledTypeException("Unhandled type: {}".format(tinfo.dstr()), tinfo)
def parse_ida_type(typ: "ida_typeinf.tinfo_t") -> "TypeInfo": """Parses an IDA tinfo_t object""" if typ.is_void(): return Void() if typ.is_funcptr() or "(" in typ.dstr(): return FunctionPointer(name=typ.dstr()) if typ.is_decl_ptr(): return Pointer(typ.get_pointed_object().dstr()) if typ.is_array(): # To get array type info, first create an # array_type_data_t then call get_array_details to # populate it. Unions and structs follow a similar # pattern. array_info = ida_typeinf.array_type_data_t() typ.get_array_details(array_info) nelements = array_info.nelems element_size = array_info.elem_type.get_size() element_type = array_info.elem_type.dstr() return Array( nelements=nelements, element_size=element_size, element_type=element_type, ) if typ.is_udt(): udt_info = ida_typeinf.udt_type_data_t() typ.get_udt_details(udt_info) name = typ.dstr() size = udt_info.total_size nmembers = typ.get_udt_nmembers() if typ.is_union(): members = [] largest_size = 0 for n in range(nmembers): member = ida_typeinf.udt_member_t() # To get the nth member set OFFSET to n and tell find_udt_member # to search by index. member.offset = n typ.find_udt_member(member, ida_typeinf.STRMEM_INDEX) largest_size = max(largest_size, member.size) type_name = member.type.dstr() members.append( UDT.Field(name=member.name, size=member.size, type_name=type_name)) end_padding = size - (largest_size // 8) if end_padding == 0: return Union(name=name, members=members) return Union( name=name, members=members, padding=UDT.Padding(end_padding), ) else: # UDT is a struct layout: t.List[t.Union[UDT.Member, "Struct", "Union"]] = [] next_offset = 0 for n in range(nmembers): member = ida_typeinf.udt_member_t() member.offset = n typ.find_udt_member(member, ida_typeinf.STRMEM_INDEX) # Check for padding. Careful, because offset and # size are in bits, not bytes. if member.offset != next_offset: layout.append( UDT.Padding((member.offset - next_offset) // 8)) next_offset = member.offset + member.size type_name = member.type.dstr() layout.append( UDT.Field(name=member.name, size=member.size, type_name=type_name)) # Check for padding at the end end_padding = size - next_offset // 8 if end_padding > 0: layout.append(UDT.Padding(end_padding)) return Struct(name=name, layout=layout) return TypeInfo(name=typ.dstr(), size=typ.get_size())