Reputation: 873
i've got a problem with loading an 64bit address into a register from within a LKM using arm64 inline assembly.
I'm trying to setup a function hook within the kernel memory. So every time when a specific function is called, it should branch to my function instead.
My idea was to load an address into a register, which is obtained while running using this:
unsigned long address = &hooked_do_undefinstr;
And then write the corresponding OPCode of
BLR X3
into the memory.
I tried to load the address into register X3 (because its an 64bit OS) with
__asm__ __volatile__ ( "MOV x3, %[var]" : [var] "=r" (address));
Because I have to get the address while running, i cant use the LDR command. when inserting the module i get the following error:
root@___ :~# insmod mod_init.ko
[ 70.386938] mod_init: Unknown symbol x19 (err 0)
[ 70.391508] mod_init: Unknown symbol x3 (err 0)
With this command, the output when i print the X3 content is zero:
[ 558.948492] MOV x3 Register value 0x0
My question now is, is there a way to load an 64bit address into a register? Or is there a better way to implement my function hook in order to jump to my address?
Greetings and thanks for your help
Upvotes: 1
Views: 3581
Reputation: 873
I were able to solve this problem by using @Jester's idea.
Just note, that if you're using his code, check whether or not your system runs little or big endian. This can be done by:
//Get the SCTLR_EL1 content
__asm__ __volatile__ ( "MRS %[result], SCTLR_EL1" : [result] "=r" (sctlr_el1));
//Check the 25th bit. if 1 -> big, else little
if(sctlr_el1 & (1<<25))
{
printk(KERN_INFO " Big Endian Found\n");
create_hook_big(addresse);
}else
{
printk(KERN_INFO " Little Endian found\n");
create_hook_little(addresse);
}
Else: this is my working code:
//Backup original entries
memcpy(original_blr, (void*)el1_sync,sizeof(original_blr));
//Set function hook, el1_sync is my used target
memcpy((void*)el1_sync,replace_jump_offset,sizeof(replace_jump_offset));
*(void (**)(void))(el1_sync + 8) = &hooked_do_undefinstr;
Upvotes: 0
Reputation: 58762
It's not entirely clear what you are doing. If you want to hook a function, you can't just stick your blr x3
in there and expect x3
to hold a value you set using inline asm elsewhere (unless you know it's not touched anywhere, but I find that unlikely). You need to put the x3
loading code also into the hooked function, something like this could work:
ldr x3, .+8
blr x3
Creating the machine code using an assembler gives: 43 00 00 58 60 00 3F D6
When patching, your code should append the target address at the end:
void patch(unsigned char* target)
{
unsigned char code[] = { 0x43, 0x00, 0x00, 0x58, 0x60, 0x00, 0x3F, 0xD6 };
memcpy(target, code, 8);
*(void (**)())(target + 8) = hooked_do_undefinstr;
}
Also note that whatever you have overwritten should be compensated by your hook function. As usual, you also need to make sure the section you are patching is writable.
Upvotes: 2