繁体   English   中英

如何通过linux中的c指针覆盖x86`movq`指令的操作数值kernel

[英]How to overwrite operand value of x86 `movq` instruction via c pointer in linux kernel

目前我在linux kernel的一页pageA上用汇编写了一个代码段。代码是

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)

在运行时,我想通过 c 指针覆盖mov指令的第一个操作数,例如,我使用kmap(pageA) map 页面pageA到 kernel 空间。

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

我想用 C 指针指向:

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

  2. 将第二个mov instruction的第一个操作数从值0x7ffff7fc60000x19016bc74000 movq $0x7ffff7fc6000, %rsi

  3. 将第三条mov instruction的第一个操作数从值0x19016bc830000 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 - 汇编程序将为 output 修补指令。


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


一旦你有了三个指令,每个指令都有一个 64 位立即数来修补,修补本身就很容易了。 您需要一个指向要修补的指令的char*变量 - 然后您希望将其递增适当的字节数以使其指向偏移量 - 然后您希望将其转换为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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM