In the previous chapter, we got the address of the system call table, and here we have something called "intercept". The so-called "interception" is the address of the system call table to our own write a function, the system call first execute our own function, after processing, and then return to the original system call execution function.
Let's stick to the code first.
Modu.c
#include <linux/init.h>#include<linux/module.h>#include<linux/moduleparam.h>#include<linux/unistd.h>#include<linux/sched.h>#include<linux/syscalls.h>#include<linux/string.h>#include<linux/fs.h>#include<linux/fdtable.h>#include<linux/uaccess.h>#include<linux/rtc.h>Module_license ("Dual BSD/GPL"); #define_debug#ifdef _DEBUG#defineKPRINTK (Fmt,args ...) printk (Kern_alert fmt,# #args)#definekprintf (Fmt,args ...) printf (fmt,# #args)#defineKperror (str) perror (str)#else#defineKprintk#definekprintf#defineKperror#endif/*Function Declaration*/Long* Get_sys_call_table (void); unsignedintCLOSE_CR (void);voidOPEN_CR (unsignedintoldval);voidStart_hook (void); AsmlinkageLong(*orig_open) (Char__user *filename,intFlagsintmode);Long* g_sys_call_table = NULL;//Save address of sys_call_tableLongG_old_sys_open =0;//save old address of Sys_openLongG_OLDCR0 =0;//Save address of CR0struct_idtr{unsigned Shortlimit; unsignedint Base;} __ATTRIBUTE__ ((packed));struct_idt_descriptor{unsigned ShortOffset_low; unsigned Shortsel; unsignedCharNone,flags; unsigned ShortOffset_high;} __ATTRIBUTE__ ((packed)); unsignedintCLOSE_CR (void) {unsignedintarr =0; unsignedintret; ASMvolatile("MOVL%%cr0,%%eax":"=a"(CR0)); RET=CR0; CR0&=0xfffeffff; ASMvolatile("MOVL%%eax,%%cr0"::"a"(CR0)); returnret;}voidOPEN_CR (unsignedintoldval) {ASMvolatile("MOVL%%eax,%%cr0"::"a"(Oldval));}/*Get The address of sys_call_table*/Long* Get_sys_call_table (void){ struct_idt_descriptor *IDT; struct_IDTR IDTR; unsignedintSys_call_off; intsys_call_table=0; unsignedChar*p; inti; ASM ("Sidt%0":"=m"(IDTR)); KPRINTK ("Address of idtr:0x%x\n", (unsignedint) &IDTR); IDT=(struct_idt_descriptor *) (IDTR.Base+8*0x80); Sys_call_off= ((unsignedint) (idt->offset_high<< -)| (unsignedint) idt->Offset_low); KPRINTK ("address of IDT 0x80:0x%x\n", Sys_call_off); P= (unsignedChar*) Sys_call_off; for(i=0;i< -; i++){ if(p[i]==0xFF&&p[i+1]==0x14&&p[i+2]==0x85) {sys_call_table=*(int*)((int) p+i+3); KPRINTK ("Address of sys_call_table:0x%x\n", sys_call_table); return(Long*) sys_call_table; } } return 0;}//My own Sys_openAsmlinkageLongMy_sys_open (Char* FileName,intFlagsintmode) {KPRINTK ("the process is \ '%s\ ' (PID is%i) \ n",current->comm,current->pid); KPRINTK ("the file is being accessed is \ "%s\" \ n", filename); returnOrig_open (Filename,flags,mode);}voidStart_hook (void) {g_sys_call_table=get_sys_call_table (); if(!g_sys_call_table) {KPRINTK ("Get sys_call_table error!\n"); return; } if(G_sys_call_table[__nr_close]! = (unsignedLong) {KPRINTK (sys_close) {"Incorrect sys_call_table address!\n"); return; } G_old_sys_open=G_sys_call_table[__nr_open]; Orig_open= (Long(*) (Char*,int,int) ) G_sys_call_table[__nr_open]; G_oldcr0=CLOSE_CR (); G_sys_call_table[__nr_open]=My_sys_open; OPEN_CR (G_OLDCR0);}intMonitor_init (void) {KPRINTK ("Monitor init\n"); Start_hook (); return 0;}voidMonitor_exit (void){ if(G_sys_call_table &&G_old_sys_open) {G_OLDCR0=CLOSE_CR (); G_sys_call_table[__nr_open]=G_old_sys_open; OPEN_CR (G_OLDCR0); } KPRINTK ("Monitor exit\n");} Module_init (Monitor_init); Module_exit (monitor_exit);
View Code
The makefile file is the same as the previous section and is not posted here. Also follow the methods in the previous section to compile the MODU.C and then load it into the kernel.
After the load succeeds, execute "DMESG" and see the System log.
If you execute "DMESG" a little later, the system log may be intercepted by the open call to print the information brush screen, because the open system call is actually called too much.
You can perform "lsmod" to see the modules contained in the current system and find the Modu we just loaded.
OK, next explain the principle.
It has been explained before that the "intercept" process is to modify the address of the calling function in the system call table, execute the function of our own implementation, and then, after we have done what we want to do in our own function, return to the original system call execution process.
This function in the code asmlinkage long My_sys_open (char * filename, int flags, int mode), is our own implementation of the call function, note that the formal parameter here is the reference system of the original open Call function prototype came, It has to be this way. The prototype of each system call is what it looks like and can be Baidu itself.
In My_sys_open (), we print which process is currently accessing (the process name and process number information), which file (the absolute path of the file) is accessed, and then jumps to the original system call function after printing.
During module initialization, the Start_hook () function is executed. In the Start_hook () function, the address of the system call table is obtained first, the original address in the system call table is saved, and the address of the My_sys_open () function is assigned to the system call table.
Note When modifying the system call table, due to a lot of things in the kernel, such as the system call table sys_call_table here is read-only, we need to modify the permissions to modify. Because the 16th bit of the control register CR0 is set, the system process is forbidden to write those files with only read-only permission, so we will clear the 16th bit of CR0 before modifying the system call Table sys_call_table, and then restore the position after the modification. such as the CLOSE_CR () function in the code, that is, the CR0 16th bit zeroing, the OPEN_CR () function is to restore CR0 16th bit.
Finally, when uninstalling the Modu module, restoring the contents of the system call table is OK.
Interception of Linux kernel monitoring module-system call