x86 CPU 指令是如何编码的?

逆向工程 部件 x86
2021-07-06 01:44:04

我正在编写一个用于在运行时挂钩函数的小型实用程序库。我需要找出前几条指令的长度,因为我不想假设任何事情或要求开发人员手动输入要重新定位和覆盖的字节数。

有很多很好的资源可以学习汇编,但似乎没有一个关于汇编助记符如何变成原始二进制指令的详细信息。

4个回答

如果您想详细了解指令编码,您需要学习英特尔® 64 位和 IA-32 架构软件开发人员手册第 2 卷(指令集参考,AZ)请注意,Intel IA-32 和 AMD64 是非常复杂的指令集,为了挂钩一个不是专门设计为通过注入跳转挂钩的函数,您将遇到大量不同的指令。无法保证该函数甚至设置了堆栈帧。

有一些库可以为您进行反汇编和挂钩,例如Microsoft Research 的Detours

您可以使用反汇编程序将二进制操作码转换为汇编代码。

例如ndisam命令能够做到这一点。

如果您有以下二进制操作码(文件的十六进制视图):

31C0FFC0C3

使用以下命令反汇编时,您将获得以下输出ndisasm

00000000  31C0              xor ax,ax
00000002  FFC0              inc ax
00000004  C3                ret

其中第一列是文件偏移量,第二列是二进制操作码,最后一行是汇编代码。

然后您可以获得第二列并获得它的字符串长度并除以 2,您将获得以字节为单位的指令长度。

很多人都提到了英特尔手册,这是一个非常宝贵的参考,但非常重要。我建议查看这个 OSDev wiki 页面,以了解如何在更简单的级别上对指令进行编码。

对于所有实际的指令长度查找问题,我建议使用反汇编程序。

函数挂钩是一个有趣的挑战。这个 MSDN 博客很好地解释了一些困难。根据要求,最好使用操作系统的调试功能附加到进程,“中断”函数,并在单独的进程中实现您的钩子。

这篇 CodeProject 文章是 x86 指令格式的优秀高级视图(带图表!)。阅读本文后,更详细的参考将更有意义。

由于多年的向后兼容演进,x86指令格式相当复杂,有各种可选的前缀和指令相关的字段,所以计算指令长度有点棘手。如果你想要一些健壮的东西,我建议你调整现有的软件而不是自己动手。但是理解这些概念当然会很有帮助。