跟踪和反汇编与内核映像文件不匹配的Linux内核指令

我正在尝试验证和理解在模拟框架中执行的指令。模拟步骤如下:

  1. 在主机 x86 机器中使用 gcc(带有 -fPIC 标志)交叉编译二进制文件
  2. 然后将二进制文件移动并在名为 SimNow 的虚拟机 x86 中执行(AMD 用于测试其处理器)
  3. SimNow 机器生成一个已执行指令列表,这些指令将传递给框架,其中包括有关每条指令的信息:虚拟地址、物理地址、大小、操作码。
  4. 由于使用 x86 反汇编器(名为 distorm),该框架生成了执行指令的跟踪,包括助记符和操作数。这是跟踪输出的示例:

执行指令列表包括包含在二进制和可能的内核指令中的指令。

我正在通过使用二进制文件上 objdump 的输出来验证跟踪的用户指令。它们是相等的,确认了执行的正确性。

这是上图中指令的 objdump 输出:

对于内核指令,我必须应用初步步骤:

  1. 我将内核头文件安装到虚拟机中,并提取了 linux 映像以在其上执行 objdump。
  2. 我通过将内核指令的虚拟地址与 /proc/kallsysms 中包含的虚拟地址进行比较,将内核符号添加到跟踪输出中。

对于验证步骤,我使用与用户指令相同的方法,将 linux 内核映像的 objdump 与跟踪输出进行比较。但是,我注意到了一些差异……主要是在发现内核符号指令时。这是跟踪的输出:

这是 linux 内核映像的对应部分:

从这些图片中可以看出,每个对应于内核符号的 callq(将 linux 映像的虚拟地址与 /proc/kallsyms 进行比较)在跟踪输出中被替换为 NOP DWORD(nopl 指令)。

我想要做的是理解为什么内核符号有一个 NOP DWORD 而不是 callq 。

是因为搬家吗?如果是,我如何重建此类指令的重定位?

注意:我使用 objdump-dr来检查 Linux 映像上的重定位,但输出没有改变。

我的内核指令验证方法错误?

回答

(部分答案/猜测可能会指向正确的方向。更新:Jester 建议这看起来像ftrace机器:https : //git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree /arch/x86/kernel/ftrace.c?h=v5.10 )

我怀疑这些调用在加载后被 NOPed,可能是在相关的跟踪点或任何未启用的情况下。出于某种原因取消调用将解释为什么有与 NOP 关联的调用目标或符号重定位元数据。

我想我已经阅读了关于 Linux 使用代码修改来实现低开销跟踪点或其他东西的信息,并且自修改代码是 Linux 肯定会做的事情。

Linux 使用自修改代码,在启动时修改一次,或在非常罕见的配置更改时修改,以减少每次执行与分支的开销,用于一些不同的事情。(例如,在 UP 机器上启动 SMP 内核将排除lock原子 RMW 中的前缀,这些前缀只需要是 SMP 安全的,而不是硬件设备。)内联 asm 宏定义符号和自定义部分,以便内核具有必要的元数据。最近还有一些关于修改rel32调用目标而不是使用间接分支的内容,以避免在这些站点上进行任何 Spectre 缓解,但这不是这里发生的事情。

因此,一般而言,当您尝试针对内核映像文件验证执行时,您应该会看到一些不匹配的情况,这可能就是其中之一

在这种情况下,这看起来像是一个函数的最顶部(在设置帧指针之前),这听起来很可能是找到某种特殊调用的地方,也许是为了跟踪(到一个保留所有寄存器的特殊函数)。

gcc 生成的代码永远不会在 AFAIKcall之前执行push %rbp/ mov %rsp, %rbp。一方面,这会违反 16 字节堆栈对齐 ABI 要求。(虽然也许内核使用-mpreferred-stack-boundary=3而不是 4?两次推送后,还有另一个更正常的调用,如果这是一个正常的函数,它也会有一个未对齐的 RSP。)无论如何,这是另一个迹象表明有一些自定义的内联 asm 黑客或正在发生的事情.


以上是跟踪和反汇编与内核映像文件不匹配的Linux内核指令的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>