分类: 网络与安全
2008-10-11 17:19:20
三、将代码导入内核的方法
所有应用程序都是运行在用户模式下的,而操作系统是运行在内核模式下的,所以应用程序根本没有机会来修改内核程序。要想颠覆内核,前提是设法让我们的代码也运行在内核模式下,即将我们的代码导入内核。
设想一下当我们的代码通过驱动程序进入内核后的情形:我们的代码一旦在内核运行,就能访问内核的所有特权内存空间和系统进程——有了这样的内核级访问特权,我们就能任意修改系统中的任何代码和数据了!
将代码导入内核的方法很多,但我们要介绍的是利用设备驱动程序将代码导入内核的方式。内核驱动程序有多种叫法,有时候又称为内核驱动程序,或者可加载模块。我们之所以利用设备驱动程序将代码导入到内核,主要考虑到两点:
1.简单性。能够让我们的代码运行在内核模式之的方法有多种,例如把我们的代码做成设备驱动程序、设法修改正在内存运行的内核、覆盖硬盘中的内核映像等等。其中,利用设备驱动程序是最为简单的一种。
2.
适用性。现在,绝大多数的操作系统都允许第三方的硬件厂商加载为其硬件产品制作的内核扩展,从而使得操作系统能够支持它们的硬件产品。这的确是一个双赢之
举,只有这样,操作系统开发商才能不断巩固和扩大其用户群。因此,各个操作系统开发商不仅提供该系统下的开发设备驱动程序的详尽帮助文档,而且还提供了相
应的开发工具包。
虽然我们已经找到将我们的代码导入到内核模式的路径,但还有一个问题需要回答:除了与硬件打交道的代码外,其它代码是否也能写进设备驱动程序?答案是肯定的。尽管这里的“设备”一词容易误导我们,实际上任何代码都可以写成设备驱动程序。
迄
今为止,我们已经回答了利用设备驱动程序来打造内核级别的Rootkit可行性问题,也就是说,内核级Rootkit大门已经打开了一扇,为了打开另一
扇,我们要解决的是“how to”的问题。并且,我们第一个必须解决的“how to”问题就是如何编写Windows设备驱动程序。
四、Windows设备驱动程序
下
面我们介绍如何在Windows
XP平台上开发一个简单的设备驱动程序。在此过程中,我们要用到设备驱动程序开发包DDK。需要注意的是,微软为不同的Windows版本提供了不同的
DDK。就目前来说,我们可以使用Windows 2003 DDK,因为该版本能够支持Windows 2000、Windows
XP和Windows 2003等三个平台下的设备驱动程序的开发。
1. 驱动程序源文件
首先在C盘根目录下新建一个目录,本例为C:\myrootkit,此后向相应文件都存放在该目录之下。然后可以在VC++下建立一个C源文件,让其内容如下所示:
//一个简单的驱动程序实例 #include "ntddk.h" NTSTATUS DriverEntry ( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath ) { DbgPrint("I am a driver!"); return STATUS_SUCCESS; } |
之后,将其保存在我们的C:\myrootkit目录下,并且该文件命名为mydriver.c。下面对上面的代码作简要的解释:
DriverEntry
是该驱动程序的入口点,即当该驱动程序启动时,操作系统会首先调用该函数。它相当于一般C/C++程序中的main或Winmain函数。另外,我们看到
DriverEntry的两个参数中都含有一个关键词IN,说明这两个参数只能用于输入。第一个参数指向应被初始化的当前驱动程序的驱动对象;第二个参数
是设备服务键的键名。
该驱动程序实在太简单了,它只是在内核运行时,利用调试语句给出一则消息:“I am a driver!”。不过,和一般程序不同,该消息不会显示在标准输出设备上,也就是说,我们在屏幕上看不到这则消失,关于调试输出的处理我们会在后文中加以详细介绍。
有
一点需要指出,那就是上面的驱动程序没有设置卸载例程。尽管卸载例程不是必需的,但有时它却非常有用:启动驱动程序时,系统会将参数
theDriverObject传递给该驱动程序的主函数,这个参数指向的数据结构含有许多函数指针,其中一个指针称为“unload
routine”。如果我们设置该指针,就能从内存中卸载驱动程序;如果不设置该指针的话,除非重新启动机器,否则无法将载入内存的驱动程序卸载掉。同
时,驱动程序在开发过程中,会不断添加或改变功能,所以要经常装载以及卸载它们。为了避免每次测试新版本的驱动程序时都必须重启系统,我们应当设置
“unload routine”指针。事实上,设置该指针并不是什么难事:先建立一个卸载例程,就可以设置该卸载指针了。
现在以前面的驱动程序为例,介绍如何为其添加卸载例程:
//一个简单的驱动程序实例 // 这里是我们的卸载函数 NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, } |