我在几个Windows程序的开头都看到了这条指令。
它正在向自己复制一个寄存器,因此,基本上,它就像一个nop
该指令的目的是什么?

评论

本质:这是一个两字节的NOP。因此,当他在更改代码时尝试执行这部分代码时,您可以原子地修补两个字节,而不必让处理器加载不完整/不正确的指令。

在x86-64 mov edi中,edi不是NOP。在x86-64中,它将rdi的高32位清零。在32位代码mov edi中,edi可以用作NOP。

#1 楼

Raymond Chen(Microsoft)的博客文章中对此进行了详细讨论:
https://devblogs.microsoft.com/oldnewthing/20110921-00/?p=9583
总之,这是编译时的补充为了支持运行时热修补而应用,因此该函数可以使用JMP指令覆盖前两个字节,以将执行重定向到另一段代码。

评论


您可能应该在mov edi,edi指令之前添加有关5个空字节的注释。

–TMR232
2015年10月3日,9:59

为什么不像66 90这样真正的2字节NOP?这样会更有效率:不需要后端uop,不需要EDI的额外延迟(以防万一),不需要物理寄存器来重命名输出。也许这应该是工具可以识别出的“签名”,除非是在热补丁代码中?

– Peter Cordes
19/12/8在16:52



@PeterCordes:Raymond Chen讨论了devblogs.microsoft.com/oldnewthing/20130102-00/?p=5663“使用MOV EDI和EDI作为两字节NOP指令的决定是在咨询了CPU制造商的建议后做出的。最好的两字节NOP”

– Ben Schwehn
8月26日20:45



@BenSchwehn:呵呵,这个决定可能要追溯到P5奔腾日,其中66前缀使指令花费了额外的时间来解码。对于P6及以后的CPU,这是不幸的。不幸的是,它必须是NOP,而不是可选的有用指令,例如对于使用帧指针的函数的push ebp的2字节编码。 (使用带有一个现代字节的push r / m32形式,而不是1字节的短形式。)但是,这样处理起来不太容易,并且需要一种替代方案,不要对不需要推送任何内容的函数进行悲观化。

– Peter Cordes
8月26日21:02

#2 楼

它旨在跳转到mov指令之前5个字节的特定位置。从那里开始,您有5个字节,可以修改为跳到32位内存空间中的其他位置。请注意,在热修补时,应首先放置5个字节的跳转,然后可以替换mov。换种方式,您冒着被替换的mov-jmp首先运行的风险,并跳到可能发生的任何事情的5个字节(默认情况下为nops,但您永远都不知道)。

[addition

关于写入5个字节的跳转-还有一个问题是,只有一条指令可以让您原子地写入4个以上的字节-cmpxchg8b,这并不是理想的指令。如果先写入0xe9,然后再写入dword,则如果在放置dword之前执行了0xe9,则将出现竞争状态。首先写跳远的另一个原因。

评论


通常是NOP或INT3。

–mrduclaw
13年3月30日在2:06

是的,但是对于INT3,您绝对不想意外地运行它。

–彼得·弗里
13年4月5日在20:41

并且如果该功能已被绕行,则首先写入4字节的跳转目标地址将原子替换先前jmp拥有的任何rel32。 (假设dword是4字节对齐的,如果函数是8字节或16字节对齐的,则为dword。它在函数的开头结束。)

– Peter Cordes
19年12月8日在17:07

#3 楼

Courtsey Hotpatching和第三方补丁的兴起在BlackHat USA 2006上发表,作者是
Alexander
Sotirov

Hotpatching是什么?
Hotpatching是一种方法通过在运行时修改应用程序的二进制代码来修改其行为。这是一种具有多种用途的常见技术:


调试(软件断点)


运行时检测工具


挂钩Windows API函数


修改执行或向封闭源代码应用程序添加新功能



无需重新部署即可部署软件更新


修复安全漏洞

修补程序是由自动工具生成的,该工具可以将原始版本和修补的二进制文件。
更改的功能包含在扩展名为.hp.dll的文件中。
在运行的进程中加载​​hotpatch DLL时,将替换易受攻击的功能的第一条
指令。 / hotpatch编译器选项可确保
每个函数的第一条指令是
mov
edi,< bredi
可以安全地被hotpatch覆盖的指令。 Windows的较旧版本未与此选项进行编译,因此无法进行热修补。