我尝试按照http://www.elliotbradbury.com/linux-syscall-hooking-interrupt-descriptor-table/来挂钩 uname 系统调用
它在 VMWare 和 Centos 5.5 中运行良好。
我将我的代码复制到一台配备 I5-2520M CPU 的笔记本电脑上,安装了 Centos 5.5。
make
insmod ./my_module.ko
然后我得到一个糟糕的消息:无法在虚拟地址 0x_ 处处理内核分页请求__
0x__是 _sys_call_table[__NR_uname] 的地址
为什么它在 vmware 中运行良好,但在笔记本电脑上却可以运行?
以及如何解决它?
谢谢 !
以下是我的代码:
#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);