ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

使用LKM中的syscall表

2019-11-22 23:50:55  阅读:355  来源: 互联网

标签:module linux-kernel c-3 linux


我正在从Linux(3.x)的syscall表中重写SYS_READ,但是在卸载模块本身时遇到了一些麻烦.
我首先加载我的模块,该模块找到syscall表,然后启用RW,使用我自己的SYS_READ函数覆盖SYS_READ(实际上,除了调用原始SYS_READ以外,它不执行其他任何操作),然后等待片刻,然后卸载模块.在模块的unload方法上,我将原始SYS_READ函数还原回syscall表中,并将syscall表重新设置为RO.

原始的SYS_READ函数已正确还原,但是在卸载模块时得到此信息:http://pastebin.com/JyYpqYgL

我想念什么?恢复真正的SYS_READ之后,我还应该做更多的事情吗?

编辑:GitHub链接到项目:https://github.com/alexandernst/procmon

编辑:

这是我获取系统调用表地址的方式:

void **sys_call_table;

struct idt_descriptor{
    unsigned short offset_low;
    unsigned short selector;
    unsigned char zero;
    unsigned char type_flags;
    unsigned short offset_high;
} __attribute__ ((packed));


struct idtr{
    unsigned short limit;
    void *base;
} __attribute__ ((packed));


void *get_sys_call_table(void){
    struct idtr idtr;
    struct idt_descriptor idtd;
    void *system_call;
    unsigned char *ptr;
    int i;

    asm volatile("sidt %0" : "=m" (idtr));
    memcpy(&idtd, idtr.base + 0x80 * sizeof(idtd), sizeof(idtd));
    system_call = (void*)((idtd.offset_high<<16) | idtd.offset_low);
    for(ptr=system_call, i=0; i<500; i++){
        if(ptr[0] == 0xff && ptr[1] == 0x14 && ptr[2] == 0x85)
            return *((void**)(ptr+3));
        ptr++;
    }

    return NULL;
}

sys_call_table = get_sys_call_table();

这就是我设置RW / RO的方式:

unsigned long set_rw_cr0(void){
    unsigned long cr0 = 0;
    unsigned long ret;
    asm volatile("movq %%cr0, %%rax" : "=a"(cr0));
    ret = cr0;
    cr0 &= 0xfffffffffffeffff;
    asm volatile("movq %%rax, %%cr0" : : "a"(cr0));
    return ret;
}

void set_ro_cr0(unsigned long val){
    asm volatile("movq %%rax, %%cr0" : : "a"(val));
}

最后,这是我定义系统调用并更改系统调用表的方式:

asmlinkage ssize_t (*real_sys_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage ssize_t hooked_sys_read(unsigned int fd, char __user *buf, size_t count);

//set my syscall
real_sys_read = (void *)sys_call_table[__NR_read];
sys_call_table[__NR_read] = (void *)hooked_sys_read;

//restore real syscall
sys_call_table[__NR_read] = (void *)real_sys_read;

解决方法:

如果您希望卸载拦截系统调用的模块,请注意某些情况仍在系统调用处理程序中并且您的代码(模块的文本段)离开内存时的情况.这导致页面错误,因为当进程从某个内核函数(休眠)返回到您的代码时,该代码不再存在.

因此,正确的模块卸载方案必须检查挂钩系统调用中可能休眠的进程.仅当syscall挂钩中没有任何进程处于休眠状态时,才可以卸载.

UPD

请查看证明我的理论的补丁.它添加了在hooked_sys_read调用时递增和递减的原子计数器.因此,正如我想的那样,模块卸载后,仍在read_sys_read中等待一个进程.该补丁显示了printk(read_counter)并为我打印了1,这意味着某人不会减少read_counter.

http://pastebin.com/1yLBuMDY

标签:module,linux-kernel,c-3,linux
来源: https://codeday.me/bug/20191122/2063415.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有