内核模块代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kprobes.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
MODULE_LICENSE("GPL");
static void my_write_cr0(long value) {
__asm__ volatile("mov %0, %%cr0" :: "r"(value) : "memory");
}
#define disable_write_protection() my_write_cr0(read_cr0() & (~0x10000))
#define enable_write_protection() my_write_cr0(read_cr0() | 0x10000)
unsigned long* sys_call_table_address;
asmlinkage int (*original_chmod)(const char __user*, umode_t);
static struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name"
};
typedef unsigned long (*kallsyms_lookup_name_t)(const char* name);
unsigned long* get_sys_call_table_address(void) {
kallsyms_lookup_name_t kallsyms_lookup_name;
int ret = register_kprobe(&kp);
if (ret < 0) {
printk(KERN_ERR "InterceptChmod: register_kprobe failed, returned %d\n", ret);
return NULL;
}
kallsyms_lookup_name = (kallsyms_lookup_name_t)kp.addr;
unregister_kprobe(&kp);
if (!kallsyms_lookup_name) {
printk(KERN_ERR "InterceptChmod: kallsyms_lookup_name not found\n");
return NULL;
}
unsigned long* address = (unsigned long*)kallsyms_lookup_name("sys_call_table");
if (!address) {
printk(KERN_ERR "InterceptChmod: sys_call_table not found\n");
}
else {
printk(KERN_INFO "InterceptChmod: sys_call_table address: %p\n", address);
}
return address;
}
asmlinkage int custom_chmod(const char __user* filename, umode_t mode) {
char fname[256];
// Copy the filename from user space to kernel space
if (strncpy_from_user(fname, filename, sizeof(fname)) > 0) {
fname[sizeof(fname) - 1] = '\0'; // Ensure null termination
printk(KERN_INFO "InterceptChmod: chmod intercepted for file: %s, mode: %o\n", fname, mode);
}
else {
printk(KERN_INFO "InterceptChmod: chmod intercepted, failed to get filename, mode: %o\n", mode);
}
// Call the original chmod system call
return original_chmod(filename, mode);
}
static int __init intercept_chmod_init(void) {
printk(KERN_INFO "InterceptChmod: Loading module\n");
sys_call_table_address = get_sys_call_table_address();
if (!sys_call_table_address) {
printk(KERN_ERR "InterceptChmod: Failed to get sys_call_table_address\n");
return -EFAULT;
}
printk(KERN_INFO "InterceptChmod: sys_call_table address: %p\n", sys_call_table_address);
original_chmod = (void*)sys_call_table_address[__NR_chmod];
printk(KERN_INFO "InterceptChmod: Original chmod address: %p\n", original_chmod);
disable_write_protection();
sys_call_table_address[__NR_chmod] = (unsigned long)custom_chmod;
enable_write_protection();
printk(KERN_INFO "InterceptChmod: Hooked chmod system call, new address: %p\n", (void*)sys_call_table_address[__NR_chmod]);
return 0;
}
static void __exit intercept_chmod_exit(void) {
if (sys_call_table_address) {
disable_write_protection();
sys_call_table_address[__NR_chmod] = (unsigned long)original_chmod;
enable_write_protection();
printk(KERN_INFO "InterceptChmod: Restored original chmod system call, address: %p\n", (void*)sys_call_table_address[__NR_chmod]);
}
printk(KERN_INFO "InterceptChmod: Module unloaded\n");
}
module_init(intercept_chmod_init);
module_exit(intercept_chmod_exit);
我使用 Linux 6.8.11-amd64、OracleVM VirtualBox 和 X86_64 处理器。
我使用以下方式加载模块:
sudo insmod lkm_chmod.ko
然后我测试他的使用命令
sudo chmod 755 testfile
他没有记录这个。
我的日志看起来像这样。
[ 9245.540511] InterceptChmod: Loading module
[ 9245.561100] InterceptChmod: sys_call_table address: 00000000d760dd16
[ 9245.561105] InterceptChmod: sys_call_table address: 00000000d760dd16
[ 9245.561106] InterceptChmod: Original chmod address: 0000000014a7fad1
[ 9245.561110] InterceptChmod: Hooked chmod system call, new address: 00000000ce1988d5
[ 9330.452750] InterceptChmod: Restored original chmod system call, address: 0000000014a7fad1
[ 9330.452766] InterceptChmod: Module unloaded
我不明白为什么他不工作,我的日志中没有错误。我尝试将 __NR_chmod 更改为 __NR_open 或 __NR_close,但他不起作用。 我尝试使用 ChatGPT,他只说废话,只是重复我的代码。
好吧,我在这个答案中找到了解决方案answer。感谢 Ian Abbott 指出在 6.9 及更早版本中
sys_call_table
不再有效。
现在我修复了代码,他开始使用kprobes工作。
#include <linux/kprobes.h>
#include <linux/ptrace.h>
static int sys_read_kprobe_pre_handler(struct kprobe* p, struct pt_regs* regs)
{
printk(KERN_NOTICE "ROOTKIT: read(%ld, 0x%lx, 0x%lx)\n", regs->di, regs->si, regs->dx);
return 0;
}
struct kprobe syscall_kprobe = {
.symbol_name = "__x64_sys_read",
.pre_handler = sys_read_kprobe_pre_handler,
};
static int __init startup(void)
{
int err;
err = register_kprobe(&syscall_kprobe);
if (err) {
pr_err("register_kprobe() failed: %d\n", err);
return err;
}
printk(KERN_NOTICE "ROOTKIT: Starting of due");
return 0;
}
static void __exit shutdown(void)
{
unregister_kprobe(&syscall_kprobe);
printk(KERN_NOTICE "ROOTKIT: Ending");
}
module_init(startup);
module_exit(shutdown);
MODULE_LICENSE("GPL");