如何通过 linux 内核中的 c 指针覆盖 x86 `movq` 指令的操作数值
How to overwrite operand value of x86 `movq` instruction via c pointer in linux kernel
目前我在linuxkernel.Thekernel.The中的一页pageA
上用汇编写了一个代码段
SYM_CODE_START(sr_function)
movq [=11=], %rdx
movq [=11=]x7ffff7fc6000, %rsi
movq [=11=]x19016bc83000, %rcx
movq , %rdx
movq [=11=], %rdx
jmp goto_fce_func
SYM_CODE_END(sr_function)
在运行时,我想通过c指针覆盖mov
指令的第一个操作数,例如,我将页面pageA
映射到内核space 使用 kmap(pageA)
.
这意味着,现在第一条指令 movq [=17=], %rdx
的地址例如 0x1000
.
我想用C指针指向:
将第一个操作数从值 0
更改为第一个 mov instruction
0x19016bc83000
movq [=17=], %rdx
将第一个操作数从值 0x7ffff7fc6000
更改为第二个 0x19016bc74000
mov instruction
movq [=26=]x7ffff7fc6000, %rsi
将第一个操作数的值从 0x19016bc83000
更改为 0
第三个mov instruction
movq [=30=]x19016bc83000, %rcx
你知道我该怎么做吗?
使用objdump -D
对该代码段的反汇编显示
0000000000001000 <sr_function>:
1000: 48 c7 c2 00 00 00 00 mov [=12=]x0,%rdx
1007: 48 be 00 60 fc f7 ff movabs [=12=]x7ffff7fc6000,%rsi
100e: 7f 00 00
1011: 48 b9 00 30 c8 6b 01 movabs [=12=]x19016bc83000,%rcx
1018: 19 00 00
101b: 48 c7 c2 09 00 00 00 mov [=12=]x9,%rdx
1022: 48 c7 c2 00 00 00 00 mov [=12=]x0,%rdx
1029: e9 de ef ff ff jmpq c <goto_fce_func>
1000: 48 c7 c2 00 00 00 00 mov [=10=]x0,%rdx
1007: 48 be 00 60 fc f7 ff movabs [=10=]x7ffff7fc6000,%rsi
100e: 7f 00 00
1011: 48 b9 00 30 c8 6b 01 movabs [=10=]x19016bc83000,%rcx
你的第一条指令将很难修补,因为你想用 64 位值修补它,但它当前编码为处理 32 位立即数。
让我们接受指令 - mov [=12=]x0, %rdx
并逐字节理解它的编码:
0x48
- 这个前缀字节指定后面的指令是 64 位大小的。
0xc7
- 这指定指令是 mov reg, imm32
指令
0xc2
- 这指定了目标寄存器(在底部 3 位中编码) - 在这种情况下,rdx
(即寄存器编号 2)
0x00, 0x00, 0x00, 0x00
- 在 little endian. 中编码你的 32 位立即数
发生这种情况时,rdx
的前 32 位无论如何都会被清零 - 但这会阻止您直接修补立即数,因为您需要访问所有 64 位。
最简单的解决方案是将您的汇编指令修补为 movabs [=20=], %rdx
- 汇编器将为此输出一条可修补的指令。
对于下面的两个 movabs
指令 - 它们具有相似的编码,除了它们的第二个字节(第一个 0xbe
和第二个 0xb9
)编码目标寄存器在字节内:它们属于0xb8 + r
操作码,其中+r
编码目标寄存器:0xbe == 0xb8 + 6
和rsi
是寄存器号 6,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
目前我在linuxkernel.Thekernel.The中的一页pageA
上用汇编写了一个代码段
SYM_CODE_START(sr_function)
movq [=11=], %rdx
movq [=11=]x7ffff7fc6000, %rsi
movq [=11=]x19016bc83000, %rcx
movq , %rdx
movq [=11=], %rdx
jmp goto_fce_func
SYM_CODE_END(sr_function)
在运行时,我想通过c指针覆盖mov
指令的第一个操作数,例如,我将页面pageA
映射到内核space 使用 kmap(pageA)
.
这意味着,现在第一条指令 movq [=17=], %rdx
的地址例如 0x1000
.
我想用C指针指向:
将第一个操作数从值
0
更改为第一个mov instruction
0x19016bc83000
movq [=17=], %rdx
将第一个操作数从值
0x7ffff7fc6000
更改为第二个0x19016bc74000
mov instruction
movq [=26=]x7ffff7fc6000, %rsi
将第一个操作数的值从
0x19016bc83000
更改为0
第三个mov instruction
movq [=30=]x19016bc83000, %rcx
你知道我该怎么做吗?
使用objdump -D
对该代码段的反汇编显示
0000000000001000 <sr_function>:
1000: 48 c7 c2 00 00 00 00 mov [=12=]x0,%rdx
1007: 48 be 00 60 fc f7 ff movabs [=12=]x7ffff7fc6000,%rsi
100e: 7f 00 00
1011: 48 b9 00 30 c8 6b 01 movabs [=12=]x19016bc83000,%rcx
1018: 19 00 00
101b: 48 c7 c2 09 00 00 00 mov [=12=]x9,%rdx
1022: 48 c7 c2 00 00 00 00 mov [=12=]x0,%rdx
1029: e9 de ef ff ff jmpq c <goto_fce_func>
1000: 48 c7 c2 00 00 00 00 mov [=10=]x0,%rdx
1007: 48 be 00 60 fc f7 ff movabs [=10=]x7ffff7fc6000,%rsi
100e: 7f 00 00
1011: 48 b9 00 30 c8 6b 01 movabs [=10=]x19016bc83000,%rcx
你的第一条指令将很难修补,因为你想用 64 位值修补它,但它当前编码为处理 32 位立即数。
让我们接受指令 - mov [=12=]x0, %rdx
并逐字节理解它的编码:
0x48
- 这个前缀字节指定后面的指令是 64 位大小的。0xc7
- 这指定指令是mov reg, imm32
指令0xc2
- 这指定了目标寄存器(在底部 3 位中编码) - 在这种情况下,rdx
(即寄存器编号 2)0x00, 0x00, 0x00, 0x00
- 在 little endian. 中编码你的 32 位立即数
发生这种情况时,rdx
的前 32 位无论如何都会被清零 - 但这会阻止您直接修补立即数,因为您需要访问所有 64 位。
最简单的解决方案是将您的汇编指令修补为 movabs [=20=], %rdx
- 汇编器将为此输出一条可修补的指令。
对于下面的两个 movabs
指令 - 它们具有相似的编码,除了它们的第二个字节(第一个 0xbe
和第二个 0xb9
)编码目标寄存器在字节内:它们属于0xb8 + r
操作码,其中+r
编码目标寄存器:0xbe == 0xb8 + 6
和rsi
是寄存器号 6,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