为了账号安全,请及时绑定邮箱和手机立即绑定

Linux内核:系统调用挂钩示例

Linux内核:系统调用挂钩示例

森林海 2019-10-14 15:28:46
我正在尝试编写一些简单的测试代码,以作为钩住系统调用表的演示。“ sys_call_table”在2.6中不再导出,因此我只是从System.map文件中获取地址,我可以看到它是正确的(在内存中查找我找到的地址,我可以看到指向该地址的指针系统调用)。但是,当我尝试修改该表时,内核会给“ Oops”加上“无法处理虚拟地址c061e4f4上的内核页面调度请求”,然后机器会重新启动。这是运行2.6.18-164.10.1.el5的CentOS 5.4。有某种保护措施还是我只有一个bug?我知道SELinux附带了它,我已经尝试过将其设置为宽松模式,但这并没有什么不同这是我的代码:#include <linux/kernel.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/unistd.h>void **sys_call_table;asmlinkage int (*original_call) (const char*, int, int);asmlinkage int our_sys_open(const char* file, int flags, int mode){   printk("A file was opened\n");   return original_call(file, flags, mode);}int init_module(){    // sys_call_table address in System.map    sys_call_table = (void*)0xc061e4e0;    original_call = sys_call_table[__NR_open];    // Hook: Crashes here    sys_call_table[__NR_open] = our_sys_open;}void cleanup_module(){   // Restore the original call   sys_call_table[__NR_open] = original_call;}
查看完整描述

3 回答

?
冉冉说

TA贡献1877条经验 获得超1个赞

我遇到了一些问题,因为我在2.6.32内核上进行了尝试,WARNING: at arch/x86/mm/pageattr.c:877 change_page_attr_set_clr+0x343/0x530() (Not tainted)随后出现了内核OOPS,因为它们无法写入内存地址。


上述行上方的注释指出:


// People should not be passing in unaligned addresses

以下修改的代码有效:


int set_page_rw(long unsigned int _addr)

{

    return set_memory_rw(PAGE_ALIGN(_addr) - PAGE_SIZE, 1);

}


int set_page_ro(long unsigned int _addr)

{

    return set_memory_ro(PAGE_ALIGN(_addr) - PAGE_SIZE, 1);

}

请注意,在某些情况下,这实际上仍未将页面设置为读/写。在static_protections()内部调用的函数会在以下情况下set_memory_rw()删除_PAGE_RW标志:


在BIOS区域

地址在.rodata内部

设置CONFIG_DEBUG_RODATA且将内核设置为只读

我在调试后发现了这个问题,为什么在尝试修改内核函数的地址时仍然出现“无法处理内核分页请求”。最终,我可以自己找到地址的页表条目并将其手动设置为可写,从而解决了该问题。值得庆幸的是,该lookup_address()功能已在2.6.26+版本中导出。这是我为此编写的代码:


void set_addr_rw(unsigned long addr) {


    unsigned int level;

    pte_t *pte = lookup_address(addr, &level);


    if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW;


}


void set_addr_ro(unsigned long addr) {


    unsigned int level;

    pte_t *pte = lookup_address(addr, &level);


    pte->pte = pte->pte &~_PAGE_RW;


}

最后,虽然Mark的答案在技术上是正确的,但在Xen中运行时会遇到问题。如果要禁用写保护,请使用读/写cr0功能。我像这样宏化它们:


#define GPF_DISABLE write_cr0(read_cr0() & (~ 0x10000))

#define GPF_ENABLE write_cr0(read_cr0() | 0x10000)

希望这对遇到这个问题的其他人有所帮助。


查看完整回答
反对 回复 2019-10-14
?
临摹微笑

TA贡献1982条经验 获得超2个赞

请注意,以下内容也可以代替使用change_page_attr起作用,并且不能折旧:


static void disable_page_protection(void) {


    unsigned long value;

    asm volatile("mov %%cr0,%0" : "=r" (value));

    if (value & 0x00010000) {

            value &= ~0x00010000;

            asm volatile("mov %0,%%cr0": : "r" (value));

    }

}


static void enable_page_protection(void) {


    unsigned long value;

    asm volatile("mov %%cr0,%0" : "=r" (value));

    if (!(value & 0x00010000)) {

            value |= 0x00010000;

            asm volatile("mov %0,%%cr0": : "r" (value));

    }

}


查看完整回答
反对 回复 2019-10-14
  • 3 回答
  • 0 关注
  • 804 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信