- 论坛徽章:
- 0
|
本帖最后由 warriorpaw 于 2013-10-30 20:03 编辑
新手学习怎么样hook系统调用,就参照(好吧就是照抄)
http://www.elliotbradbury.com/li ... t-descriptor-table/
写了如下的代码- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/unistd.h>
- #include <linux/utsname.h>
- #include <asm/pgtable.h>
- #include <asm/desc.h>
-
- MODULE_LICENSE("GPL");
-
- typedef struct desc_struct gate_desc;
- typedef void (*sys_call_ptr_t)(void);
- typedef asmlinkage long (*orig_uname_t)(struct new_utsname *);
-
- sys_call_ptr_t *_sys_call_table = NULL;
- pte_t *pte;
-
- orig_uname_t orig_uname = NULL;
- char *msg = "All ur base r belong to us";
-
- struct desc_ptr {
- unsigned short size;
- unsigned long address;
- } __attribute__((packed)) ;
-
- pte_t *lookup_address(unsigned long address)
- {
- pgd_t *pgd = pgd_offset_k(address);
- pud_t *pud;
- pmd_t *pmd;
- if (pgd_none(*pgd))
- return NULL;
- pud = pud_offset(pgd, address);
- if (pud_none(*pud))
- return NULL;
- pmd = pmd_offset(pud, address);
- if (pmd_none(*pmd))
- return NULL;
- if (pmd_large(*pmd))
- return (pte_t *)pmd;
- return pte_offset_kernel(pmd, address);
- }
-
- asmlinkage long hooked_uname(struct new_utsname *name) {
- orig_uname(name);
- strncpy(name->sysname, msg, 27);
- return 0;
- }
-
- static int _init_module(void ) {
- struct desc_ptr idtr;
- gate_desc *idt_table;
- gate_desc *system_call_gate;
- unsigned int _system_call_off;
- unsigned char *_system_call_ptr;
- unsigned int i;
- unsigned char *off;
-
- printk("+ Loading module\n");
- asm ("sidt %0" : "=m" (idtr));
- idt_table = (gate_desc *) idtr.address;
- system_call_gate = &idt_table[0x80];
- _system_call_off = (system_call_gate->a & 0xffff) | (system_call_gate->b & 0xffff0000);
- _system_call_ptr = (unsigned char *) _system_call_off;
-
- for(i = 0; i < 128; i++) {
- off = _system_call_ptr + i;
- if(*(off) == 0xff && *(off+1) == 0x14 && *(off+2) == 0x85) {
- _sys_call_table = *(sys_call_ptr_t **)(off+3);
- break;
- }
- }
-
- if(_sys_call_table == NULL) {
- printk("- unable to locate sys_call_table\n");
- return 0;
- }
- printk("+ found sys_call_table at %08x!\n", (unsigned int)_sys_call_table);
- orig_uname = (orig_uname_t) _sys_call_table[__NR_uname];
- pte = lookup_address((unsigned long) _sys_call_table);
- ////////////////////////////////////////////////
- set_pte_atomic(pte, pte_mkwrite(*pte));
- _sys_call_table[__NR_uname] = (sys_call_ptr_t) hooked_uname;
- set_pte_atomic(pte, pte_wrprotect(*pte));
- ////////////////////////////////////////////////
- printk("+ uname hooked!\n");
- return 0;
- }
-
- static void _cleanup_module(void) {
- if(orig_uname != NULL)
- {
- set_pte_atomic(pte, pte_mkwrite(*pte));
- _sys_call_table[__NR_uname] = (sys_call_ptr_t) orig_uname;
- set_pte_atomic(pte, pte_wrprotect(*pte));
- }
-
- printk("+ Unloading module\n");
- }
-
- module_init(_init_module);
- module_exit(_cleanup_module);
复制代码 比较关键的代码就是//注释符包括住的那几行了
理论上set_pte_atomic(pte, pte_mkwrite(*pte))修改了_sys_call_table所在页的read/write标志位了,应该可以随意替换了吧??
在装有centos 5.5的虚拟机里面测试- [root@localhost linux-syscall-hooker]# make
- make -C /lib/modules/2.6.18-194.el5/build M=/root/changesct/linux-syscall-hooker modules
- make[1]: Entering directory `/usr/src/kernels/2.6.18-194.el5-i686'
- CC [M] /root/changesct/linux-syscall-hooker/my_module.o
- Building modules, stage 2.
- MODPOST
- CC /root/changesct/linux-syscall-hooker/my_module.mod.o
- LD [M] /root/changesct/linux-syscall-hooker/my_module.ko
- make[1]: Leaving directory `/usr/src/kernels/2.6.18-194.el5-i686'
- [root@localhost linux-syscall-hooker]# insmod ./my_module.ko
- [root@localhost linux-syscall-hooker]# uname
- All ur base r belong to us
- [root@localhost linux-syscall-hooker]#
复制代码 一切正常,OK 符合预期
然后就复制my_module.c和Makefile到一台I5-2520m的笔记本上,也是centos5.5系统同一个iso装出来的,进init 3模式测试的
root登录
make 正常
insmod ./my_module.ko
这破笔记本毫不留情的直接内核oops了,报unable to handle kernel paging request at virtual address ,出错地址就是&_sys_call_table[__NR_uname],我就蛋疼了,PTE的写标志位都修改过了怎么还会报这个错,简单的想了想,也许是SMP缓存同步什么的问题?
就尝试着写了下面的代码。- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/unistd.h>
- #include <linux/utsname.h>
- #include <linux/delay.h>
- #include <asm/pgtable.h>
- #include <asm/desc.h>
-
- MODULE_LICENSE("GPL");
- typedef struct desc_struct gate_desc;
- typedef void (*sys_call_ptr_t)(void);
- typedef asmlinkage long (*orig_uname_t)(struct new_utsname *);
- static sys_call_ptr_t *_sys_call_table = NULL;
- static pte_t *pte;
- static orig_uname_t orig_uname = NULL;
- static char *msg = "All ur base r belong to us";
-
- struct desc_ptr {
- unsigned short size;
- unsigned long address;
- } __attribute__((packed)) ;
-
- #define local_flush_tlb() \
- do { \
- unsigned int tmpreg; \
- \
- __asm__ __volatile__( \
- "movl %%cr3, %0; \n" \
- "movl %0, %%cr3; # flush TLB \n" \
- : "=r" (tmpreg) \
- :: "memory"); \
- } while (0)
-
- pte_t *lookup_address(unsigned long address)
- {
- pgd_t *pgd = pgd_offset_k(address);
- pud_t *pud;
- pmd_t *pmd;
- if (pgd_none(*pgd))
- return NULL;
- pud = pud_offset(pgd, address);
- if (pud_none(*pud))
- return NULL;
- pmd = pmd_offset(pud, address);
- if (pmd_none(*pmd))
- return NULL;
- if (pmd_large(*pmd))
- return (pte_t *)pmd;
- return pte_offset_kernel(pmd, address);
- }
-
- asmlinkage long hooked_uname(struct new_utsname *name) {
- orig_uname(name);
- strncpy(name->sysname, msg, 27);
- return 0;
- }
-
- static int _init_module(void ) {
- struct desc_ptr idtr;
- gate_desc *idt_table;
- gate_desc *system_call_gate;
- unsigned int _system_call_off;
- unsigned char *_system_call_ptr;
- unsigned int i;
- unsigned char *off;
-
- printk("+ Loading module\n");
- asm ("sidt %0" : "=m" (idtr));
- idt_table = (gate_desc *) idtr.address;
- system_call_gate = &idt_table[0x80];
- _system_call_off = (system_call_gate->a & 0xffff) | (system_call_gate->b & 0xffff0000);
- _system_call_ptr = (unsigned char *) _system_call_off;
-
- for(i = 0; i < 128; i++) {
- off = _system_call_ptr + i;
- if(*(off) == 0xff && *(off+1) == 0x14 && *(off+2) == 0x85) {
- _sys_call_table = *(sys_call_ptr_t **)(off+3);
- break;
- }
- }
-
- if(_sys_call_table == NULL) {
- printk("- unable to locate sys_call_table\n");
- return 0;
- }
-
- printk("+ uname %08x!\n", (unsigned int)&_sys_call_table[__NR_uname]);
- pte = lookup_address((unsigned long) _sys_call_table);
- ////////////////////////////////////////////////
- set_pte_atomic(pte, pte_mkwrite(*pte));
- mb();
- local_flush_tlb();
- orig_uname = (orig_uname_t) _sys_call_table[__NR_uname];
- msleep(500);
- _sys_call_table[__NR_uname] = (sys_call_ptr_t) hooked_uname;
- set_pte_atomic(pte, pte_wrprotect(*pte));
- ////////////////////////////////////////////////
- printk("+ uname hooked!\n");
-
- return 0;
- }
-
- static void _cleanup_module(void) {
- if(orig_uname != NULL) {
- printk("+ Unloading module\n");
- set_pte_atomic(pte, pte_mkwrite(*pte));
- mb();
- msleep(500);
- local_flush_tlb();
- _sys_call_table[__NR_uname] = (sys_call_ptr_t) orig_uname;
- set_pte_atomic(pte, pte_wrprotect(*pte));
- }
- printk("+ Unload done!\n");
- }
-
- module_init(_init_module);
- module_exit(_cleanup_module);
复制代码 就是简单的用内核宏mb()内存屏障下,然后local_flush_tlb刷新TLB,然后再sleep一下,别问我为啥要sleep一下,我也不明白就是感觉然让内核进程换出下也许会好,虚拟机测试,没错误
复制到那台笔记本上测试,让我蛋疼无比的事情发生了,加载卸载模块有时候oops,有时候没错误,感觉跟玩我似的随机的oops!!!
写个test.sh- while [ 1 ]
- do
- insmod my_module.ko
- echo .....................................
- sleep 1
- rmmod my_module.ko
- echo .....................................
- sleep 1
- done
复制代码 让笔记本不停的加载卸载,出现了如下的现象,,,,
前面还加载卸载的很正常,偶尔的就会出现这个oops,不是每次都出现,,,
瞬间蛋疼无比,这算是什么错误啊
有时候oops信息都打印不完整cpu就宕掉了。。。如下图
又尝试过使用WBINVD指令和__asm__ __volatile__ ("": : :"memory")再做屏障,去掉sleep
还是会这样oops,还是_sys_call_table[__NR_uname]赋值的那一行随机oops掉。。。
我真蛋疼的不知所措了。。。。。。
在此求教各位高手了帮忙看看这是怎么回事的???
真机CPU和虚拟机里面有什么大的差别啊????
|
|