安装内核模块,使自己的代码进入内核空间运行,可以替换linux原有的系统调用。
更改mkdir的系统调用的内核模块代码如下:(ubuntu1510 X86_64)
#include <linux/module.h>
#include <linux/kernel.h>
// 更改83号mkdir中断处理
#define callnumber 83
// grep sys_call_table /boot/System.map-`uname -r`
unsigned long* sys_call_table = (unsigned long*) 0xffffffff818001c0;
unsigned long bak_syscall = 0;
asmlinkage long mysyscall(void)
{
printk(KERN_INFO "this is skm syscall");
return 0;
}
void change_call(unsigned long address)
{
unsigned long callnumbe = callnumber;
unsigned long syscalltb = (unsigned long)sys_call_table;
__asm__ __volatile__
(
".intel_syntax noprefix\n"
"mov rax,cr0\n"
"push rax\n"
"and rax,0xfffffffffffeffff\n"
"mov cr0,rax\n"
"mov rax,%1\n"
"mov rbx,%2\n"
"lea rax,[rax+rbx*8]\n"
"mov rbx,[rax]\n"
"mov %0,rbx\n"
"mov rbx,%3\n"
"mov [rax],rbx\n"
"pop rax\n"
"mov cr0,rax\n"
:"=m"(bak_syscall)
:"m"(syscalltb),"m"(callnumbe),"m"(address)
:"rax","rbx"
);
printk(KERN_INFO "src syscall method address is 0x%lx\n",bak_syscall);
printk(KERN_INFO "our syscall method address is 0x%lx\n",address);
}
void recover_call(unsigned long address)
{
printk(KERN_INFO "will recover syscall address is 0x%lx\n",address);
unsigned long callnumbe = callnumber;
unsigned long syscalltb = (unsigned long)sys_call_table;
unsigned long result = 0;
__asm__ __volatile__
(
".intel_syntax noprefix\n"
"mov rax,cr0\n"
"push rax\n"
"and rax,0xfffffffffffeffff\n"
"mov cr0,rax\n"
"mov rax,%1\n"
"mov rbx,%2\n"
"lea rax,[rax+rbx*8]\n"
"mov %0,rax\n"
"mov rbx,%3\n"
"mov [rax],rbx\n"
"pop rax\n"
"mov cr0,rax\n"
:"=m"(result)
:"m"(syscalltb),"m"(callnumbe),"m"(address)
:"rax","rbx"
);
printk(KERN_INFO "recover syscall table address is 0x%lx\n",result);
printk(KERN_INFO "recover syscall method address is 0x%lx\n",address);
}
int insmod_init(void)
{
unsigned long para = (unsigned long)(&mysyscall);
change_call(para);
return 0;
}
void rmmod_exit(void)
{
recover_call(bak_syscall);
}
module_init(insmod_init);
module_exit(rmmod_exit);
使用下面语句建立Makefile文件
obj-m += test.o
VERSIONID = /lib/modules/$(shell uname -r)/build/
all:
make -C $(VERSIONID) M=$(PWD) modules
clean:
make -C $(VERSIONID) M=$(PWD) clean
由于代码中使用了intel汇编,编译时Makefile会报错
需要修改Makefile的对应的代码源码文件编译位置添加 -masm=intel语句
sun@sun-desktop:~/program/sun_c/kernel$ make
make -C /lib/modules/4.2.0-25-generic/build/ M=/home/sun/program/sun_c/kernel modules
make[1]: Entering directory '/usr/src/linux-headers-4.2.0-25-generic'
skm===================================
@make -f ./scripts/Makefile.build obj=/home/sun/program/sun_c/kernel
skm==================================
CC [M] /home/sun/program/sun_c/kernel/test.o
/home/sun/program/sun_c/kernel/test.c: In function ‘insmod_init’:
/home/sun/program/sun_c/kernel/test.c:79:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
unsigned long para = (unsigned long)(&mysyscall);
^
Building modules, stage 2.
MODPOST 1 modules
CC /home/sun/program/sun_c/kernel/test.mod.o
LD [M] /home/sun/program/sun_c/kernel/test.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.2.0-25-generic'
编译成功使用 sudo insmod test.ko 安装编译好的内核模块
然后使用命令dmesg查看内核日志会显示:
[17795.236888] skm change syscall mkdir
[17795.236893] CR0 value is 0x80050033
然后直接在终端执行命令新建目录 mkdir 123
内核日志会记录我们内核模块的相应日志,表示系统调用被我们截断了
[17795.236888] skm change syscall mkdir
[17795.236893] CR0 value is 0x80050033
[17869.650698] this is skm syscall
[17871.123488] this is skm syscall