因此,基本上我想做的就是在执行汇编代码的分析任务期间将数据与内存地址区分开。
这是我很难应付的例子。
假设我们在.data节中声明了一个变量val。
0x08048054 01 00 00 00
这是通过反汇编ELF文件的一行汇编代码。
mov $0x08048054, %eax
所以可能这是变量val的间接引用,如下所示:
mov $0x8048054,%eax
mov %edx,0x4(%esp)
mov %eax,(%esp)
call printf
然后将$ 0x8048054转换为变量名val,如下所示:
mov val,%eax
mov %edx,0x4(%esp)
mov %eax,(%esp)
call printf
但是还有另一种情况,在一个计算中仅将0x8048054用作数字:
mov $0x8048054,%eax
add 0x8(%ebp), %eax
大概等于(我知道我们很难在实际代码中看到这个,但这是可能的)
b = 0x8048054 + argc;
在这种情况下,我不应该将$ 0x8048054重新写入val
所以我在想的是,如果我能弄清楚%eax寄存器的类型,我可能可以区分这两种情况。
我做对了吗?
谁能给我些帮助吗?
谢谢!
“类型”的一个视图是应用于值的一组操作。
因此,了解寄存器(或一个或多个存储器位置)中值的“类型”的方法是确定程序对其应用了哪些操作。应用于寄存器的每个操作建议该值可能是例如“类型约束”的一组可能的类型。
如果在操作中使用寄存器来确定地址,这反过来会导致内存获取(x86 LEA指令“形成地址”,但不会导致内存获取!),那么它就是某种指针。什么样的内存获取提示了指针的类型。如果是字节获取,则可能是“ char的指针”,如果是获取浮点单位的值,则可能是“指向double的指针”。因此,使用寄存器的方式建立了一些类型约束(例如,“可能是类型T”)。
如果将寄存器添加到另一个寄存器或添加到该寄存器,则它可以是指针(例如,指针算术)或数字(整数或自然数)。如果寄存器被多义或除法,则它可能不是指针。
但是这些分析仅限于您可以通过直接检查一些使用寄存器值的指令(例如,可以由特定寄存器值“达到”的那些指令)来确定的内容。
但是,许多机器操作通常只是通过寄存器复制值。您真正想要做的是对寄存器值来自何处以及去向何处的数据流分析。流入,流入或流出寄存器的值上的所有运算符都应用于建立类型约束。类型的更好表征是(数据)流经寄存器的值的类型约束的交集。(您必须担心是否发生了不可见的强制转换:在许多体系结构中,无需任何特定的机器指令,指向字符串的指针可以“无形地转换”为指向其第一个字符的指针)。
因此,类型推断过程需要对整个程序进行数据流分析(由于某些数据流取决于值的类型,因此可能是迭代的),估计每个值的类型的交集,然后考虑是否隐含转换可能会发生。(您可以在头脑中进行这种推理过程,但是如果您必须在大型程序上进行推理,则实际上将需要工具来管理庞大的数据量)。
通常,您无法做到完美;可以很容易地将类型推断转变为图灵暂停问题:
if Turing(x) then op1(register1) else op2(register1) endif
[因此,寄存器始终仅在op1中使用还是仅在op2中使用?]因此,您对类型的估计会有些许困难。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句