对于Linux上的Mach内核API仿真,我需要在刚刚创建或终止任务时调用我的内核模块。
在我的内核模块中,最好通过Linux安全模块来完成,但几年前,他们通过取消所需的符号来防止外部模块充当LSM。
我能找到的另一种方法是让我的模块像rootkit一样。找到系统调用表并将其挂钩。
修补内核是不可能的。我需要轻松安装我的应用程序。还有其他办法吗?
答案 0 :(得分:3)
您可以使用Kprobes,它可以动态挂钩内核中的代码。您需要在创建和销毁过程中找到正确的功能,从而为您提供所需的信息。例如,对于创建的任务,fork.c中的do_fork()将是一个很好的起点。对于销毁的任务,请执行do_exit。您可能希望编写一个retprobe,它是一种kprobe,它还可以在函数执行结束时为您提供控制权,然后再返回。在函数返回之前需要控制的原因是通过检查返回值来检查它是否成功创建了进程。如果出现错误,则函数将返回负值,或者在某些情况下可能返回0。
你可以通过创建一个kretprobe结构来实现这个目的:
static struct kretprobe do_fork_probe = {
.entry_handler = (kprobe_opcode_t *) my_do_fork_entry,
.handler = (kprobe_opcode_t *) my_do_fork_ret,
.maxactive = 20,
.data_size = sizeof(struct do_fork_ctx)
};
my_do_fork_entry在控件进入钩子函数时执行,my_do_fork_ret在返回之前执行。你可以按如下方式挂钩:
do_fork_probe.kp.addr =
(kprobe_opcode_t *) kallsyms_lookup_name("do_fork");
if ((ret = register_kretprobe(&do_fork_probe)) <0) {
// handle error
}
在钩子的实现中,获取参数和返回值有点笨拙。你通过保存的寄存器pt_regs数据结构得到这些。让我们看一下返回钩子,在x86上你可以通过regs-&gt; ax获得返回值。
static int my_do_fork_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
{
struct do_fork_ctx *ctx = (struct do_fork_ctx *) ri->data;
int ret = regs->ax; // This is on x86
if (ret > 0) {
// It's not an error, probably a valid process
}
}
在入口点,您可以通过寄存器访问参数。例如在x86上,regs-&gt; di是第一个参数,regs-&gt; si是第二个参数等。您可以谷歌获取完整列表。请注意,您不应该依赖这些寄存器作为返回挂钩中的参数,因为寄存器可能已被覆盖以用于其他计算。
你肯定必须跳出许多箍才能使这个工作,但希望这个说明应该让你朝着正确的方向前进。