如何在 IDA 中为非标准函数调用生成函数调用树?

逆向工程 艾达
2021-06-21 19:54:13

我有大型 PE 文件(C++),其中有很多使用vtable的间接函数调用jmp dword

如何为此类函数生成调用树?(就像 IDA 用户外部参照图表菜单一样)。

下面是一个反汇编代码的例子:

UPX1:2401135C sub_2401135C proc near                  ; CODE XREF: sub_2401263C+Cp
UPX1:2401135C                                         ; StartAddress+21p ...
UPX1:2401135C test    eax, eax
UPX1:2401135E jz      short locret_2401136A
UPX1:24011360 call    ds:off_24057054
UPX1:24011366 or      eax, eax
UPX1:24011368 jnz     short loc_2401136B
UPX1:2401136A
UPX1:2401136A locret_2401136A:                        ; CODE XREF: sub_2401135C+2j
UPX1:2401136A retn
UPX1:2401136B ; ---------------------------------------------------------------------------
UPX1:2401136B
UPX1:2401136B loc_2401136B:                           ; CODE XREF: sub_2401135C+Cj
UPX1:2401136B mov     al, 2
UPX1:2401136D jmp     sub_2401141C
UPX1:2401136D sub_2401135C endp

ds:off_24057054如果我将包含数据外部参照,则用户外部参照图表只能显示调用分支。我该怎么做才能看到jmp sub_2401141C分支?

1个回答

在这些情况下,调用的目标是在运行时生成的,不能静态确定(极少数例外)。

您需要在运行二进制文件时记录此信息,并使用 AddCodeXref API 或类似方法将额外信息合并到您的 IDB 中。

如果你不想写自己的东西,这个插件可以帮助你做到这一点以及更多:funcap

编辑

jmp subxxx的情况下,跳转的目标是明确定义的。您可以以编程方式遍历整个二进制文件,提取跳转目标并添加交叉引用。

我一起破解了一些东西,试一试。

def is_external_jmp(ins_ea):
    """
    True for JMPs between functions.
    NN_JMP (86): jmp sub_xxx (0xE9 + offset) or jmp loc_xxx (0xE9 + offset)
    """    
    decode_insn(ins_ea)

    if cmd.itype == NN_jmp:
        # HACK: GetOperandValue returns the target
        # address, not the offset (as I would expect)
        target = GetOperandValue(ins_ea, 0)
        (s, e) = current_function_boundaries(ins_ea)

        if target < s or target > e:
            # Not within the current function
            return True

    return False


def current_function_boundaries(ea=None):
    """
    Convenience function
    @returns: boundaries or None
    """
    if not ea:
        ea = ScreenEA()

    f = get_func(ea)

    if not f:
        # Probably called outside a function
        return (None, None)

    else:
        return (f.startEA, f.endEA)


def main():

    for f_ea in Functions():
        for ins_ea in FuncItems(f_ea):
            if is_external_jmp(ins):
                # One of these "jmp sub_xxx"
                target = GetOperandValue(ins_ea, 0)
                AddCodeXref(ins_ea, target, fl_CN)



if __name__ == '__main__':
    main()