+ -
当前位置:首页 → 问答吧 → LINUX 2.6.X 下系统调用替换和文件保护的简单实现

LINUX 2.6.X 下系统调用替换和文件保护的简单实现

时间:2005-04-18

来源:互联网

一个LINUX下系统调用替换和文件保护的简单实现.(i386)

程序见附件(http://www.linuxforum.net/forum/files/551958-fileprotector.zip)
(http://www.linuxforum.net/forum/showflat.php?Cat=&Board=linuxK&Number=551958&page=1&view=collapsed&sb=5&o=7&fpart=)

* 不需要手工设置sys_call_table的地址(2.6.X内核里,这个地址不再输出)
* 不需要/dev/kmem文件支持
* 提供系统调用替换(挂钩)服务

简单的流程描述:
加载:
1。找到sys_call_table
2。替换sys_read系统调用的入口
3。输入要保护的文件列表
4。获得受保护文件的inode,生成保护文件列表
5。当文件被试图打开时(sys_read系统调用被执行),检查目标文件的inode是否在被保护文件列表里。如果在,返回错误;否则调用原来的sys_read系统调用,并返回。

卸载:
1。关闭文件保护
2。恢复系统调用
3。清空保护文件列表。

使用方法:
1。开包,编译(不用多讲了,make一下)
2。insmod sc.ko; insmod fp.ko
3。ls "somefile" >; /proc/fileprotector/filelist
4。vi somefile,看一下,是不是已经打不开了。
5。rmmod fp; rmmod sc


只用于学习,测试. 欢迎交流.

GPL的,勿用多说.

没时间写DOC,以后再说吧  

作者: 野枫   发布时间: 2005-04-18

系统调用的替换和截获 2005.04.12

作者:
野枫

鸣谢:
<<Linux on-the-fly kernel patching without LKM>;>;
sd <[email protected]>;, devik <[email protected]>;
December 12th 2001

此文描述了用sidt指令获得idt_table地址的方法,受此启发,我实现了用内核影像中
idt_descr获得idt_table的方法。

说明:
本文描述了LINUX 2.6.X的系统调用替换和截获的方法,希望它有助于我们对LINUX系统调用
机制的理解,或应用于某些有益的尝试和研究。
本文尚未完善(包括代码),也许还有错误。
作者不保证本文(包括代码)提到的方法或技术可以应用于您的实际环境。
作者不承担任何因使用或误用本文(包括代码)导致的损失和法律纠纷。

警告:
修改系统内核文件或其运行时影像是极其危险的事情,三思而行。

术语:
IDT(中断描述表):i386构架系统中,存放中断、异常的处理信息的结构
系统调用表:linux系统存放系统调用处理信息的结构

概念:
linux系统(i386)中的系统调用是通过用户软件调用中断int0x80激发的,
int0x80被执行后,内核获得cpu控制权,交由system_call程序处理.
system_call的主要工作是:保存寄存器,判断系统调用编号合法性等工作,
然后根据sys_call_table(系统调用表)和系统调用编号,找到系统调用处理程序,
执行相应系统调用.

数据结构及关联图:

idt_descr (中断描述表的 *描述* ,用于存放中断向量表的信息)
 |
 |
 |-- idt_table[256] (中断描述表)
 |-- 中断处理程序0
 |-- 中断处理程序1
 |-- 中断处理程序2
 |-- ...
 |-- 中断处理程序128(0x80)
    ...|
       |
       |-- system_call (系统调用处理程序)
       |
       |
   <是否为合法的系统调用>- No - 返回错误
       |
      Yes
       |
       |-- 调用 sys_call_table[系统调用编号] (存放系统调用处理信息的结构)

分析:

文件读写,目录创建、修改,大多是用户程序通过调用系统调用完成的,因此,控制了系统
调用,就能实现对用户文件操作有选择性的服务。

根据上图,不难看出,最实用的办法是:
找到sys_call_table中相应系统调用对应项,保存该项信息,用新的系统服务处理函数替换原来
的函数。重要的是,新函数内部逻辑中,必须有个逻辑分支调用原来的系统服务函数,这样系统
调用逻辑便完整了。(当然,如果有能力也有必要,可以提供一个完整的系统调用取代原来的,
再此不做讨论)
值得注意的是,2.4.18以后的内核sys_call_table已经不再输出,如何获得这个关键结构,请看
实现部分。

除了上面截获系统调用的方法,还有若干其他方法,比如:
1. sys_call_table整体移植,也就是在system_call中设置陷阱,使system_call调用我们的
sys_call_table。
2. 在系统调用入口(sys_call_table[]中指向的系统调用函数)插入代码,执行特定程序后再
返回继续执行系统调用。
等,复杂性和隐蔽性越来越强,有兴趣的朋友可以深入研究,欢迎讨论交流。

实现:
本程序提供了一个模块sc.ko,它提供替换系统调用的服务,当然,卸载前一定要恢复原状的。
因为重点不在系统调用挂钩,所以采用了最简便的实现方法,替换sys_call_table中的系统调用
服务程序入口地址。

2.6.X内核不输出sys_call_table这个关键结构的地址了,没有这个结构地址,系统调用挂钩就
无处挂了。
再看一下上面的图,没有sys_call_table,也许可以从他的上一层,甚至更高层入手,顺藤摸瓜。
对了,就是这么搞。idt_table里第128项是system_call信息,system_call里有sys_call_table
地址。也就是说,只要我们知道idt_table在哪里,就有可能找到sys_call_table.
怎么做?
system_call函数里一定会有一个调用指令类似于:call *sys_call_table(0, %eax, 4),找到这条
指令就可以知道sys_call_table的地址了。这个指令的操作码是:0x8514ff。
sidt 这个汇编指令帮我们搞定了idt_table在哪里这个充分条件,呵呵查手册吧。
我这里要说的是另一种思路(绕远的方法),内核不输出idt_table,我们也不用sidt指令,能不
能解决这个棘手问题呢?
再看上图,顶端数据结构是idt_descr,它也不输出啊。在arch/i386/kernel/entry.S里,找到
这个符号,看看上下文,有些东西眼熟。对了,cpu_gdt_table这个符号是被内核输出的,查看一下
arch/i386/kernel/i386_ksyms.c。这跟idt_table和idt_descr有关系么?有,head.S里的这一部分
是非初始化数据段,不是代码,所以各个符号间的相对偏移量是可预见的。

OK,点到为止,下面是伪代码:



asmlinkage ssize_t (*orig_read)(unsigned int,char*,size_t);
asmlinkage ssize_t new_read(unsigned int fd,char* buf,size_t size){
do_some_thing_on_this_fd(fd);
return orig_read(fd,buf,size);
}

static int __init init_our_module(void){
unsigned int idt_descr;
unsigned int idt_table;
unsigned int system_call;
unsigned int sys_call_table;
idt_descr=cpu_gdt_table - idt_descr_to_cpu_gdt_table_offset;
idt_table=get_idt_addr(idt_descr);
// 这个过程有点麻烦,请看察看相关资料关于idt_table项定义
system_call=get_system_call_addr(idt_table,0x80);
// 前面提到了,检索操作码
sys_call_table=get_sys_call_table_addr(system_call);

replace_sys_call(__NR_read,(syscall_handler_t *)&new_read,(syscall_handler_t **)&orig_read);

return 0;
}

作者: 野枫   发布时间: 2005-04-18

嗯,在linuxforum见过了,正在研究

作者: albcamus   发布时间: 2005-04-18

呵呵,这个是利用加载module的漏洞,然后替换了sys函数,hacker必精通

作者: macro-linux   发布时间: 2005-04-18

强悍,居然在sys_call_table没有被export的情况下,仍然替换了正规的系统调用!!

我昨天看kernel module programming guide,当时以为2.6.X中只能打补丁导出sys_call_table才可能进行偷窃系统调用行为,想不到啊

赞一个

作者: albcamus   发布时间: 2005-04-25

测试一下了,换了write好像不行了.没什么反应

作者: ouyangyufu   发布时间: 2010-09-07

热门下载

更多