我正在使用idapython编写一个IDA插件,以便将注释(位于数据库中)添加到结构类型的变量中。为此,首先,我需要获取给定结构类型(例如,结构BITMAPINFO)的交叉引用列表,该列表可以在IDA的“结构”子视图中找到。

我知道IDA从6.2版开始提供此功能,方法是用鼠标右键单击结构名称并选择“列出交叉引用到”。将会弹出如下窗口:



上图中的列表的每个项都是地址,其中全局变量的类型为%structure name%声明(这里为BITMAPINFO)或定义“结构名称”类型的局部变量的位置。前者就像


(这里是GUID类型,而不是BITMAPINFO)。 IDA根据其标识的类型声明局部变量的位置。

我想知道是否有办法通过IDAPython获取这些数据。

注意:这与cross不同-引用结构类型的成员,可以通过右键单击结构成员名称来获得,如下所示。



在这里问之前,我是这样的:

#CODE 1
ea = idc.LocByName(%structure name%)  

frm = [x.frm for x in idautils.XrefsTo(ea)]


我想我已经使用上面的代码获得了对%structure name%的交叉引用的整个列表。但是,我发现列表中的许多EA似乎无效,例如“ 0xff0052c9”(MaxEA为0x108f800)。但是,我想我的代码已经达到了预期的效果,因为返回列表的长度等于列表中显示为第一张图片的项目数。但是我无法解释结果,尤其是(貌似)无效的结果。另外,当我使用以下代码向列表中的地址添加注释时

#CODE 2
for ea in xrefs_list:
    # each cross-reference to the given struc type

    if repeatable:
        # add repeatable comment 'cmt' at address 'ea'
        idc.MakeRptCmt(ea, cmt)

    else:
        # add comment  'cmt' at address 'ea'
        idc.MakeComm(ea, cmt)


我发现我只在idc.MinEA()和idc.MaxEA()之间的有效地址中添加了注释,并且这些地址是声明查询的结构类型的全局实例的地方,如第二张图片所示。 />
我的问题是:




我上面的代码(CODE 1)对获取结构类型的所有交叉引用是否正确?
如果是,该如何解释那些看似无效的地址(0xFF000000以上)
如何向除结构类型的全局实例的引用以外的其他交叉引用地址添加注释?



评论

好像那些引用是堆栈变量引用。我更新了答案以使其匹配。

#1 楼

堆栈变量参考

所显示的外部参照是来自堆栈变量的外部参照。如您所述,当尝试将外部参照获取到结构时,您会得到两种类型的结果:


有效地址,它们是数据部分中的结构实例

0xFF000000及以上地址,其中该结构用作堆栈变量。

在IDA中,函数的堆栈变量在内部表示为结构,每个堆栈变量均是该结构的成员。


idaman struc_t * ida_export get_frame(const func_t * pfn);


文档链接

知道这一点,我们可以推断出奇怪的外部参照是member-id(它们是)。要获取包含结构的名称,请使用fullname = idaapi.get_member_fullname(mid)并获取类似$ F4014B0.var_14的名称。
$ F4014B00xF4014B0处函数的堆栈框架结构的网络节点名称。

import idc
import idaapi
import idautils

sid = idc.GetStrucIdByName('my-struct-name')
for xref in idautils.XrefsTo(sid):
    if 0xFF000000 > xref.frm:
        # The struct is used as data
        print 'Data xref from 0x{:X}'.format(xref.frm)
    else:
        # The struct is used as a stack variable.
        mid = xref.frm
        fullname = idaapi.get_member_fullname(mid)
        function_ea = int(fullname[2:].split('.')[0], 0x10)
        print 'Stack xref from 0x{:X}'.format(function_ea)


获取成员变量的外部参照

(这里是因为这是我最初的回答,并且包含有价值的信息。)

您真的很接近解。您的代码为您提供了sid,因此您仅获得对该结构本身的引用。您需要的是对不同成员的引用,这可以使用mid完成。您可以使用完全限定的成员名称获取它。但是,由于每个结构都有很多成员,因此枚举通常是更好的选择。

import idc
import idautils

def get_member_ids(sid):
    offset = 0
    while offset != 0xFFFFFFFF:
        mid = idc.GetMemberId(sid, offset)
        if mid != -1:
            yield mid
        offset = idc.GetStrucNextOff(sid, offset)


def get_member_xrefs(struc_name):
    sid = idc.GetStrucIdByName(struc_name)
    for mid in get_member_ids(sid):
        for xref in idautils.XrefsTo(mid):
            yield xref.frm


# And the usage:
for xref in get_member_xrefs('my-struct-name'):
    print '0x{:X}'.format(xref)


编辑以评论问题Netnodes上的一点点

下一点是关于IDA内部的,所以我在这里可能不合时宜。我是基本的SDK文档信息,请参见此处。

在我的代码中可以看到,许多记录在有效地址(ea)上使用的API也可以在其他IDA原语上使用-结构ID,成员ID -没有任何区别。

在内部,IDA中的对象被映射到netnodes。 IDA中的行被线性映射到网络节点号,而其他对象则映射到以0xFF000000开始的数字。
虽然地址和结构ID可能具有不同的语义,但它们都是网络节点号。在IDA的API中,这意味着它们的处理方式相同。

我希望这可以使事情变得更清楚。

评论


感谢您的回答。您的代码返回的是每个结构成员的交叉引用的联合列表,也可以通过右键单击结构成员的名称来获得该列表。这与对%structure name%的交叉引用列表不同,这不是我想要的结果。我向问题添加了新信息。此外,我开始知道SID和MID可以用作EA。你能告诉我如何解释吗?

–冰场
16-6-5在17:09



@Bingchang,我编辑了回复,以解决您有关MID和SID的问题。我还没有主要问题的答案。我误会了。

–TMR232
16年5月5日在18:53

你的回答真的很酷。就像您回答的那样,那些(看似)无效的地址是对堆栈变量的引用,并且每个堆栈变量都是结构的成员,该结构在内部表示函数的堆栈框架。我已经解决了我的问题,并更新了我的问题以包括我的解决方案。此外,您还可以打开IDA内部的大门。

–冰场
16年6月6日在7:42



@Bingchang我很乐意提供帮助。请注意,您的问题与标题不再匹配。为了清楚起见,您可能希望将其分为两个独立的问题,以便将来人们可以更轻松地查找它。

–TMR232
16年6月6日在12:35

按照您的建议,我重新编辑了我的问题并将其分为2个问题。但是,我不确定是否合适或是否需要打开一个新问题。

–冰场
16 Jun 8'在2:59



#2 楼

为了使问题和答案分开以使情况更清楚,我主要根据@ tmr232的答案添加了自己的解决方案。

对于第一个问题,就像@ tmr232回答的那样,那些(看似)无效地址是对堆栈变量的引用。在IDA的内部结构中,每个堆栈变量都被视为表示函数堆栈框架的结构的成员。问题中的CODE 1可以将所有交叉引用返回到结构类型,包括对全局实例和本地堆栈实例的交叉引用。

对于第二个问题,将注释添加到对本地堆栈的引用中实例可以通过将这些引用视为结构的成员来添加。

代码为:

def add_struct_cmt (struct_name, cmt, repeatable):

    # locate ea by structure name, here, ea is identical to sid
    sid = idc.LocByName(%structure name%)

    if sid == idaapi.BADADDR:
        return 

    # get all cross-references to 'sid' including references to global 
    # struct instances and references to local stack variables
    frm = [x.frm for x in idautils.XrefsTo(sid)]

    for ea in frm:

        if ea > idc.MaxEA():
            # references to stack variables

            # IDA 6.8 and above: getting 'member_t' using 'ea' as mid
            mptr = idaapi.get_member_by_id(ea)

            # IDA 6.8: setting member comment using 'mptr' as index
            idaapi.set_member_cmt(mptr, cmt, repeatable)

            # IDA 6.9: 'mptr' is type of list
            #idaapi.set_member_cmt(mptr[0], cmt, repeatable)

        else:
            # references to global struct instances

            if repeatable:
                # add repeatable comment
                idc.MakeRptCmt(ea, cmt)

            else:
                # add non-repeatable comment
                idc.MakeCmt(ea, cmt)     


评论


注意:1. API get_member_by_id在IDA 6.6中不存在,但是,可以被其他API绕过,例如sid = idaapi.get_member_struc(idaapi.get_member_fullname(mid)),然后枚举其成员

–冰场
16 Jun 8'在3:09



注意:在IDA 6.8中,idaapi.get_member_by_id返回“ member_t *”类型的代理,但是,在IDA 6.9中,它返回的是列表,而“ member_t *”类型的代理是第一个元素。

–冰场
16年6月8日在3:16