github:https://github.com/WeiJiLab/kernel-hook-framework
一、项目介绍
Usually we want to hack a kernel function,
-
to insert customized code before or after a certain kernel function been called, or
-
to totally replace a function with new one.
How can we manage that? Well it’s time to bring inline hook technique to kernel space. By replacing the first few instructions of a specific function to conditionless jump, and store the original instructions to a trampoline function, we can customizing the functions calling, and do whatever we want do in the hook function. Isn’t is exciting?
二、代码结构
-
src/
The hook framework itself. In normal cases, you needn’t modify its code, unless you are trying to fix bug, because we want to keep it as simple and independent to any customization. After compile, you will get hookFrame.ko. -
sample/
The customized hook/replacement functions. Write your code here, and you can take hook_vfs_read.c, replace_vfs_open.c as reference when writing your own function. Also in module.c, you can get a general view of how to register your function to hook framework. After compile, hookFrameTest.ko will be generated.
root@curtis-Aspire-E5-471G:/home/curtis/code/kernel-hook-framework# tree ./
./
├── make_hook_frame.sh
├── readme.md
├── sample
│ ├── aftvermagic.sh
│ ├── hook_fuse_open.c
│ ├── hook_vfs_read.c
│ ├── include
│ │ ├── common_data.h
│ │ ├── hijack_arm64.h
│ │ ├── hijack_arm.h
│ │ ├── hijack_x86_64.h
│ │ ├── hijack_x86.h
│ │ └── hook_framework.h
│ ├── Makefile
│ ├── module.c
│ ├── prevermagic.sh
│ └── replace_vfs_open.c
└── src
├── aftvermagic.sh
├── arch
│ ├── arm
│ │ ├── hijack_arm.c
│ │ └── hijack_arm.h
│ ├── arm64
│ │ ├── hijack_arm64.c
│ │ └── hijack_arm64.h
│ ├── x86
│ │ ├── common.c -> ../x86_64/common.c
│ │ ├── distorm -> ../x86_64/distorm
│ │ ├── hijack_x86.c
│ │ └── hijack_x86.h
│ └── x86_64
│ ├── common.c
│ ├── distorm
│ │ ├── config.h
│ │ ├── decoder.c
│ │ ├── decoder.h
│ │ ├── distorm.c
│ │ ├── distorm.h
│ │ ├── instructions.c
│ │ ├── instructions.h
│ │ ├── insts.c
│ │ ├── insts.h
│ │ ├── mnemonics.c
│ │ ├── mnemonics.h
│ │ ├── operands.c
│ │ ├── operands.h
│ │ ├── prefix.c
│ │ ├── prefix.h
│ │ ├── textdefs.c
│ │ ├── textdefs.h
│ │ ├── wstring.h
│ │ └── x86defs.h
│ ├── hijack_x86_64.c
│ └── hijack_x86_64.h
├── framework
│ ├── hijack_operation.c
│ ├── module.c
│ ├── proc_interface.c
│ ├── stack_safety_check.c
│ ├── symbol_resolver.c
│ ├── write_map_page.c
│ └── write_page.c
├── include
│ └── common_data.h
├── Makefile
└── prevermagic.sh
三、编译测试
Sometimes you will find the vermagic of hookFrame.ko and hookFrameTest.ko different from your target kernel. You can pass the target kernel’s vermagic string to make:
- 测试环境
root@curtis-Aspire-E5-471G:/home/curtis/code/kernel-hook-framework# uname -a
Linux curtis-Aspire-E5-471G 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
root@curtis-Aspire-E5-471G:/home/curtis/code/kernel-hook-framework# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.3 LTS
Release: 20.04
Codename: focal
- 测试代码编译
# install bbe to modify vermagic string within .ko
# bbe用来修改内核模块的vermagic字符串
root@curtis-Aspire-E5-471G:/home/curtis/code/kernel-hook-framework# apt-get install bbe
# 查看编译环境gcc版本
root@curtis-Aspire-E5-471G:~# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
.....
# 查看目标环境内核驱动vermagic
root@curtis-Aspire-E5-471G:/home/kmodule/kprobe_example# modinfo probe_example.ko
filename: /home/curtis/write_code/kmodule/kprobe_example/probe_example.ko
license: GPL
srcversion: C2BF47FCD744ABC53E80FE1
depends:
retpoline: Y
name: probe_example
vermagic: 5.15.0-52-generic SMP mod_unload modversions
parm: symbol:string
# 编译内核驱动,发现如果带vermagic将会错误修改/generated/utsrelease.h
root@curtis-Aspire-E5-471G:/home/kernel-hook-framework/sample# make x86_64 KDIR=/usr/lib/modules/5.15.0-52-generic/build CROSS_COMPILE=x86_64-linux-gnu- vermagic="5.15.0-52-generic SMP mod_unload modversions"
# 编译示例驱动
root@curtis-Aspire-E5-471G:/home/kernel-hook-framework/sample# make x86_64 KDIR=/usr/lib/modules/5.15.0-52-generic/build CROSS_COMPILE=x86_64-linux-gnu-
make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- KBUILD_EXTRA_SYMBOLS=/home/curtis/code/kernel-hook-framework/sample/../src/Module.symvers EXTRA_CFLAGS="-D_ARCH_X86_64_ -I/home/curtis/code/kernel-hook-framework/sample/include -fno-pic" -C /usr/lib/modules/5.15.0-52-generic/build M=/home/curtis/code/kernel-hook-framework/sample modules
make[1]: Entering directory '/usr/src/linux-headers-5.15.0-52-generic'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
You are using: x86_64-linux-gnu-gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
WARNING: Symbol version dump "/home/curtis/code/kernel-hook-framework/sample/../src/Module.symvers" is missing.
Modules may not have dependencies or modversions.
You may get many unresolved symbol warnings.
CC [M] /home/curtis/code/kernel-hook-framework/sample/hookFrameTest.mod.o
LD [M] /home/curtis/code/kernel-hook-framework/sample/hookFrameTest.ko
BTF [M] /home/curtis/code/kernel-hook-framework/sample/hookFrameTest.ko
Skipping BTF generation for /home/curtis/code/kernel-hook-framework/sample/hookFrameTest.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.15.0-52-generic'
# 编译hook framework
root@curtis-Aspire-E5-471G:/home/curtis/code/kernel-hook-framework/src# make x86_64 KDIR=/usr/lib/modules/5.15.0-52-generic/build CROSS_COMPILE=x86_64-linux-gnu-
make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- EXTRA_CFLAGS="-D_ARCH_X86_64_ -I/home/curtis/code/kernel-hook-framework/src -I/home/curtis/code/kernel-hook-framework/src/arch/x86_64 -fno-pic -fno-stack-protector" -C /usr/lib/modules/5.15.0-52-generic/build M=/home/curtis/code/kernel-hook-framework/src modules
make[1]: Entering directory '/usr/src/linux-headers-5.15.0-52-generic'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
You are using: x86_64-linux-gnu-gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
......
LD [M] /home/curtis/code/kernel-hook-framework/src/hookFrame.o
MODPOST /home/curtis/code/kernel-hook-framework/src/Module.symvers
CC [M] /home/curtis/code/kernel-hook-framework/src/hookFrame.mod.o
LD [M] /home/curtis/code/kernel-hook-framework/src/hookFrame.ko
BTF [M] /home/curtis/code/kernel-hook-framework/src/hookFrame.ko
Skipping BTF generation for /home/curtis/code/kernel-hook-framework/src/hookFrame.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.15.0-52-generic'
尝试安装驱动试试看,有没有Hook成功。
# 安装hook框架
root@curtis-Aspire-E5-471G:/home/kernel-hook-framework/src# insmod hookFrame.ko
[23927.370331] Symbol save_stack_trace_tsk not found!
[23927.370348] Your kernel should be "CONFIG_STACKTRACE && !CONFIG_ARCH_STACKWALK", skip stack safety check and use as your risk!!!
[23927.373527] load hook framework success!
# 安装测试驱动,从结果来看已经Hook成功了
root@curtis-Aspire-E5-471G:/home/kernel-hook-framework/sample# insmod hookFrameTest.ko
[24036.218182] reading /usr/lib/modules/5.15.0-52-generic/modules.builtin.bin
[24036.218200] in replaced vfs_open
[24036.218206] reading /sys/module/hookFrameTest/initstate
[24036.218215] reading /sys/module/hookFrameTest/initstate
[24036.218224] in replaced vfs_open
[24036.218239] in replaced vfs_open
[24036.218244] reading /sys/module/hookFrameTest/refcnt
[24036.218250] reading /sys/module/hookFrameTest/refcnt
[24036.218537] all hijacked target disabled and removed
[24036.218542] unload hook framework test!
Hook成功了并打印了打开文件的绝对路径。
四、构建自己的Hook函数流程
- 获取原函数地址
- 调用hijack_target_prepare和hijack_target_enable使能hook函数。