我对Windows x64内核模式驱动程序进行了以下反汇编,现在由IDA Pro 7.1.180227创建:我也知道该代码的目的是将所述指针参数设置为
rdx
。操作码是
NULL
。并将其与ODA中的参考进行交叉引用或使用ODA进行参考,得到的结果与IDA相同:33 D2
。在确切的代码路径上的其他地方使用以存储其他指针。因此,从理论上讲,xor edx, edx
的高位双字可能是“脏”。为什么它不是这样显示在反汇编中? REX.W操作码的前缀会影响操作数的大小。对于此操作码,操作数大小(66h)和地址大小(67h)前缀均不存在。
因此,按照Intel SDM(“ XOR-逻辑异或”部分),我确实应该处理操作码
rdx
或指令edx
,以确认操作码的IDA转换。参阅Intel SDM的第2.1.5节(“ ModR / M和SIB字节的寻址模式编码”)为我们提供了有关如何对操作数(rdx
)进行编码的线索,并因此从表2-2( “带有ModR / M字节的32位寻址形式”):xor rdx, rdx
作为操作数。数字。
但是,这将意味着
33 /r
中的“脏”高位双字不会被清零,因此最终将通过乱码/截断指针。鉴于这是内核模式代码,其后果应该很清楚。我简直不敢相信编译器会犯这样的错误。那我想念什么呢?
#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
小一个字节,因此编译器更喜欢它。评论
顺便说一句,这也给其他问题带来了麻烦。例如,NOP指令通常为0x90,实际上是xchg eax,eax。但是在64位模式下,这不是NOP,因为它会将高32位清零。因此xchg eax,eax在64位和32位模式下具有不同的编码。
– jakobbotsch
18年7月5日在14:41
我在某处读到了有关该消息的信息,但没有建立连接。
– 0xC0000022L♦
18年7月5日在15:22
@IgorSkochinsky是的,这就是我的意思。他们必须找到xchg eax的新编码,因为eax在x64上不是NOP。
– jakobbotsch
18年7月5日在18:28
@Joshua:是的,我认为Jakob的意思是,汇编程序不能在asm源中将xchg eax,eax使用0x90缩写形式,而必须使用带有ModRM字节的xchg r,r / m32形式( felixcloutier.com/x86/XCHG.html)。但有趣的是,16位和64位操作数大小仍可以使用带有66或REX.W前缀的0x90。 NASM确实在64位模式下将xchg ax,ax组装为66 90。
– Peter Cordes
18年7月5日在21:17
@PeterCordes正是。我说的不好,但是最后我们到了那里!
– jakobbotsch
18年7月6日在10:53
评论
您能提供一些相关代码吗?例如,使用E / RDX的代码,在XOR指令之前对其进行处理的其他代码等。我最近遇到了一个类似的问题,在进行了更深入的研究之后,RDX的上半部分确实始终为零,这使得该问题成为无法利用的bug开发人员。stackoverflow的副本为什么32位寄存器上的x86-64指令将整个64位寄存器的上半部分置零?另请参见在x86汇编中将寄存器设置为零的最佳方法是:xor,mov或and ?这说明32位操作数大小始终是最好的(例如xor r10d,r10d不小于xor r10,r10,但是Silvermont仅将32位操作数大小识别为归零习惯!)