Example #1
0
 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)
Example #2
0
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)
Example #3
0
 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)
Example #4
0
 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)
Example #5
0
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)
Example #6
0
 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())