Skip to content
/ khook Public
forked from milabs/khook

Linux Kernel hooking engine (x86)

License

Notifications You must be signed in to change notification settings

clayne/khook

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

0

KHOOK (خوک) - Linux Kernel hooking engine.

Usage

Include Makefile.khook to your Makefile/Kbuild file:

NODNAME      ?= your-module-name
...
include      /path/to/khook/Makefile.khook
...
$(MODNAME)-y += $(KHOOK_GOALS)
ccflags-y    += $(KHOOK_CCFLAGS)
ldflags-y    += $(KHOOK_LDFLAGS) # use LDFLAGS for old kernels
...

Then, include KHOOK engine header like follows:

#include <khook/engine.h>

Use khook_init(lookup) and khook_cleanup() to initalize and de-initialize hooking engine.

Use khook_lookup_name(sym) to resolve sym address.

Use khook_write_kernel(fn, arg) to write kernel read-only data.

Examples

See the khook_demo folder for examples. Use make to build it.

Hooking of generic kernel functions

An example of hooking a kernel function with known prototype (function is defined in linux/fs.h):

#include <linux/fs.h> // has inode_permission() proto
KHOOK(inode_permission);
static int khook_inode_permission(struct inode *inode, int mask)
{
        int ret = 0;
        ret = KHOOK_ORIGIN(inode_permission, 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):

#include <linux/binfmts.h> // has no load_elf_binary() proto
KHOOK_EXT(int, load_elf_binary, struct linux_binprm *);
static int khook_load_elf_binary(struct linux_binprm *bprm)
{
        int ret = 0;
        ret = KHOOK_ORIGIN(load_elf_binary, 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 KHOOK to 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_execute is shown below (see #5 for details):


#include <scsi/scsi_device.h>
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;
}

Starting from f996ce39 it's possible to hook x86-32 kernels as correct trampoline has been implemented.

Hooking of system calls (handler functions)

An example of hooking kill(2) system call handler (see #3 for the details):

// long sys_kill(pid_t pid, int sig)
KHOOK_EXT(long, sys_kill, long, long);
static long khook_sys_kill(long pid, long sig) {
        printk("sys_kill -- %s pid %ld sig %ld\n", current->comm, pid, sig);
        return KHOOK_ORIGIN(sys_kill, pid, sig);
}

// long sys_kill(const struct pt_regs *regs) -- modern kernels
KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *);
static long khook___x64_sys_kill(const struct pt_regs *regs) {
        printk("sys_kill -- %s pid %ld sig %ld\n", current->comm, regs->di, regs->si);
        return KHOOK_ORIGIN(__x64_sys_kill, regs);
}

Features

  • x86 only
  • 2.6.33+ kernels
  • use of in-kernel length disassembler
  • ready-to-use submodule with no external deps

How it works?

The diagram below illustrates the call to function X without hooking:

CALLER
| ...
| CALL X -(1)---> X
| ...  <----.     | ...
` RET       |     ` RET -.
            `--------(2)-'

The diagram below illustrates the call to function X when KHOOK is used:

CALLER
| ...
| CALL X -(1)---> X
| ...  <----.     | JUMP -(2)----> khook_X_stub
` RET       |     | ???            | INCR use_count
            |     | ...  <----.    | CALL handler   -(3)----> khook_X
            |     | ...       |    | DECR use_count <----.    | ...
            |     ` RET -.    |    ` RET -.              |    | CALL origin -(4)----> khook_X_orig
            |            |    |           |              |    | ...  <----.           | N bytes of X
            |            |    |           |              |    ` RET -.    |           ` JMP X + N -.
            `------------|----|-------(8)-'              '-------(7)-'    |                        |
                         |    `-------------------------------------------|--------------------(5)-'
                         `-(6)--------------------------------------------'

License

This software is licensed under the GPL.

Author

Ilya V. Matveychikov

2018, 2019, 2020, 2022, 2023, 2024

About

Linux Kernel hooking engine (x86)

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C 86.0%
  • Assembly 9.7%
  • Makefile 2.2%
  • Nix 2.1%