我试图在x86-32上的Linux内核v3.5中钩住sys-execve系统调用。我只需将sys_call_table entry address更改为hook函数
asmlinkage long (*real_execve)( const char __user*, const char __user* const __user*,
const char __user* const __user* );
...
asmlinkage long hook_execve( const char __user* filename, const char __user* const __user* argv,
const char __user* const __user* envp )
{
printk( "Called execve hook\n" );
return real_execve( filename, argv, envp );
}
...
real_execve = (void*)sys_call_table[ __NR_execve ];
sys_call_table[ __NR_execve ] = (unsigned long)hook_execve;
我确实设置了修改sys_call_表项的页面权限,并且提到的scheme对于其他sys调用(chdir、mkdir等等)很有效。但在execve钩住时,我得到了空指针解引用:
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596033] Called execve hook
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596408] BUG: unable to handle kernel NULL pointer dereference at (null)
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596486] IP: [< (null)>] (null)
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596526] *pdpt = 0000000032302001 *pde = 0000000000000000
Mar 11 14:18:08 mbz-debian kernel: [ 5590.596584] Oops: 0010 [#1] SMP
由于包含
arch/x86/kernel/entry_32.S
的PTREGSCALL3(execve)
,我使用三个参数调用sys_execve。但是,我尝试用四个参数调用它(添加struct pt_regs*
),但得到了相同的错误。也许这种执行方式完全有问题?还是我错过了什么?更新1
我发现
sys_call_table[ __NR_execve ]
实际上包含ptregs_execve
的地址(而不是sys_execve
)。在arch/x86/kernel/entry_32.S
中定义如下:#define PTREGSCALL3(name) \
ENTRY(ptregs_##name) ; \
CFI_STARTPROC; \
leal 4(%esp),%eax; \
pushl_cfi %eax; \
movl PT_EDX(%eax),%ecx; \
movl PT_ECX(%eax),%edx; \
movl PT_EBX(%eax),%eax; \
call sys_##name; \
addl $4,%esp; \
CFI_ADJUST_CFA_OFFSET -4; \
ret; \
CFI_ENDPROC; \
ENDPROC(ptregs_##name)
...
PTREGSCALL3(execve)
所以为了修改
sys_execve
我需要在不修改地址的情况下替换它的代码?我读过类似的文章,这是条路吗?更新2
实际上,我发现了以下调用序列:
do_execve->do_execve_common->search_binary_handler->security_bprm_check
,这个security_bprm_check
是lsm(linux安全模块)操作的包装器,它控制二进制文件的执行。在那之后,我阅读并跟踪here并使其生效。它解决了我的问题,因为现在我可以看到要执行的进程的名称,但我仍然不确定它的正确性。也许其他人会对这一切做些澄清。 最佳答案
在过去,在linux内核中挂接系统调用是一项简单的任务,但是在较新的内核中,程序集存根被添加到系统调用中。为了解决这个问题,我动态地修补内核的内存。
您可以在此处查看我的挂接系统的完整解决方案:
https://github.com/kfiros/execmon