gpt4 book ai didi

c - 使用 LKM 的系统调用表

转载 作者:太空狗 更新时间:2023-10-29 11:09:37 32 4
gpt4 key购买 nike

我正在从 Linux (3.x) 的系统调用表中覆盖 SYS_READ,但在卸载模块本身时遇到了一些麻烦。我首先加载找到系统调用表的模块,然后启用 RW,用我自己的 SYS_READ 函数覆盖 SYS_READ(实际上并没有除了调用原始的 SYS_READ) 之外做任何其他事情,然后我等待片刻,然后卸载模块。在我的模块的卸载方法中,我将原始的 SYS_READ 函数恢复到系统调用表中,并将系统调用表设置回 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;

最佳答案

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

因此,正确的模块卸载方案必须检查可能在 Hook 系统调用中休眠的进程。仅当系统调用 Hook 中没有休眠进程时才可能卸载。

UPD

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

http://pastebin.com/1yLBuMDY

关于c - 使用 LKM 的系统调用表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18220980/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com