根据字符串引用的虚拟地址在二进制文件(PE)中查找指令

逆向工程 拆卸 视窗 可执行 x64dbg 修补
2021-06-12 20:42:47

英语不是我的第一语言,所以如果我的文字不太清楚,我很抱歉。

我正在尝试为 PE 二进制文件编写一个自动修补程序,它应该适用于该可执行文件的多个版本。为此,我需要找到引用特定静态字符串的指令的字节。我需要为下面以红色突出显示的 LEA 指令找到文件中的字节:

在此处输入图片说明

我不能简单地对“48 8D 15 C8 50 DA 00”进行模式搜索,因为操作码的最后四个字节在可执行版本之间会随着字符串地址的变化而变化。

使用十六进制编辑器在文件中查找字符串偏移量非常容易,并且将该偏移量转换为虚拟地址也非常简单,我已经开始工作了(从文件偏移量转换为 VA 正确生成了 0x140FDE580)。

问题实际上是从这个虚拟地址进入 LEA 地址操作数 (C8 50 DA 00) 的二进制操作码。既然这个地址是相对于当前指令位置的,那么除了在每条指令之间迭代,计算EIP和字符串VA之间的距离,看看当前指令是否寻址这个VA偏移量之外,还有没有更优化的搜索这条指令的方式?

提前致谢!

2个回答

将 RVA 作为字节搜索适用于 x86 代码,因为 RVA 直接在指令中编码。但是,正如您所注意到的,它不适用于 x64,在 x64 上您有一个RIP-relative 偏移量,该偏移量显然会根据指令的地址而变化。

我看不到您可以在这里使用的任何技巧,但我认为除非您的二进制文件是多 GB,否则.text在每个字节边界处对该部分进行简单的蛮力操作应该足够快。如果在实践中仍然太慢,请将您的代码连同解释发布到 Stack Overflow 或 Code Golf,以便其他程序员可以建议您加快速度。

当然,只需屏蔽动态字节并增加模式的大小。

48 8D 15 C8 50 DA 00 [原件]
C8 8D 15 ? ? ? ? ... [新的]

显然,您的模式必须更长才能保持唯一性,但它会在大多数更新中保持一致,除非大多数情况下更改了编译器设置。只需让您的模式忽略动态偏移即可。好吧,那是你的模式问题。

就您的 RIP 相对问题而言,这非常简单。
目标 = (RIP + InstrLen + InstrImm)。

目标只是下一条指令(RIP + InstrLen),偏移量为(NextInstr - ImmSize)。您需要知道的只是指令长度和跟随分支的立即数。如果你想使用一个宏,像 DiStorm 这样的许多库也有遵循当前指令的宏。