IDA 是否在牵扯我的腿——或者 REX.W 有时无法在静态分析中确定?

逆向工程 艾达 x64 操作码
2021-06-24 20:39:23

注意:我通常会涉足反汇编(即助记符),并且只在无法避免的情况下查看原始操作码。

我有以下由 IDA Pro 7.1.180227 创建的 Windows x64 内核模式驱动程序的反汇编行:

xor     edx, edx

现在我知道一个事实,这是准备通过rdx. 我也知道该代码的目的是将所述指针参数设置为NULL.

操作码是33 D2. 和交叉引用与参考或看着它在官方发展援助得到相同的与IDA: xor edx, edx

现在,这个反汇编让我感到不妥的是rdx,作为 的超集edx,在该确切代码路径上的其他地方使用来存储其他指针。所以理论上,上面的双字rdx可能是“脏”。

根据这是 x64 代码的事实,我希望它能够读取xor rdx, rdx. 为什么这不是它在反汇编中的呈现方式?


现在我明白了,根据英特尔 SDM (05/2018) 的第 3.6.1 节(表 3-4),操作码的 REX.W 前缀会影响操作数大小。

对于此操作码,既不存在操作数大小 (66h) 也不存在地址大小 (67h) 前缀。

因此,通过英特尔 SDM(“XOR-Logical Exclusive OR”部分),我确实应该处理操作码33 /r或指令XOR r32, r/m32,确认操作码的 IDA 翻译。参考英特尔 SDM 的第 2.1.5 节(“ModR/M 和 SIB 字节的寻址模式编码”)为我们提供了有关操作数 ( D2)如何编码的线索,因此从表 2-2(“带有 ModR/M 字节的 32 位寻址形式"):EDX/DX/DL/MM2/XMM2作为操作数。

数据。

然而,这意味着“脏”的高位双字 inrdx不会被清零,因此最终会传递一个乱码/截断的指针。鉴于这是内核模式代码,后果应该很清楚。

我简直不敢相信编译器会犯这样的错误。那么错过了什么?

1个回答

在 x86-64 中,任何只影响寄存器低 32 位的操作都会自动将高 32 位清零。

英特尔架构手册中的相关部分在第 1 卷 3.4.1.1 中,其中指出:

在 64 位模式下,操作数大小决定目标通用寄存器中的有效位数:

  • 64 位操作数在目标通用寄存器中生成 64 位结果。
  • 32 位操作数生成 32 位结果,零扩展到目标通用寄存器中的 64 位结果。
  • 8 位和 16 位操作数生成 8 位或 16 位结果。目标通用寄存器的高 56 位或 48 位(分别)不会被操作修改。如果 8 位或 16 位运算的结果用于 64 位地址计算,则显式将寄存器符号扩展到完整的 64 位。

因此,两种形式都给出相同的结果,并且xor edx, edx比 短一个字节xor rdx, rdx,因此编译器更喜欢它。