如何通过Linux内核中的c指针覆盖x86`movq`指令的操作数值

目前我已经pageA在 linux 内核的一页上使用汇编编写了一个代码段。代码是

SYM_CODE_START(sr_function)
    movq $0, %rdx
    movq $0x7ffff7fc6000, %rsi 
    movq $0x19016bc83000, %rcx
    movq $9, %rdx
    movq $0, %rdx
    jmp goto_fce_func
SYM_CODE_END(sr_function)

在运行时,我想mov通过 c 指针覆盖指令的第一个操作数,例如,我pageA使用kmap(pageA).

这意味着,现在第一条指令movq $0, %rdx具有地址,例如0x1000

我想用C指针指向?

  1. 将第一个操作数从值0更改0x19016bc83000为第一个mov instruction movq $0, %rdx

  2. 将第一个操作数从 value0x7ffff7fc6000更改0x19016bc74000为第二个mov instruction movq $0x7ffff7fc6000, %rsi

  3. 将第一个操作数从 value0x19016bc83000更改0为第三个mov instruction movq $0x19016bc83000, %rcx

你知道我怎么能这样做吗?

使用objdump -D显示反汇编此代码段

0000000000001000 <sr_function>:
    1000:   48 c7 c2 00 00 00 00    mov    $0x0,%rdx
    1007:   48 be 00 60 fc f7 ff    movabs $0x7ffff7fc6000,%rsi
    100e:   7f 00 00 
    1011:   48 b9 00 30 c8 6b 01    movabs $0x19016bc83000,%rcx
    1018:   19 00 00 
    101b:   48 c7 c2 09 00 00 00    mov    $0x9,%rdx
    1022:   48 c7 c2 00 00 00 00    mov    $0x0,%rdx
    1029:   e9 de ef ff ff          jmpq   c <goto_fce_func>

回答

1000:   48 c7 c2 00 00 00 00    mov    $0x0,%rdx
1007:   48 be 00 60 fc f7 ff    movabs $0x7ffff7fc6000,%rsi
100e:   7f 00 00 
1011:   48 b9 00 30 c8 6b 01    movabs $0x19016bc83000,%rcx

您的第一条指令将很难修补,因为您想用 64 位值修补它,但它目前已编码为处理 32 位立即数。

让我们接受指令 -mov $0x0, %rdx并逐字节了解其编码:

  • 0x48 - 此前缀字节指定要遵循的指令为 64 位大小。
  • 0xc7- 这指定指令是mov reg, imm32指令
  • 0xc2- 这指定了目标寄存器(在底部 3 位中编码) - 在这种情况下,rdx(这是寄存器编号 2)
  • 0x00, 0x00, 0x00, 0x00- 以little endian编码您的 32 位立即数。

发生这种情况时,rdx无论如何都会将 的前 32 位清零 - 但这会阻止您直接修补立即数,因为您需要访问所有 64 位。

对此最简单的解决方案是将您的汇编指令修补为movabs $0, %rdx- 汇编器将为其输出可修补的指令。


至于以下两条movabs指令 - 它们具有相似的编码,除了它们的第二个字节(0xbe用于第一个和第二个字节0xb9)对字节内的目标寄存器进行编码:它们属于0xb8 + r操作码,其中+r对目标寄存器进行编码:0xbe == 0xb8 + 6rsi是寄存器编号 6,0xb9 == 0xb8 + 1而 rcx 是寄存器编号 1。


一旦你有三个指令,每个指令都有一个 64 位立即补丁,补丁本身就很容易了。您需要一个char*指向要修补的指令的变量 - 然后您想将它增加适当的字节数,以便它指向偏移量 - 然后您想将其强制转换为 a uint64_t*- 并适当地修补它。

char* ptr; // points to e.g. the last movabs instructions
ptr += 2; // skip over 0x48 and 0xb9
*((uint64_t*)ptr) = 0; // zero out the entire immediate


以上是如何通过Linux内核中的c指针覆盖x86`movq`指令的操作数值的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>