首页
社区
课程
招聘
[原创]Win32Asm 驱动学习笔记<5> 驱动程序的安装与卸载
发表于: 2013-8-16 11:21 8722

[原创]Win32Asm 驱动学习笔记<5> 驱动程序的安装与卸载

2013-8-16 11:21
8722

Win32Asm 驱动学习笔记 第五章《 驱动程序的安装与卸载》

     
版权声明

         本文所述内容很多来自互联网以及其他一些参考资料,并不是全部原创,属于学习笔记汇总,凡因此文引发的版权问题,作者本人不负任何责任。

自序

      虽我未学,下笔无文,然驱动入门之路何其曲折,何妨我将其倾注于笔墨文字,因其内容多引用经典,作者心得体会穿插其间,故不敢擅称教程,借以笔记之说,攒此文字,以谓后来者。
      另外,作者不才,内容错漏之处还请海涵指正,谢谢。

第五章 驱动程序的安装与卸载
本章目录:
5.1  Windows服务
5.2  服务控制管理器(SCM)
5.3  服务控制程序(SCP)
     5.3.1 建立到SCM的连接
     5.3.2 安装一个新的驱动
     5.3.3 打开已存在的驱动
     5.3.4  停止已存在的驱动
     5.3.5 启动驱动程序
     5.3.6 卸载驱动
5.4 通用模板
     5.4.1 模板的建立
     5.4.2 模板的导入

5.5 本章小结

正文开始:
      前面我们学到了一个简单的驱动程序“beeper.sys”,今天我们来学习怎么自己编程来加载它,我们前面介绍过,NT式驱动的加载与卸载是基于服务的, 我们先来简单介绍下Windows服务吧,在这方面罗云彬翻译的KmdTut中文版里介绍的不错,我对原文进行了适当的补充完善后摘抄入此,内容如下:
5.1 Windows服务    
      Windows  NT使用某种机制来启动进程,并让它们不和某个具体的交互式的用户界面相关联,这些进程就被称为服务(service),服务的一个很好的例子就是Web 服务器,这些Web服务都没有用户界面,服务是唯一以这种方式运行的应用程序(注:指没有用户界面,当然,严格地说病毒、木马以及所有不想见光的程序也是 这样的~~),服务可以在系统启动的时候自动启动,也可以被手工启动,从这一点来看,设备驱动程序和服务是类似的。
    Windows  NT还支持驱动程序服务,只要使用的时候遵循设备驱动程序协议就可以了,这和用户模式的服务类似,所以,"服务"一词既可以指用户模式的服务进程或者内核 模式的设备驱动程序,微软不知何故没有明确地区分两者的概念,所以下面的叙述可能看起来有点让人疑惑。可能有的地方我会说到"driver"一词,但在其 他的文章中可能说到"service"一词,但既然这篇教程讲的是如何编写内核设备驱动程序,那么我们就约定无论说到"service"还 是"driver",我们的意思都是指"驱动程序",当的确需要提及"服务"的时候,我会明确地指出来的。
    另外,请读者时刻记得,文档中关于服务管理的函数其实是叙述得相当含糊的,因为这些函数既能用于驱动程序也能用于服务,在下面的文章中,我们只强调它们在驱动方面的用途和忽略服务方面的用途。
    Windows NT中有主要有两个组件和服务管理相关:
◎ 服务控制管理器(Service Control Manager/SCM)--用于启动服务以及和它通讯
◎ 服务控制程序(Service Control Program/SCP)--用于和SCM进行通讯,告诉它何时启动或者停止服务

    服务程序中包含可执行代码,这两个组件对服务和驱动程序的处理方式是相同的。我们先来看看这两个组件,在后面再讲述驱动程序。

5.2 服务控制管理器(SCM)
       SCM的代码位于\%SystemRoot%\System32\Services.exe中,当系统启动的时候,SCM被WinLogon进程启动,然 后它扫描注册表中HKLM\SYSTEM\CurrentControlSet\Services键下的相关内容,根据这些内容创建一个服务数据库,数据 库中包括所有服务的相关参数,如果服务或者驱动被标为自动启动的,那么启动它们并检测启动中是否出错。
    为了更深入一步,我们可以用注册表编辑器regedit.exe来打开并观察注册表中的 HKLM\SYSTEM\CurrentControlSet\Services\下面的内容。
    想要查看系统中安装了哪些服务(注意不是驱动),可以在控制面板中选择"管理工具",再打开"服务"来查看。
    要查看系统中安装了哪些驱动,可以在控制面板中选择"管理工具",再打开"计算机管理",在"系统信息"下的"软件环境"中,你可以看到所有驱动的列表,但是不幸的是,在Windows XP中,这个功能被取消了。
    仔细对比一下上面三个地方的内容,我们可以发现这些内容是很一致的。
    HKLM\SYSTEM\CurrentControlSet\Services\下面有很多子键,表示一个服务的内部名称,每个子键下包含了和这个服务相关的参数。
    现在来考察一下安装一个服务所需的最低数量的参数,我们拿前面提到beeper.sys来举例。



图5.1 beeper.sys驱动的注册表键值

    这些参数的含义如下:

◎ DisplayName--用户程序访问服务时使用的名称;

◎ ErrorControl--如果SCM启动服务的时候驱动报错,这个值决定了SCM如何对付这个错误,我们对两种取值有点兴趣:
· SERVICE_ERROR_IGNORE (0)--I/O管理器忽略这个错误,不作记录
· SERVICE_ERROR_NORMAL (1)--如果驱动被装入的时候报错,系统将给用户显示一个告警框,并将错误记录到系统日志中

      你可以在控制面板中的"管理工具"中选择"事件查看器"来查看系统日志,例如,beeper.sys驱动在初始化的时候做完了所有该做的事(这个例子会让 喇叭发声音,但是发声功能是在初始化函数DriverEntry中做的,初始化函数执行完,后面就没什么事了),所以它就返回一个错误,系统就会将它从内 存中卸载。但是这里的ErrorControl参数等于SERVICE_ERROR_IGNORE,所以系统日志中并没有错误记录。

◎ ImagePath--指驱动文件的全路径文件名,如果该参数没有指定路径,那么系统会在\%SystemRoot%\Drivers目录下查找
◎ Start--指明何时装载驱动,这里我们关心的也是两个取值
· SERVICE_AUTO_START (2)--驱动在系统启动的时候装载
· SERVICE_DEMAND_START (3)--驱动由SCM根据用户要求装载

     如果驱动的Start参数为SERVICE_AUTO_START  (2),那么SCM会在系统启动的时候就装载它,这样的驱动被称为自动启动的服务,如果驱动的执行依赖于其他的驱动,SCM也会把其他的驱动也启动起来 (要控制设备驱动被装载的顺序,可以使用Group、Tag和DependOnGroup等参数值;要控制服务被装载的顺序,可以使用Group和 DependOnService参数)。Start参数还有其他的取值,如SERVICE_BOOT_START  (0),但这个参数只能供设备驱动程序使用,I/O管理器将在用户模式的进程启动之前把装载这些驱动程序,这时SCM还没有启动呢!

◎ Type--用于指定服务的类型,既然我们这里讲的是KMD的编程,那么我们只对一个取值感兴趣,那就是SERVICE_KERNEL_DRIVER (1)

    仔细观察图5.1后,你对beeper.sys有什么要说的吗?好的,我们看到beeper这个内核模式驱动程序位于”D:\RadASM\Masm\Projects\beeper"目录下,它的名称为"beeper",由用户控制启动,出错信息不被记录。
    Path前面的"\??"前缀的含义你下面就会知道!
    如果我们要启动SCM数据库中不存在的驱动程序,那么可以在任何时刻在SCP的帮助下动态装入(也许称为DCP/device control program更为贴切,但是微软的术语库中并没有这个词)。

5.3 服务控制程序(SCP)

     从名称理解,服务控制程序(service control  program/SCP)可以控制服务或者设备驱动程序,这些功能是在SCM的管理下,通过调用适当的函数来完成的,这些函数位 于\%SystemRoot%\System32\advapi.dll (Advanced API)中。
    这里是一段关于使用SCP来控制beeper.sys驱动的代码例子


;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;  Service Control Program for beeper driver
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.386
.model flat, stdcall
option casemap:none
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                             I N C L U D E   F I L E S
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
include windows.inc
include kernel32.inc
include user32.inc
include advapi32.inc
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
include \RadASM\masm32\Macros\Strings.mac 


 includelib debug.lib
 include debug.inc
; ----------------------debug-------------------------------
; PrintError
; PrintText<"debug message!">
; PrintString<driver>
; PrintStringByAddr<offset driver>
; PrintDword<hSCManager,driver>

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                       C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
start proc
local hSCManager:HANDLE
local hService:HANDLE
local acDriverPath[MAX_PATH]:CHAR
LOCAL bRet:BOOL
LOCAL SvrSta
    
    invoke OpenSCManager, NULL, NULL, SC_MANAGER_CREATE_SERVICE
    
     mov hSCManager, eax
    
     PrintDec hSCManager
   
    .if hSCManager != NULL
          
       invoke GetFullPathName, $CTA0("beeper.sys"),sizeof acDriverPath,addr acDriverPath,NULL
       PrintString acDriverPath
        
       invoke CreateService, hSCManager, $CTA0("beeper"), $CTA0("Beeper"), \
                SERVICE_START + DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, \
                SERVICE_ERROR_IGNORE, addr acDriverPath, NULL, NULL, NULL, NULL, NULL
        mov hService, eax
       
        PrintDec hService
       
         .if hService==NULL
                  
              PrintError
            
              invoke GetLastError
           
              ; 服务创建失败,是由于服务已经创立过
              .if  eax==ERROR_IO_PENDING || eax==ERROR_SERVICE_EXISTS   ||  eax==ERROR_SERVICE_MARKED_FOR_DELETE 
                   
                    invoke OpenService ,hSCManager,$CTA0("beeper"), SERVICE_ALL_ACCESS
                    mov hService, eax
                    push eax
                    ;如果打开服务也失败,则意味错误 
                     .if eax==NULL
                              pop eax
                              PrintError
                              jmp exit 
                      
                        .endif
                     pop eax  
                     
                     
                     ;服务创建失败,是由于服务已经标记删除  
                     .if  eax==ERROR_SERVICE_MARKED_FOR_DELETE
                   
                          invoke ControlService,hService,SERVICE_CONTROL_STOP, addr SvrSta
                          invoke CloseServiceHandle,hService
                          
                          ;再次创建
                          invoke CreateService, hSCManager, $CTA0("beeper"), $CTA0("beeper"), \
                SERVICE_START + DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, \
                SERVICE_ERROR_IGNORE, addr acDriverPath, NULL, NULL, NULL, NULL, NULL
                            
                           ;如果再次创建再失败,则意味着错误                       
                          .if eax==NULL
                          
                               PrintError
                                mov bRet,FALSE
                                jmp exit 
                              
                          .endif
                         
  
                       .endif
                       
                 ;由于其他原因创建服务失败
                .else
                  
                   PrintText "注册驱动时出错,出错信息如下:"
                   PrintError                 
                   mov bRet,FALSE
                   jmp exit
               
        
                .endif
              
          .endif
           
            invoke StartService, hService, 0, NULL
            invoke DeleteService, hService
            
     
     .else
     

            invoke MessageBox, NULL, $CTA0("打开服务管理器出错."), \
                            NULL, MB_ICONSTOP
        
            PrintText "打开服务管理器出错"
            PrintError
        
    .endif
   
    
    exit:
    
      .if  hService

               invoke CloseServiceHandle ,hService ; 服务句柄
     .endif
     
      .if hSCManager

             invoke CloseServiceHandle ,hSCManager; SCM句柄
    
      .endif
      
    invoke ExitProcess, 0
    
start endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
end start


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 5
支持
分享
最新回复 (7)
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
2
非安全果然酷爱Win32 ASM

希望能坚持这个系列教程,并且能逐步加深 : )
2013-8-16 11:30
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
3
呵呵 ,我会的,谢谢支持。
2013-8-16 11:50
0
雪    币: 97697
活跃值: (200824)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
4
+1
2013-8-16 13:50
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
5
谢谢支持,每次都能看到你额
2013-8-16 14:06
0
雪    币: 259
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
写得很多都没有涉及一个问题,这些驱动程序与应用程序之间的通迅就是不成功(I/O控制),点击后总是提示:“控制失败:系统找不到指定的文件。”,难道你从来没有遇到过吗?能解决吗?
2014-7-2 19:41
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
7
名称不对的问题吧,你可以看下我相关的例子有完整的实例,下面的笔记会讲到I/O通讯,只是我还没有时间完成。
2014-7-5 06:22
0
雪    币: 259
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢,就是名称的问题,和文件名一致就可以了
2014-8-12 11:18
0
游客
登录 | 注册 方可回帖
返回
//