通过脚本在结构体中设置IDA函数指针

4 投票
1 回答
3741 浏览
提问于 2025-04-18 11:29

通常,我们手动把一个结构体的成员改成函数指针的方法是,点击这个成员,按下'Y'键,然后在弹出的框里输入正确的声明。例如,对于结构体成员fncQuery,我会把字符串改成:

BOOL (__cdecl *fncQuery)(char *cmdID)

这样做是有帮助的;当我下次找到这个函数指针的调用时,我会把相应的“call [reg+offset]”这一行标记为这个函数指针,IDA会重新分析并为我注释参数。

我有一千个结构体,每个结构体至少有一个这样的函数指针成员,还有对应的这些函数参数和返回值的描述。可以理解的是,我想通过一个IDAPython脚本来匹配它们,而不是手动去做。不过,我找不到脚本中和'Y'按钮等效的功能。

AddStrucMember好像不行——我可以通过给它一个结构体ID来声明一个成员成为指向结构体的指针,但这不是我需要的。

SetMemberType和前面的也一样。

SetType需要一个线性地址和一个类型字符串——这本来是完美的,但线性地址只适用于代码段,所以我无法用SetType去修改结构体成员的定义。

在我的搜索中,我发现有人用低级的idaapi结合他的IDAPython脚本,做了一些“黑魔法”,来检测一个结构体成员是否和已知函数同名,如果是的话,就“获取”这个函数的类型并“设置”到这个成员上。具体来说,这种可怕的调用是这样的(虽然我没有提供完整的上下文,但你得相信我,这段代码运行得很好,第一次函数调用会用有意义的值填充它的多个输出参数):

get_named_type = g_dll.get_named_type
get_named_type.argtypes = [
    ctypes.c_void_p, #const til_t *ti,
    ctypes.c_char_p, #const char *name,
    ctypes.c_int, #int ntf_flags,
    ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const type_t **type=NULL,
    ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const p_list **fields=NULL,
    ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const char **cmt=NULL,
    ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const p_list **fieldcmts=NULL,
    ctypes.POINTER(ctypes.c_ulong), #sclass_t *sclass=NULL,
    ctypes.POINTER(ctypes.c_ulong), #uint32 *value=NULL);
]

get_named_type(
                til,
                funcname,
                idaapi.NTF_SYMM,
                ctypes.byref(typ_type),
                ctypes.byref(typ_fields),
                ctypes.byref(typ_cmt),
                ctypes.byref(typ_fieldcmts),
                ctypes.byref(typ_sclass),
                ctypes.byref(value)
type_arr = ctypes.create_string_buffer(0x400)
                type_arr[0] = chr(idaapi.BT_PTR)
                manualTypeCopy(type_arr, 1, len(type_arr), typ_type)
                ret = g_dll.set_member_tinfo(
                    til,
                    struc,
                    memb,
                    ctypes.c_uint(0),
                    type_arr,
                    typ_fields,
                    ctypes.c_uint(0),
                )

关于“get_named_type”的幕后工作我不是很明白,查看它的源代码(并从中做一些我自己的使用)可能会显得有些强人所难和过早。

你知道有没有更简单的方法可以满足我的需求吗?我只需要从一个IDAPython脚本中把结构体成员定义为函数指针。请帮帮我,谢谢 :)

1 个回答

4

这是个老问题,但我找到了解决方案,分享给大家:

SetType(idc.get_member_id(id, offset), "__int64 (__fastcall *)(ClassName *this)");
  • id - 这是一个结构的标识符(由 idc.add_struc 返回的值,以前叫 AddStrucEx
  • offset - 这是结构中某个成员的偏移量。如果你需要通过成员名称来改变类型,可以使用 get_member_offset(以前叫 GetMemberOffset)来实现

对于更新版本的 IDA/IDAPython,请参考 这个迁移指南

撰写回答