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

Assembly 跟踪和反汇编与内核映像文件不匹配的Linux内核指令,assembly,gcc,linux-kernel,x86,trace,Assembly,Gcc,Linux Kernel,X86,Trace,我试图验证并理解在模拟框架中执行的指令。 模拟步骤如下所示: 二进制文件在主机x86机器上与gcc(带-fPIC标志)交叉编译 然后在名为SimNow的虚拟机x86中移动并执行二进制文件(AMD用于测试其处理器) SimNow机器生成一个已执行指令的列表,这些指令被传递到一个框架,其中包括关于每条指令的信息:虚拟地址、物理地址、大小、操作码 借助x86反汇编程序(名为distorm),该框架生成执行指令的跟踪,包括助记符和操作数。 这是跟踪输出的一个示例: 已执行指令列表包括二进制指令中包含的

我试图验证并理解在模拟框架中执行的指令。 模拟步骤如下所示:

  • 二进制文件在主机x86机器上与gcc(带-fPIC标志)交叉编译
  • 然后在名为SimNow的虚拟机x86中移动并执行二进制文件(AMD用于测试其处理器)
  • SimNow机器生成一个已执行指令的列表,这些指令被传递到一个框架,其中包括关于每条指令的信息:虚拟地址、物理地址、大小、操作码
  • 借助x86反汇编程序(名为distorm),该框架生成执行指令的跟踪,包括助记符和操作数。 这是跟踪输出的一个示例:
  • 已执行指令列表包括二进制指令中包含的指令和可能的内核指令

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

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

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

  • 我将内核头文件安装到虚拟机中,并提取linux映像以在其上执行objdump
  • 我通过比较内核指令的虚拟地址与/proc/kallsysms中包含的虚拟地址,将内核符号添加到跟踪输出中
  • 对于验证步骤,我使用与用户指令相同的方法,将linux内核映像的objdump与跟踪输出进行比较。 然而,我注意到了一些差异…主要是在发现内核符号指令时。 这是跟踪的输出:

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

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

    我想做的是理解为什么内核符号使用NOP双字而不是callq

    这是因为搬迁吗?如果是,我如何根据这些指示重建搬迁

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

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

    (部分答案/猜测可能会为您指明正确的方向。更新:Jester建议这看起来像
    ftrace
    machine:)

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

    我想我已经读过关于Linux使用代码修改来实现低开销跟踪点之类的东西,而自修改代码是Linux通常肯定会做的事情

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

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

    在本例中,这看起来像是一个函数的最顶端(在设置帧指针之前),这听起来像是一个寻找某种特殊调用的地方,可能是为了跟踪(到保留所有寄存器的特殊函数)


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

    请参阅并使用和。在最近的一次编译中,使用
    gcc-Wall-fverbose asm-O2-S foo.c
    ·编译您的
    foo.c
    ,并使用查看
    foo.S
    。我在二进制文件中使用了elf、objdump和readelf,它适用于用户指令。但是,它不适用于内核指令,它不应该包含在二进制文件中……不?这些可能是内核在加载后动态修改的内容的占位符吗?e、 g.不使用它们,或者将它们从NOP更改为callq,以实现非常低的开销跟踪?Linux确实有一些内联asm攻击,这些攻击会生成符号,用于为其他事情进行自我修改,例如,如果SMP内核在启动机器上启动,则不使用
    lock
    前缀。我想我已经读过关于Linux使用代码修改来实现低开销跟踪点之类的东西。因此,这可以解释为什么内核在磁盘上的ELF映像与内存中的执行不匹配。是的,这看起来像是一个函数的最顶端(在生成堆栈帧之前),这听起来像是一个查找跟踪调用(对保留所有寄存器的特殊函数)的地方。出于某种原因取消呼叫可以解释为什么在NOP上有呼叫目标的符号