NT式驱动和WDM式驱动的加载

1.C语言调用约定,要求在声明函数时用__cdecl对函数进行修饰.

void  __cdecl  Foo(int a,int b);

C语言调用会在目标文件中产生一个符号来代表这个函数,此符号的形式为下划线+函数名,且函数体以ret形式返回。

push    11223344h

push    12345678h

call      _Foo

add     esp,8                   //恢复堆栈

即从右至左,将参数推进堆栈,执行结束后,以ret返回。

 

2.标准调用约定,要求在声明函数时用_stdcall对函数进行修饰。

void  __stddll  Foo(int a, int b);

标准调用会在目标文件中产生一个符号来代表这个函数,此符号形式为下划线+函数名+X。其中X代表清理堆栈时需要的数字,函数以ret X形式返回。

push    11223344h

push    12345678h

call       _Foo@8

即从右至左,将参数推进堆栈,当函数调用完,函数以ret 8返回。Foo函数负责恢复堆栈,而“调用者”不负责恢复堆栈,这个是C语言调用和标准调用最重要的区别之一。

 

3.手动加载NT式驱动

①打开注册表 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services  

创建新的项目        例如 DDK

②添加以下子键:

       名称                类型                   数据

       DisplayName: SZ                      DDK

       ErrorControl:  DWORD              1

       ImagePath:    EXPAND_SZ        /??/D:/DDK.sys

       Start:              DWORD              3        //规定按需要装入此驱动

       Type:              DWORD              1        //此驱动在内核模式下加载

③在命令行运行net start 服务名称,上面的DDK。停止使用net stop  服务名。

 

4.编写程序加载NT式驱动

NT式设备驱动程序的动态加载主要是由服务控制管理程序(Service Control Manager,即SCM)系统组件来完成的。
Windwos服务可以在系统启动时加载,用户也可以按需在服务控制平台开启或者关闭服务。程序员可以通过Windows提供的相关服务函数进行加载或者卸载该服务等。服务程序更是可以在用户还没有登录系统的时候,就载入系统并且被执行。

加载NT驱动一般分为4个步骤:
1.    调用OpenSCManager打开SCM管理器;
2.    调用CreateService创建服务;如果存在则调用OpenService打开服务(可根据GetLastError判断);
3.    调用StartService开启服务;
4.    关闭句柄。
卸载NT驱动一般分为5个步骤:
1.    调用OpenSCManager打开SCM管理器;
2.    调用OpenService打开此项服务;
3.    调用ControlService传递SERVICE_CONTROL_STOP来停止服务
4.    调用DeleteService卸载此项服务;
5.    关闭句柄。
注意:DeleteService只是标记一下该项服务需要删除,只有停止了服务并且关闭了打开服务的句柄,改服务才会被正式卸载。

加载驱动的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//装载NT驱动程序
BOOL LoadNTDriver(char* lpszDriverName,char* lpszDriverPath)
{
    char szDriverImagePath[256];
    //得到完整的驱动路径
    GetFullPathName(lpszDriverPath, 256, szDriverImagePath, NULL);

    BOOL bRet = FALSE;

    SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
    SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄

    //打开服务控制管理器
    hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );

    if( hServiceMgr == NULL )  
    {
        //OpenSCManager失败
        printf( "OpenSCManager() Faild %d ! \n", GetLastError() );
        bRet = FALSE;
        goto BeforeLeave;
    }
    else
    {
        ////OpenSCManager成功
        printf( "OpenSCManager() ok ! \n" );  
    }

    //创建驱动所对应的服务
    hServiceDDK = CreateService( hServiceMgr,
        lpszDriverName, //驱动程序的在注册表中的名字  
        lpszDriverName, // 注册表驱动程序的 DisplayName 值  
        SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限  
        SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序  
        SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值  
        SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值  
        szDriverImagePath, // 注册表驱动程序的 ImagePath 值  
        NULL,  
        NULL,  
        NULL,  
        NULL,  
        NULL);  

    DWORD dwRtn;
    //判断服务是否失败
    if( hServiceDDK == NULL )  
    {  
        dwRtn = GetLastError();
        if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )  
        {  
            //由于其他原因创建服务失败
            printf( "CrateService() Faild %d ! \n", dwRtn );  
            bRet = FALSE;
            goto BeforeLeave;
        }  
        else  
        {
            //服务创建失败,是由于服务已经创立过
            printf( "CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" );  
        }

        // 驱动程序已经加载,只需要打开  
        hServiceDDK = OpenService( hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS );  
        if( hServiceDDK == NULL )  
        {
            //如果打开服务也失败,则意味错误
            dwRtn = GetLastError();  
            printf( "OpenService() Faild %d ! \n", dwRtn );  
            bRet = FALSE;
            goto BeforeLeave;
        }  
        else
        {
            printf( "OpenService() ok ! \n" );
        }
    }  
    else  
    {
        printf( "CrateService() ok ! \n" );
    }

    //开启此项服务
    bRet= StartService( hServiceDDK, NULL, NULL );  
    if( !bRet )  
    {  
        DWORD dwRtn = GetLastError();  
        if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING )  
        {  
            printf( "StartService() Faild %d ! \n", dwRtn );  
            bRet = FALSE;
            goto BeforeLeave;
        }  
        else  
        {  
            if( dwRtn == ERROR_IO_PENDING )  
            {  
                //设备被挂住
                printf( "StartService() Faild ERROR_IO_PENDING ! \n");
                bRet = FALSE;
                goto BeforeLeave;
            }  
            else  
            {  
                //服务已经开启
                printf( "StartService() Faild ERROR_SERVICE_ALREADY_RUNNING ! \n");
                bRet = TRUE;
                goto BeforeLeave;
            }  
        }  
    }
    bRet = TRUE;
//离开前关闭句柄
BeforeLeave:
    if(hServiceDDK)
    {
        CloseServiceHandle(hServiceDDK);
    }
    if(hServiceMgr)
    {
        CloseServiceHandle(hServiceMgr);
    }
    return bRet;
}

卸载驱动的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//卸载驱动程序  
BOOL UnloadNTDriver( char * szSvrName )  
{
    BOOL bRet = FALSE;
    SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
    SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
    SERVICE_STATUS SvrSta;
    //打开SCM管理器
    hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );  
    if( hServiceMgr == NULL )  
    {
        //带开SCM管理器失败
        printf( "OpenSCManager() Faild %d ! \n", GetLastError() );  
        bRet = FALSE;
        goto BeforeLeave;
    }  
    else  
    {
        //带开SCM管理器失败成功
        printf( "OpenSCManager() ok ! \n" );  
    }
    //打开驱动所对应的服务
    hServiceDDK = OpenService( hServiceMgr, szSvrName, SERVICE_ALL_ACCESS );  

    if( hServiceDDK == NULL )  
    {
        //打开驱动所对应的服务失败
        printf( "OpenService() Faild %d ! \n", GetLastError() );  
        bRet = FALSE;
        goto BeforeLeave;
    }  
    else  
    {  
        printf( "OpenService() ok ! \n" );  
    }  
    //停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。  
    if( !ControlService( hServiceDDK, SERVICE_CONTROL_STOP , &SvrSta ) )  
    {  
        printf( "ControlService() Faild %d !\n", GetLastError() );  
    }  
    else  
    {
        //打开驱动所对应的失败
        printf( "ControlService() ok !\n" );  
    }  
    //动态卸载驱动程序。  
    if( !DeleteService( hServiceDDK ) )  
    {
        //卸载失败
        printf( "DeleteSrevice() Faild %d !\n", GetLastError() );  
    }  
    else  
    {  
        //卸载成功
        printf( "DelServer:eleteSrevice() ok !\n" );  
    }  
    bRet = TRUE;
BeforeLeave:
//离开前关闭打开的句柄
    if(hServiceDDK)
    {
        CloseServiceHandle(hServiceDDK);
    }
    if(hServiceMgr)
    {
        CloseServiceHandle(hServiceMgr);
    }
    return bRet;   
}

 

5.WDM驱动的安装需要提供inf文件。

我们拿一个inf文件来分析:

;——— 版本区域 —————————————————
[Version]
Signature=”$Chicago$”
Provider=%Coder%
DriverVer=06/22/2014,2.0.0.1

; 如果设备是一个标准类别,使用标准类名称和GUID,否则自定义类别名称和GUID.
Class=Processing Device
ClassGUID={EF2962F0-444A-4d61-5273-4C756f876549}

;——— 安装盘节 ———————–
; 这些节确定安装盘和安装文件的路径,按照自己的需要修改

[SourceDisksNames]
1=”HELLOWDM”,,,

[SourceDisksFiles.x86]
HELLOWDM.sys=1

;——— ClassInstall/ClassInstall32 Section ——————————-
; 如果使用标准类设备,下面的不需要

;9X style
[ClassInstall]
Addreg=Class_AddReg

;NT Style
[ClassInstall32]
Addreg=Class_addReg

[Class_AddReg]
HKR,,,,”DONJIN Media Processing Device”
HKR,,Icon,,”-5″

;——— 目标文件节 ——————————————-
[DestinationDirs]
Wdm5.Files.Driver=10,System32\Drivers
Wdm5.Files.Driver.NTx86=10,System32\Drivers

;——— 制造商节 ———————————-
[Manufacturer]
%MfgName% = Coder.Co

[DonJin.Co]
%DeviceDesc%=DJBOARD_DDI, PCI\VEN_104C&DEV_AC60&SUBSYS_00004A44

;———- DDInstall Sections ———————————————–
;———- Windows 2000 —————————————————–
[DJBOARD_DDI.NTx86]
CopyFiles=DJBOARD.Files.Driver.NTx86
AddReg=DJBOARD_NT_AddReg

[DJBOARD.Files.Driver.NTx86]
DJKBWDM.sys,,,%COPYFLG_NOSKIP%

[DJBOARD_NT_AddReg]
HKLM, “System\CurrentControlSet\Services\DJKBWDM\Parameters”,\
“BreakOnEntry”, 0x00010001, 0

[DJBOARD_DDI.NTx86.Services]
AddService = DJKBWDM, %SPSVCINST_ASSOCSERVICE%, DJBOARD_AddService

[DJBOARD_AddService]
DisplayName    = %DeviceDesc%    ;服务显示名称要和设备名称相同
ServiceType    = %SERVICE_KERNEL_DRIVER%
StartType      = %SERVICE_DEMAND_START%
ErrorControl   = %SERVICE_ERROR_NORMAL%
ServiceBinary  = %10%\System32\Drivers\HELLOWDM.sys
BaseSerialPort = %SERVICE_BASE_SERIAL_PORT%

;——— 字符串节 ———————————————————–
[Strings]
MfgName=”Coder Communication Tech CO., LTD”
DeviceDesc=”Coder Technology: PCI Analog Board”

SPSVCINST_ASSOCSERVICE=0x00000002 ; Driver service is associated with device being installed
COPYFLG_NOSKIP=2 ; Do not allow user to skip file

ServiceDesc=”Coder PCI Board Driver(DFM Board)”
SERVICE_KERNEL_DRIVER=1
SERVICE_AUTO_START=2
SERVICE_DEMAND_START=3
SERVICE_ERROR_NORMAL=1
SERVICE_BASE_SERIAL_PORT=5

本文链接:http://www.alonemonkey.com/driverload-nt-wdm.html