ARM64 - 汇编分支到函数地址
ARM64 - assembly branch to function address
我在使用 arm64 内联汇编从 LKM 中将 64 位地址加载到寄存器时遇到问题。
我正在尝试在内核内存中设置函数挂钩。所以每次调用特定函数时,它应该分支到我的函数。
我的想法是将一个地址加载到一个寄存器中,该寄存器是在 运行 使用以下命令时获得的:
unsigned long address = &hooked_do_undefinstr;
然后写入
对应的OPCode
BLR X3
进入记忆。
我尝试使用
将地址加载到寄存器 X3(因为它是 64 位 OS)
__asm__ __volatile__ ( "MOV x3, %[var]" : [var] "=r" (address));
因为我必须在运行时获取地址,所以我不能使用LDR 命令。插入模块时出现以下错误:
root@___ :~# insmod mod_init.ko
[ 70.386938] mod_init: Unknown symbol x19 (err 0)
[ 70.391508] mod_init: Unknown symbol x3 (err 0)
使用此命令,当我打印 X3 内容时输出为零:
[ 558.948492] MOV x3 Register value 0x0
我现在的问题是,有没有办法将 64 位地址加载到寄存器中?
或者有没有更好的方法来实现我的函数钩子以跳转到我的地址?
问候并感谢您的帮助
不完全清楚你在做什么。如果你想挂钩一个函数,你不能只把你的 blr x3
放在那里并期望 x3
保存你在其他地方使用内联 asm 设置的值(除非你知道它没有被触及任何地方,但我发现不太可能)。您需要将 x3
加载代码也放入挂钩函数中,这样的事情可以工作:
ldr x3, .+8
blr x3
使用汇编器创建机器码给出:43 00 00 58 60 00 3F D6
修补时,您的代码应在末尾附加目标地址:
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;
}
另请注意,您覆盖的任何内容都应由您的钩子函数进行补偿。像往常一样,您还需要确保要修补的部分是可写的。
我用@Jester 的想法解决了这个问题。
请注意,如果您使用他的代码,请检查您的系统运行的是小端还是大端。这可以通过以下方式完成:
//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);
}
其他:这是我的工作代码:
//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;
我在使用 arm64 内联汇编从 LKM 中将 64 位地址加载到寄存器时遇到问题。
我正在尝试在内核内存中设置函数挂钩。所以每次调用特定函数时,它应该分支到我的函数。
我的想法是将一个地址加载到一个寄存器中,该寄存器是在 运行 使用以下命令时获得的:
unsigned long address = &hooked_do_undefinstr;
然后写入
对应的OPCodeBLR X3
进入记忆。
我尝试使用
将地址加载到寄存器 X3(因为它是 64 位 OS)__asm__ __volatile__ ( "MOV x3, %[var]" : [var] "=r" (address));
因为我必须在运行时获取地址,所以我不能使用LDR 命令。插入模块时出现以下错误:
root@___ :~# insmod mod_init.ko
[ 70.386938] mod_init: Unknown symbol x19 (err 0)
[ 70.391508] mod_init: Unknown symbol x3 (err 0)
使用此命令,当我打印 X3 内容时输出为零:
[ 558.948492] MOV x3 Register value 0x0
我现在的问题是,有没有办法将 64 位地址加载到寄存器中? 或者有没有更好的方法来实现我的函数钩子以跳转到我的地址?
问候并感谢您的帮助
不完全清楚你在做什么。如果你想挂钩一个函数,你不能只把你的 blr x3
放在那里并期望 x3
保存你在其他地方使用内联 asm 设置的值(除非你知道它没有被触及任何地方,但我发现不太可能)。您需要将 x3
加载代码也放入挂钩函数中,这样的事情可以工作:
ldr x3, .+8
blr x3
使用汇编器创建机器码给出:43 00 00 58 60 00 3F D6
修补时,您的代码应在末尾附加目标地址:
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;
}
另请注意,您覆盖的任何内容都应由您的钩子函数进行补偿。像往常一样,您还需要确保要修补的部分是可写的。
我用@Jester 的想法解决了这个问题。
请注意,如果您使用他的代码,请检查您的系统运行的是小端还是大端。这可以通过以下方式完成:
//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);
}
其他:这是我的工作代码:
//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;