Currently I have written a code segment using assembly on one page pageA
in linux kernel.The code is
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)
At run time, I would like to overwrite the first operad of mov
instruction via c pointer, For example, I map the page pageA
to kernel space using kmap(pageA)
.
That means, Now the first instruction movq $0, %rdx
has the address for example 0x1000
.
I would like to use C pointer to:
change the first operand from value 0
to 0x19016bc83000
for the first mov instruction
movq $0, %rdx
change the first operand from value 0x7ffff7fc6000
to 0x19016bc74000
for the second mov instruction
movq $0x7ffff7fc6000, %rsi
change the first operand from value 0x19016bc83000
to 0
for the third mov instruction
movq $0x19016bc83000, %rcx
Do you know how could i do this?
the Disassembly of this code segment by using objdump -D
shows
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
Your first instruction will be very difficult to patch, because you want to patch it with a 64-bit value but it's currently encoded to deal with a 32-bit immediate.
Let's take the instruction - mov $0x0, %rdx
and understand its encoding byte-by-byte:
0x48
- this prefix byte specifies that the instruction to follow is 64-bit sized. 0xc7
- this specifies that the instruction is a mov reg, imm32
instruction 0xc2
- this specifies the target register (encoded in the bottom 3 bits) - in this case, rdx
(which is register number 2) 0x00, 0x00, 0x00, 0x00
- encode your 32-bit immediate in little endian . When this happens, the top 32 bits of rdx
are zeroed out anyways - but this prevents you from patching the immediate directly, because you need access to all 64 bits.
The simplest solution for this is to patch your assembly instruction to be movabs $0, %rdx
- for which the assembler will output a patchable instruction.
And as for the following two movabs
instructions - they have a similar encoding, except that their second byte ( 0xbe
for the first and 0xb9
for the second) encode the destination register inside the byte : they belong to the 0xb8 + r
opcodes, where the +r
encodes the destination register: 0xbe == 0xb8 + 6
and rsi
is register number 6, 0xb9 == 0xb8 + 1
and rcx is register number 1.
Once you have three instructions that each have a 64-bit immediate to patch, the patching itself is easy. You need a char*
variable that points to the instruction you want to patch - then you want to increment it by the appropriate amount of bytes so that it points to the offset - and then you want to cast it to a uint64_t*
- and patch it appropriately.
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.