清理 HexRays 输出

逆向工程 艾达 六线谱
2021-07-01 07:22:24

我的 HexRays 反编译器输出通常如下所示:

  v0 = LoadLibraryW(L"wininet.dll");
  v1 = v0;
  if ( !v0 )
    goto LABEL_1;
  v2 = GetProcAddress(v0, "InternetOpenW");
  v3 = GetProcAddress(v1, "InternetConnectW");
  v4 = v2;
  v5 = v4;

对我来说,这里只有几个变量。v0、v2 和 v3。其余的完全重复。是否可以清理我的反编译器输出以消除这些无关变量?

3个回答

将光标定位在 v1 处并按=如果我没记错的话,从 IDA 6.6 开始,它将允许您定义某些变量实际上与其他变量相同。

从 v6.6 开始,IDA 支持反编译 API文档很差,几乎不存在。然而,理论上,应该可以编写一个插件来对反编译器生成的抽象语法树 (AST) 进行静态分析,从而消除无用的单元分配。

关于如何在 Python 中以编程方式映射、重命名和重新键入变量的简短 tl; dr 代码示例。

编辑:将代码添加到 set_lvar_type 以允许使用类型的字符串(我花了很长时间才解决这个问题)。现在您可以执行以下操作:

mapping = [ 'accum', 'v7', 'v4', 'shift', 'v5', 'v6', 'ptr', 'v2', 'v3' ]
for n, x, y in chunk_tuple(mapping, 3):
    if map_lvar(x, y, ea) and              \
       set_lvar_type(y, 'int32_t', ea) and \
       rename_lvar(y, n, ea):
            print("set {}".format(n))

在此处输入图片说明

请注意,int作为一种类型不起作用,但int32_t

其余代码github不要指望这会在 IDA 6.x 上工作,尽管可能会。我从来没有试过。

import re
from itertools import islice

import ida_hexrays
import idaapi
import idautils
import idc


def map_lvar(src, dst, ea):
    func = idaapi.get_func(ea)
    if func:
        ea = func.start_ea
        vu = idaapi.open_pseudocode(ea, 0)

        lvars1 = [n for n in vu.cfunc.lvars if n.name == src]
        lvars2 = [n for n in vu.cfunc.lvars if n.name == dst]
        if len(lvars1) == 1 and len(lvars2) == 1:
            print("mapping {} to {}".format(lvars1[0].name, lvars2[0].name))
            # we might need to change the lvar type?
            vu.set_lvar_type(lvars1[0], lvars2[0].type())
            vu.map_lvar(lvars1[0], lvars2[0])
        else:
            print("couldn't find one of the vars {} or {}".format(src, dst))

def set_lvar_type(src, t, ea):
    if isinstance(t, str):
        type_tuple = idaapi.get_named_type(None, t, 1) 
        tif = idaapi.tinfo_t()
        tif.deserialize(None, type_tuple[1], type_tuple[2])
        if tif:
            t = tif
        else:
            print("couldn't convert {} into tinfo_t".format(t))
            return False

    func = idaapi.get_func(ea)
    if func:
        ea = func.start_ea
        vu = idaapi.open_pseudocode(ea, 0)
        if not vu:
            return False
        lvars = [n for n in vu.cfunc.lvars if n.name == src]
        if len(lvars) == 1:
            print("changing type of {} to {}".format(lvars[0].name, t))
            return vu.set_lvar_type(lvars[0], t)
        else:
            print("couldn't find var {}".format(src))
    return False

def rename_lvar(src, dst, ea):
    def make_unique_name(name, taken):
        if name not in taken:
            return name
        fmt = "%s_%%i" % name
        for i in range(3, 1024):
            tmpName = fmt % i
            if tmpName not in taken:
                return tmpName
        return "i_give_up"

    func = idaapi.get_func(ea)
    if func:
        ea = func.start_ea
        vu = idaapi.open_pseudocode(ea, 0)
        names = [n.name for n in vu.cfunc.lvars]
        if dst in names:
            dst = make_unique_name(dst, names)
        lvars = [n for n in vu.cfunc.lvars if n.name == src]
        if len(lvars) == 1:
            print("renaming {} to {}".format(lvars[0].name, dst))
            vu.rename_lvar(lvars[0], dst, 1)
            # how to close the view without a widget object?
            #     idautils.close_pseudocode (nope)
            #     ida_kerwin.close_widget   (nope)
        else:
            print("couldn't find var {}".format(src))