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;