类型重建歧义

逆向工程 艾达 反编译 类型重建
2021-06-22 20:32:25

TIE: Principled Reverse Engineering of Types in Binary Programs 中,Lee J. 等人声称解决了类型重构带来的 C 代码反编译过程中的大部分挑战。

虽然生成一个void *可能适合a 的复杂类型绝对不是微不足道的,但我只是在考虑可能的类型恢复歧义,因为它只涉及类型intor的变量int *

int foo(int *a, int sz) {
    int res = 0;
    for (int *q = a; q < &a[sz]; q++)
        res += *q;
    return res;
}

在 32 位体系结构中,上面的代码显示了 variable 的这种歧义的示例res,因为intint *都与 32 位寄存器兼容,反汇编代码是相同的。如果res是一个指针,它会被不正确地使用,因为我们将返回一个自动变量的地址(并且会导致未定义的行为)。

那么这个例子真的可以考虑吗(是一个有效的例子)吗?你能举出一个例子,说明这两种类型产生歧义但正确使用吗?我们是否可以得出结论,如果一个变量只是被取消引用,就可以推断出它是一个指针吗?

2个回答

我在实际程序中看到的一个常见问题是 NULL 指针,它与整数 0 具有相同的值。例如,目前(2020 年)Hex-Rays 反编译器不支持保存不同类型的一个变量,例如当一个寄存器初始化为零在一个分支中用作整数,在另一个分支中用作指针,您可能会看到“有趣”的输出。唉,我手头没有例子,但如果我再次看到它,我会在这里添加它。

想到的另一件事是使用一个字段来存储下一个和上一个指针的双链表的“聪明”实现,称为XOR 链表这种模式可能几乎不可能自动恢复,但幸运的是,它似乎更像是一种理论上的好奇而不是实际构造。

实际上,类型重构主要是看程序是如何使用数据的,并试图以此为基础推导出类型。您的示例对于大多数反编译器来说确实不是问题,因为res仅用作int(代码在将指针存储到时总是取消引用指针res)。

但是,在程序集级别,如果您所在的程序部分是完全静态的,您可以强制使用常量既是整数值是地址。例如:

mov 0xdeadbeef, %eax
xor %ebx, %eax       <-- bitwise operators are almost never used on addresses
mov (%ebx), $ecx     <-- Yet, %ebx is an address

反编译器的启发式在这里会给出矛盾的信息,是%ebx数据还是地址?因此,将做出一个决定,但不能保留两种类型(数据和地址)并将其向后移植到反编译代码。不知何故,这在翻译中丢失了。