Linux Kernel hooking engine (x86)
KHOOK (خوک) - Linux Kernel hooking engine.
Include KHOOK engine: ~~~
Add the following line to the KBuild/Makefile:
ldflags-y += -T$(src)/khook/engine.lds (use LDFLAGS for old kernels) ~~~
Use
khook_init()and
khook_cleanup()to initalize and de-initialize hooking engine.
An example of hooking a kernel function with known prototype (function is defined in
linux/fs.h): ~~~
KHOOK(inodepermission); static int khookinodepermission(struct inode *inode, int mask) { int ret = 0; ret = KHOOKORIGIN(inodepermission, inode, mask); printk("%s(%p, %08x) = %d\n", _func__, inode, mask, ret); return ret; } ~~~
An example of hooking a kernel function with custom prototype (function is not defined in
linux/binfmts.h): ~~~
KHOOKEXT(int, loadelfbinary, struct linuxbinprm *); static int khookloadelfbinary(struct linuxbinprm *bprm) { int ret = 0; ret = KHOOKORIGIN(loadelfbinary, bprm); printk("%s(%p) = %d (%s)\n", _func__, bprm, ret, bprm->filename); return ret; } ~~~
Starting from a6e7f394 it's possible to hook a function with big amount of arguments. This requires for
KHOOKto make a local copy of N (hardcoded as 8) arguments which are passed through the stack before calling the handler function.
An example of hooking 12 argument function
scsi_executeis shown below (see #5 for details):
#include KHOOK(scsi_execute); static int khook_scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, unsigned char *sense, struct scsi_sense_hdr *sshdr, int timeout, int retries, u64 flags, req_flags_t rq_flags, int *resid) { int ret = 0; ret = KHOOK_ORIGIN(scsi_execute, sdev, cmd, data_direction, buffer, bufflen, sense, sshdr, timeout, retries, flags, rq_flags, resid); printk("%s(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx) = %d\n", __func__, (long)sdev, (long)cmd, (long)data_direction, (long)buffer, (long)bufflen, (long)sense, (long)sshdr, (long)timeout, (long)retries, (long)flags, (long)rq_flags, (long)resid ,ret); return ret; }
An example of hooking
kill(2)system call handler (see #3 for the details): ~~~ // long syskill(pidt pid, int sig) KHOOKEXT(long, syskill, long, long); static long khooksyskill(long pid, long sig) { printk("syskill -- %s pid %ld sig %ld\n", current->comm, pid, sig); return KHOOKORIGIN(sys_kill, pid, sig); }
// long syskill(const struct ptregs *regs) -- modern kernels KHOOKEXT(long, _x64syskill, const struct ptregs *); static long khookx64syskill(const struct ptregs *regs) { printk("syskill -- %s pid %ld sig %ld\n", current->comm, regs->di, regs->si); return KHOOK_ORIGIN(x64syskill, regs); } ~~~
The diagram below illustrates the call to function
Xwithout hooking:
CALLER | ... | CALL X -(1)---> X | ...The diagram below illustrates the call to function
XwhenKHOOKis used:CALLER | ... | CALL X -(1)---> X | ... STUB.hook ` RET | | ??? | INCR use_count | | ... HOOK.fn | | ... | | DECR use_count STUB.orig | | | | | | ...License
This software is licensed under the GPL.
Author
2018, 2019, 2020