最近在学linux-kernel编程,刚看到改写系统函数。
文章介绍说,在2.4内核中,可以直接导出sys_call_table,这样的话,很容易在改变系统函数从而做邪恶的事。
但是从2.6开始,sys_call_table便不再可以导出了。这样就带来了问题。于是就解决吧。。。
查了很多网址,有的说可以通过/dev/kmem文件查找。但是在我的
>>>uname -a
>>> Linux localhost.localdomain 2.6.18-308.4.1.el5 #1 SMP Tue Apr 17 17:08:10 EDT 2012 i686 i686 i386 GNU/Linux
中,根本就没有该文件。
于是google之。
终于找到了,通过/boot/System.map-2.6.18-308.4.1.el5文件查找。
>>>grep sys_call_table System.map-2.6.18-308.4.1.el5
>>>c06294e0 R sys_call_table
开头的第一列就是sys_call_table在内核中的地址。
于是就有了第一版的代码。
但是。。。
insmod模块时,系统oops了。
仔细看
>>>grep sys_call_table System.map-2.6.18-308.4.1.el5
>>>c06294e0 R sys_call_table
R,是只读属性。
想办法改之,继续google之。
终于有了现有的代码。
http://stackoverflow.com/questions/2103315/linux-kernel-system-call-hooking-example
在上述url中,有一处与我的centos不一致,
那就是我的centos中没有set_memory_rw/set_memory_ro函数,
但是我从/usr/src/...include中查到了change_page_attr函数。
试试,好使。
于是有了最终版本,测试OK
=====================================================================================
代码:
test.c
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/moduleparam.h>
4 #include <linux/unistd.h>
5 #include <asm/cacheflush.h>
6
7 #include <linux/sched.h>
8 #include <asm/uaccess.h>
9
10 #ifdef KERN_2_6_24
11 #include <asm/semaphore.h>
12 #else
13 #include <asm-i386/cacheflush.h>
14 #endif
15
16 static int set_page_rw(long unsigned int _addr)
17 {
18 struct page* pg;
19 pgprot_t prot;
20 pg = virt_to_page(_addr);
21 prot.pgprot = VM_READ| VM_WRITE;
22 return change_page_attr(pg, 1, prot);
23 }
24
25 static int set_page_ro(long unsigned int _addr)
26 {
27 struct page* pg;
28 pgprot_t prot;
29 pg = virt_to_page(_addr);
30 prot.pgprot = VM_READ;
31 return change_page_attr(pg, 1, prot);
32 }
33
34 static unsigned long **sys_call_table;
35 static int uid;
36 module_param(uid, int, 0644);
37
38 asmlinkage int (*original_call)(const char*, int, int);
39
40 asmlinkage int our_sys_open(const char* filename, int flags, int mode)
41 {
42 int i = 0;
43 char ch;
44 printk("\n\n\n\n\n\n\n\n\n\n\n\n\n");
45 if(uid == current->uid){
46 printk("Opened file by %d\n", uid);
47 do{
48 get_user(ch, filename+i);
49 i++;
50 printk("%c",ch);
51 }while(ch != 0);
52 }
53 return original_call(filename, flags, mode);
54 }
55
56 int init_module()
57 {
58 int ret = 0;
59 printk(KERN_ALERT "I'm dangerous. I hope you did a ");
60 printk(KERN_ALERT "sync before you insmod'ed me.\n");
61 printk(KERN_ALERT "My counterpart, cleanup_module(), is even");
62 printk(KERN_ALERT "more dangerous. If\n");
63 printk(KERN_ALERT "you value your file system, it will ");
64 printk(KERN_ALERT "be \"sync; rmmod\" \n");
65 printk(KERN_ALERT "when you remove this module.\n");
66
67 sys_call_table = (unsigned long **)0xc06294e0;
68 ret = set_page_rw((long unsigned int)sys_call_table);
69 original_call = (int(*)(const char*, int,int))sys_call_table[__NR_open];
70 sys_call_table[__NR_open] = (long*)our_sys_open;
71
72 printk(KERN_INFO "Spying on UID:%d\n", uid);
73 ret = 0;
74 return ret;
75 }
76
77 void cleanup_module()
78 {
79 if (sys_call_table[__NR_open] != our_sys_open) {
80 printk(KERN_ALERT "Somebody else also played with the ");
81 printk(KERN_ALERT "open system call\n");
82 printk(KERN_ALERT "The system may be left in ");
83 printk(KERN_ALERT "an unstable state.\n");
84 }
85
86 sys_call_table[__NR_open] = original_call;
87 set_page_ro(sys_call_table);
88 }
=====================================================================================
Makefile:
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 18
EXTRAVERSION = -238.19.1.el5
RHEL_MAJOR = 5
RHEL_MINOR = 6
NAME=Avast! A bilge rat!
obj-m += test.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
=====================================================================================