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