设备scan和驱动入门安装
从一个接口开始,扫描硬件设备:
#include <cfgmgr32.h>
BOOL ScanForHardwareChange()
{
DEVINST devInst;
CONFIGERT status;
//得到设备管理树的根结点
status = CM_Locate_DevNode(&devInst,NULL,CM_LOCATE_DEVNODE_NARMAL);
if (status!=CR_SUCCESS)
{
printf( "CM_Locate_DevNode failed: %x\n ",status);
return FALSE;
}
//刷新
status = CM_Reenumerate_DevNode(devInst,CM_REENUMERATE_ASYNCHRONOUS); //CM_REENUMERATE_ASYNCHRONOUS 异步方式可以立即响应
if (status !=CR_SUCCESS)
{
printf( "CM_Reenumerate_DevNode failed: %x\n ",status);
return FALSE;
}
return TRUE;
}
一 驱动入门实例
VS2012编译调试WDM驱动(KdPrint无调试信息 debugview win7无调试信息)
对于WDM驱动 VS2012有向导可以新建WDM项目 如图 这点说明不用自己配置 文件目录 C/C++ 选项 LINK 选项 等一系列的参数 比以前方便了不少
新建以后是空项目 放入《windows驱动开发技术详解》中第一章的WDM代码
分别是: HelloWDM.h
- #if __cplusplus
- extern "C"
- {
- #endif
- #include <wdm.h>
- #ifdef __cplusplus
- }
- #endif
- typedef struct _DEVICE_EXTERSION
- {
- PDEVICE_OBJECT fdo;
- PDEVICE_OBJECT NextStatckDevice;
- UNICODE_STRING ustrDeviceName; //设备名
- UNICODE_STRING ustrSymLinkName; //符号链接名
- }DEVICE_EXTENSION, *PDEVICE_EXTENSION;
- #define PAGEDCODE code_seg("PAGE")
- #define LOCKEDCODE code_seg()
- #define INITCODE code_set("INIT")
- #define PAGEDDATA data_set("PAGE")
- #define LOCKEDDATA data_set()
- #define INITDATA data_set("INIT")
- #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
- NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);
- NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
- NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
- void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject);
- NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp);
- NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
- extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
HelloWDM.cpp
- #include "HelloWDM.h"
- #pragma INITCODE
- extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
- {
- KdPrint(("Entry DriverEntry\n"));
- pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
- pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
- pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
- pDriverObject->MajorFunction[IRP_MJ_CREATE] =
- pDriverObject->MajorFunction[IRP_MJ_READ] =
- pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine;
- pDriverObject->DriverUnload = HelloWDMUnload;
- KdPrint(("Leave DriverEntry\n"));
- return STATUS_SUCCESS;
- }
- #pragma PAGECODE
- NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
- {
- PAGED_CODE();
- KdPrint(("Enter HelloWDMAddDevice\n"));
- NTSTATUS status;
- PDEVICE_OBJECT fdo;
- UNICODE_STRING devName;
- RtlInitUnicodeString(&devName, L"\\Device\\MyWDMDevice");
- status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
- if(!NT_SUCCESS(status))
- return status;
- PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
- pdx->fdo = fdo;
- pdx->NextStatckDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
- UNICODE_STRING symLinkName;
- RtlInitUnicodeString(&symLinkName, L"\\DosDevices\\HelloWDM");
- pdx->ustrDeviceName = devName;
- pdx->ustrSymLinkName = symLinkName;
- status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName, &(UNICODE_STRING)devName);
- if(!NT_SUCCESS(status))
- {
- IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
- status = IoCreateSymbolicLink(&symLinkName, &devName);
- if(!NT_SUCCESS(status))
- {
- return status;
- }
- }
- fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
- fdo->Flags &= ~DO_DEVICE_INITIALIZING;
- KdPrint(("Leave HelloWDMAddDevice\n"));
- return STATUS_SUCCESS;
- }
- #pragma PAGEDCODE
- NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
- {
- PAGED_CODE();
- KdPrint(("Enter HelloWDMPnp\n"));
- NTSTATUS status = STATUS_SUCCESS;
- PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
- PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
- static NTSTATUS (*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp)=
- {
- DefaultPnpHandler,
- DefaultPnpHandler,
- HandleRemoveDevice,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- };
- ULONG fcn = stack->MinorFunction;
- if(fcn >= arraysize(fcntab))
- {
- status = DefaultPnpHandler(pdx, Irp);
- return status;
- }
- status = (*fcntab[fcn])(pdx, Irp);
- KdPrint(("Leave HelloWDMPnp\n"));
- return status;
- }
- #pragma PAGEDCODE
- NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp)
- {
- PAGED_CODE();
- KdPrint(("Enter DefaultPnpHandler\n"));
- IoSkipCurrentIrpStackLocation(Irp);
- KdPrint(("Leave DefaultPnpHandler\n"));
- return IoCallDriver(pdx->NextStatckDevice, Irp);
- }
- #pragma PAGEDCODE
- NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
- {
- PAGED_CODE();
- KdPrint(("Enter HandlerRemoveDevice\n"));
- Irp->IoStatus.Status = STATUS_SUCCESS;
- NTSTATUS status = DefaultPnpHandler(pdx, Irp);
- IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName);
- if(pdx->NextStatckDevice)
- IoDetachDevice(pdx->NextStatckDevice);
- IoDeleteDevice(pdx->fdo);
- KdPrint(("Leave HandlerRemoveDevice\n"));
- return status;
- }
- #pragma PAGEDCODE
- NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
- {
- PAGED_CODE();
- KdPrint(("Enter HelloWDMDispatchRoutine\n"));
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- KdPrint(("Leave HelloWdmDispatchRoutine\n"));
- return STATUS_SUCCESS;
- }
- #pragma PAGEDCODE
- void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)
- {
- PAGED_CODE();
- KdPrint(("Enter HelloWDMUnload\n"));
- KdPrint(("Leave HelloWDMUnload\n"));
- }
代码放置后工程目录如图:
项目默认是vista的debug版本 修改为 win7 debug
然后build工程 出现错误:
错误原因是因为 警告级别设置过高 将警告级别改为W3等级 如图
设置后编译通过 生成了MyDriver1.sys文件 MyDriver1.inf文件 这个时候修改inf文件为:如果没有产生INF文件则自己新建一个
- ;--------- Version Section ---------------------------------------------------
- [Version]
- Signature="$CHICAGO$";
- Provider=Zhangfan_Device
- DriverVer=07/19/2013,15.16.19.288
- ; If device fits one of the standard classes, use the name and GUID here,
- ; otherwise create your own device class and GUID as this example shows.
- Class=ZhangfanDevice
- ClassGUID={EF2962F0-0D55-4bff-B8AA-2221EE8A79B0}
- ;--------- SourceDiskNames and SourceDiskFiles Section -----------------------
- ; These sections identify source disks and files for installation. They are
- ; shown here as an example, but commented out.
- [SourceDisksNames]
- 1 = "HelloWDM",Disk1,,
- [SourceDisksFiles]
- MyDriver1.sys = 1,,
- ;--------- ClassInstall/ClassInstall32 Section -------------------------------
- ; Not necessary if using a standard class
- ; 9X Style
- [ClassInstall]
- Addreg=Class_AddReg
- ; NT Style
- [ClassInstall32]
- Addreg=Class_AddReg
- [Class_AddReg]
- HKR,,,,%DeviceClassName%
- HKR,,Icon,,"-5"
- ;--------- DestinationDirs Section -------------------------------------------
- [DestinationDirs]
- YouMark_Files_Driver = 10,System32\Drivers
- ;--------- Manufacturer and Models Sections ----------------------------------
- [Manufacturer]
- %MfgName%=Mfg0
- [Mfg0]
- ; PCI hardware Ids use the form
- ; PCI\VEN_aaaa&DEV_bbbb&SUBSYS_cccccccc&REV_dd
- ;改成你自己的ID
- %DeviceDesc%=YouMark_DDI, PCI\VEN_9999&DEV_9999
- ;---------- DDInstall Sections -----------------------------------------------
- ; --------- Windows 9X -----------------
- ; Experimentation has shown that DDInstall root names greater than 19 characters
- ; cause problems in Windows 98
- [YouMark_DDI]
- CopyFiles=YouMark_Files_Driver
- AddReg=YouMark_9X_AddReg
- [YouMark_9X_AddReg]
- HKR,,DevLoader,,*ntkern
- HKR,,NTMPDriver,,MyDriver1.sys
- HKR, "Parameters", "BreakOnEntry", 0x00010001, 0
- ; --------- Windows NT -----------------
- [YouMark_DDI.NT]
- CopyFiles=YouMark_Files_Driver
- AddReg=YouMark_NT_AddReg
- [YouMark_DDI.NT.Services]
- Addservice = HelloWDM, 0x00000002, YouMark_AddService
- [YouMark_AddService]
- DisplayName = %SvcDesc%
- ServiceType = 1 ; SERVICE_KERNEL_DRIVER
- StartType = 3 ; SERVICE_DEMAND_START
- ErrorControl = 1 ; SERVICE_ERROR_NORMAL
- ServiceBinary = %10%\System32\Drivers\MyDriver1.sys
- [YouMark_NT_AddReg]
- HKLM, "System\CurrentControlSet\Services\HelloWDM\Parameters",\
- "BreakOnEntry", 0x00010001, 0
- ; --------- Files (common) -------------
- [YouMark_Files_Driver]
- MyDriver1.sys
- ;--------- Strings Section ---------------------------------------------------
- [Strings]
- ProviderName="Zhangfan."
- MfgName="Zhangfan Soft"
- DeviceDesc="Hello World WDM!"
- DeviceClassName="Zhangfan_Device"
- SvcDesc="Zhangfan"
接下来是加载驱动 使用EzDriverInstaller工具 下载地址:http://download.****.NET/detail/whatday/5782597
把MyDriver1.sys和MyDriver1.inf拷贝到VM的win7下,用EzDriverInstaller打开inf文件 如图
这时打开Dbgview 进行调试信息的监视
点击 Add New Device按钮后 设备添加成功 但是DbgView中没有出现调试信息
原因在于 win7/vista下需要修改调试信息过滤的键值 具体做法是
新建一个1.reg文件,写入如下内容:
- Windows Registry Editor Version 5.00
- [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter]
- "DEFAULT"=dword:00000008
导入重启之后,OK。键值00000008不行 可以改为0000000f尝试 我这边测试08是成功的。
重启后再次开启 EzDriverInstaller 和 DbgView 再次点击 Add New Device 这时发现已经有调试信息了
接下来就是调试WDM驱动,便于测试在驱动中添加一个 读取制定函数SSDT地址的功能 修改后的代码如下:
HelloWDM.h:
- #include "HelloWDM.h"
- #pragma INITCODE
- extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
- {
- KdPrint(("Entry DriverEntry\n"));
- pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
- pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
- pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
- pDriverObject->MajorFunction[IRP_MJ_CREATE] =
- pDriverObject->MajorFunction[IRP_MJ_READ] =
- pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine;
- pDriverObject->DriverUnload = HelloWDMUnload;
- KdPrint(("Leave DriverEntry\n"));
- DbgBreakPoint();
- ULONG SSDT_NtOpenProcess_Cur_Addr;
- ULONG dwAddr = (ULONG)KeServiceDescriptorTable->pSSDTBase;
- KdPrint(("当前SSDT的基地址是:0x%x\n", dwAddr));
- SSDT_NtOpenProcess_Cur_Addr = *(PULONG)(dwAddr + 4*190);
- KdPrint(("当前NtOpenProcess的地址是0x%x\n", SSDT_NtOpenProcess_Cur_Addr));
- return STATUS_SUCCESS;
- }
- #pragma PAGECODE
- NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
- {
- PAGED_CODE();
- KdPrint(("Enter HelloWDMAddDevice\n"));
- NTSTATUS status;
- PDEVICE_OBJECT fdo;
- UNICODE_STRING devName;
- RtlInitUnicodeString(&devName, L"\\Device\\MyWDMDevice");
- status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
- if(!NT_SUCCESS(status))
- return status;
- PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
- pdx->fdo = fdo;
- pdx->NextStatckDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
- UNICODE_STRING symLinkName;
- RtlInitUnicodeString(&symLinkName, L"\\DosDevices\\HelloWDM");
- pdx->ustrDeviceName = devName;
- pdx->ustrSymLinkName = symLinkName;
- status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName, &(UNICODE_STRING)devName);
- if(!NT_SUCCESS(status))
- {
- IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
- status = IoCreateSymbolicLink(&symLinkName, &devName);
- if(!NT_SUCCESS(status))
- {
- return status;
- }
- }
- fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
- fdo->Flags &= ~DO_DEVICE_INITIALIZING;
- KdPrint(("Leave HelloWDMAddDevice\n"));
- return STATUS_SUCCESS;
- }
- #pragma PAGEDCODE
- NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
- {
- PAGED_CODE();
- KdPrint(("Enter HelloWDMPnp\n"));
- NTSTATUS status = STATUS_SUCCESS;
- PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
- PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
- static NTSTATUS (*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp)=
- {
- DefaultPnpHandler,
- DefaultPnpHandler,
- HandleRemoveDevice,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- DefaultPnpHandler,
- };
- ULONG fcn = stack->MinorFunction;
- if(fcn >= arraysize(fcntab))
- {
- status = DefaultPnpHandler(pdx, Irp);
- return status;
- }
- status = (*fcntab[fcn])(pdx, Irp);
- KdPrint(("Leave HelloWDMPnp\n"));
- return status;
- }
- #pragma PAGEDCODE
- NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp)
- {
- PAGED_CODE();
- KdPrint(("Enter DefaultPnpHandler\n"));
- IoSkipCurrentIrpStackLocation(Irp);
- KdPrint(("Leave DefaultPnpHandler\n"));
- return IoCallDriver(pdx->NextStatckDevice, Irp);
- }
- #pragma PAGEDCODE
- NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
- {
- PAGED_CODE();
- KdPrint(("Enter HandlerRemoveDevice\n"));
- Irp->IoStatus.Status = STATUS_SUCCESS;
- NTSTATUS status = DefaultPnpHandler(pdx, Irp);
- IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName);
- if(pdx->NextStatckDevice)
- IoDetachDevice(pdx->NextStatckDevice);
- IoDeleteDevice(pdx->fdo);
- KdPrint(("Leave HandlerRemoveDevice\n"));
- return status;
- }
- #pragma PAGEDCODE
- NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
- {
- PAGED_CODE();
- KdPrint(("Enter HelloWDMDispatchRoutine\n"));
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- KdPrint(("Leave HelloWdmDispatchRoutine\n"));
- return STATUS_SUCCESS;
- }
- #pragma PAGEDCODE
- void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)
- {
- PAGED_CODE();
- KdPrint(("Enter HelloWDMUnload\n"));
- KdPrint(("Leave HelloWDMUnload\n"));
- }
没有打印出SSDT的相关信息 ,初步估计还是加载了上次的SYS文件,WIN7系统肯定有备份存档之类的,在C盘搜索MyDriver1.sys 得到4个路径如图:
其中第一个路径 刚才已经覆盖过 但是驱动显示的结果没有变化所以 这里先pass掉
然后依次测试第二 第三,当测试到第三个路径时出现权限问题:
返回上一级目录 对该目录右键 设置管理员取得所有权:
设置后就可以成功覆盖SYS文件了 用EzDriverInstaller工具加载 发现覆盖驱动后 调试信息发生了变化 如图:
一般来说win7的驱动备份文件夹都是各个优化软件的减肥首选,由此看来win7的驱动备份文件夹也不是完全无用的,至少更新驱动的时候还是需要用到。
至此VS2012编译调试WDM驱动就完毕了,现在可以随意的修改调试我们的WDM程序了。
这里需要注意 “Add New Device”测试完毕后 一定要“Remove Device”因为如果重启WIN7 进入正常模式(非DEBUG模式)它会自动加载我们的WDM驱动 如果驱动中有断点API或错误 就会蓝屏挂掉。当然如果是进入DEBUG模式,然后双机调试就可以看到在windbg中断下来了,断点位置就是我们程序中设置的断点API代码。
最后再附上 win7/ vista下为什么需要修改调试信息过滤键值的原因 原文如下
在OSR查了下资料,摘录如下:
The problem: Your DbgPrint or KdPrint messages don't appear in WinDbg (or KD) when you run your driver on Windows Vista.
The reason? Vista automatically maps DbgPrint and friends to DbgPrintEx. Now, you may recall that DbgPrintEx allows you to control the conditions under which messages will be sent to the kernel debugger by filtering messages via a component name and level in the function call and an associated filter mask in either the registry or in memory.
In Vista, DbgPrint and KdPrint are mapped to component "DPFLTR_DEFAULT_ID" and level "DPFLTR_INFO_LEVEL". Of course, in Vista, xxx_INFO_LEVEL output is disabled by default. So, by default, your DbgPrint/KdPrint doesn't get sent to the kernel debugger.
How to fix it? Two choices:
-
Enable output of DbgPrint/KdPrint messages by default --Open the key "HKLM/SYSTEM/CCS/Control/Session Manager/Debug Print Filter". Under this key, create a value with the name "DEFAULT" Set the value of this key equal to the DWORD value 8 to enable xxx_INFO_LEVEL output as well as xxx_ERROR_LEVEL output. Or try setting the mask to 0xF so you get all output. You must reboot for these changes to take effect.
- Specifically change the component filter mast for DPFLTR. In early releases of Vista/LH you changed the default printout mask by specifying a mask value for the DWORD at Kd_DPFLTR_MASK ("ed Kd_DPFLTR_MASK"). In build 5308 (the February CTP of Vista), it seems that the mask variable has changed and you need to set the mask value for the DWORD at Kd_DEFAULT_MASK ("ed Kd_DEFAULT_MASK). In either case, specify 8 to enable DPFLTR_INFO_LEVEL output in addition to DPFLTR_ERROR_LEVEL output, or 0xF to get all levels of output.
See the WDK documentation for Reading and Filtering Debugging Messages (follow the path: Driver Development Tools/Tools for Debugging Drivers/Using Debugging Code in a Driver/Debugging Code Overview) for the complete details on the use of DbgPrintEx/KdPrintEx. Or look at the Debugging Tools For Windows documentation (Appendix A) on DbgPrintEx.
编译环境:VS2012 + WIN8 64
测试环境:VM WIN7
测试对象:WDM驱动 (sys文件 和 inf文件)
项目类型:Win32 Console Application
其它说明:代码来源于网络,经小修改而成,加载驱动方法还有很多(如SetupCopyOEMInf等OEM系列函数),但是逆向EzDriverInstaller驱动加载器,发现和下面代码逻辑基本一致,所以最终记录以下代码,以便日后使用。
代码如下:
- // WinInstallWin.cpp :
- //
- #include "stdafx.h"
- #include <windows.h>
- #include <newdev.h>
- #include <setupapi.h>
- #include <locale.h>
- #pragma comment(lib, "newdev.lib")
- #pragma comment(lib, "setupapi.lib")
- #ifndef MAX_DEVICE_ID_LEN
- #define MAX_DEVICE_ID_LEN 200
- #define MAX_DEVNODE_ID_LEN MAX_DEVICE_ID_LEN
- #define MAX_GUID_STRING_LEN 39 // 38 chars + terminator null
- #define MAX_CLASS_NAME_LEN 32
- #endif
- WORD g_wVender = 0;
- WORD g_wHardware = 0;
- TCHAR g_strVender[20][64] = {0};
- TCHAR g_strHardware[20][64] = {0};
- TCHAR g_strHID[MAX_PATH+1] = {0};
- //打印错误
- VOID ShowErrorMsg(DWORD Count,LPCWSTR szData)
- {
- printf("%d\n%s",&Count,&szData);
- }
- //过滤字符
- VOID FindComma(LPSTR szData)
- {
- WORD wLen = (WORD)strlen(szData);
- WORD wIdx;
- WORD wLoop;
- CHAR szTmp[128] = {0};
- for (wIdx = 0, wLoop = 0; wLoop < wLen; wLoop++)
- {
- if (szData[wLoop] == ',')
- szData[wLoop] = '.';
- else if (szData[wLoop] == ' ')
- continue;
- szTmp[wIdx++] = szData[wLoop];
- }
- memcpy(szData, szTmp, wIdx*sizeof(char));
- szData[wIdx] = 0;
- }
- //去除字符串左边的空格
- VOID StrLTrim(LPSTR szData)
- {
- LPSTR ptr = szData;
- //判断是否为空格
- while (isspace(*ptr))
- ptr++;
- if (strcmp(ptr, szData))
- {
- WORD wLen = (WORD)(strlen(szData) - (ptr - szData));
- memmove(szData, ptr, (wLen+1)*sizeof(char));
- }
- }
- //去除字符串右边的空格
- VOID StrRTrim(LPSTR szData)
- {
- LPSTR ptr = szData;
- LPSTR pTmp = NULL;
- //debug模式下 使用isspace判断中文 需要设置编码
- #if defined(WIN32) && defined(_DEBUG)
- char* locale = setlocale( LC_ALL, ".OCP" );
- #endif
- while (*ptr != 0)
- {
- //判断是否为空格
- if (isspace(*ptr))
- {
- if (!pTmp)
- pTmp = ptr;
- }
- else
- pTmp = NULL;
- ptr++;
- }
- if (pTmp)
- {
- *pTmp = 0;
- memmove(szData, szData, strlen(szData) - strlen(pTmp));
- }
- }
- //从字符串右边开始截取字符串
- VOID StrRight(LPSTR szData, WORD wCount)
- {
- WORD wLen = (WORD)strlen(szData) - wCount;
- if (wCount > 0x7FFF)//负数
- wCount = 0;
- if (wCount >= (WORD)strlen(szData))
- return;
- memmove(szData, szData + wLen, wCount * sizeof(char));
- szData[wCount] = 0;
- }
- VOID ConvertGUIDToString(const GUID guid, LPSTR pData)
- {
- CHAR szData[30] = {0};
- CHAR szTmp[3] = {0};
- WORD wLoop;
- sprintf_s(pData, _countof(szData), "%04X-%02X-%02X-", guid.Data1, guid.Data2, guid.Data3);
- for (wLoop = 0; wLoop < 8; wLoop++)
- {
- if (wLoop == 2)
- strcat_s(szData, "-");
- sprintf_s(szTmp, _countof(szTmp), "%02X", guid.Data4[wLoop]);
- strcat_s(szData, szTmp);
- }
- memcpy(pData + strlen(pData), szData, strlen(szData));
- }
- BOOL AnsiToUnicode(LPCSTR Source, const WORD sLen, LPWSTR Destination, const WORD wLen)
- {
- return MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, Source, sLen, Destination, wLen);
- }
- BOOL UnicodeToAnsi(LPCWSTR Source, const WORD wLen, LPSTR Destination, const WORD sLen)
- {
- return WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, Source, wLen, Destination, sLen, 0L, 0L);
- }
- // 初始化全局变量
- __inline VOID InitialGlobalVar()
- {
- WORD wLoop;
- g_wVender = g_wHardware = 0;
- for (wLoop = 0; wLoop < 20; wLoop++)
- {
- RtlZeroMemory(g_strVender[wLoop], sizeof(TCHAR)*64);
- RtlZeroMemory(g_strHardware[wLoop], sizeof(TCHAR)*64);
- }
- }
- //安装驱动功能
- __inline BOOL IsInstalled()
- {
- HDEVINFO hDevInfo = 0L;
- SP_DEVINFO_DATA spDevInfoData = {0L};
- WORD wIdx;
- BOOL bIsFound;
- //得到设备信息结构的句柄
- hDevInfo = SetupDiGetClassDevs(0L, 0, 0, DIGCF_ALLCLASSES | DIGCF_PRESENT);
- if (hDevInfo == INVALID_HANDLE_VALUE)
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiGetClassDevs"));
- return FALSE;
- }
- spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
- wIdx = 0;
- bIsFound = 0;
- while (++wIdx)
- {
- //找到所有的硬件设备,并且可以得到所有的硬件设备的详细信息
- if (SetupDiEnumDeviceInfo(hDevInfo, wIdx, &spDevInfoData))
- {
- LPTSTR ptr;
- LPBYTE pBuffer = NULL;
- DWORD dwData = 0L;
- DWORD dwRetVal;
- DWORD dwBufSize = 0L;
- while (TRUE)
- {
- //可以在前面得到的指向某一个具体设备信息集合的指针中取出某一项信息
- dwRetVal = SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_HARDWAREID,
- &dwData, (PBYTE)pBuffer, dwBufSize, &dwBufSize);
- if (!dwRetVal)
- dwRetVal = GetLastError();
- else
- break;
- if (dwRetVal == ERROR_INVALID_DATA)
- break;
- else if (dwRetVal == ERROR_INSUFFICIENT_BUFFER)
- {
- if (pBuffer)
- LocalFree(pBuffer);
- pBuffer = (LPBYTE)LocalAlloc(LPTR, dwBufSize);
- }
- else
- {
- ShowErrorMsg(dwRetVal, _T("SetupDiGetDeviceRegistryProperty"));
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- return FALSE;
- }
- }
- if (dwRetVal == ERROR_INVALID_DATA)
- continue;
- for (ptr = (LPTSTR)pBuffer; *ptr && (ptr < (LPTSTR)&pBuffer[dwBufSize]); ptr += _tcslen(ptr) + sizeof(TCHAR))
- {
- WORD wLoop;
- for (wLoop = 0; wLoop < g_wHardware; wLoop++)
- {
- if (!_tcscmp(g_strHardware[wLoop], ptr))
- {
- bIsFound = TRUE;
- break;
- }
- }
- }
- if (pBuffer)
- LocalFree(pBuffer);
- if (bIsFound)
- break;
- }
- }
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- return bIsFound;
- }
- //寻找指定的节名 如果找到返回TRUE 反之返回FALSE
- BOOL FindSectionName(FILE *pFile, const char *szKey)
- {
- char szData[256] = {0};
- if (!pFile)
- return FALSE;
- //将文件内部的位置指针重新指向一个流(数据流/文件)的开头
- rewind(pFile);
- //循环读取文件内容
- while (!feof(pFile))
- {
- //读取一行
- fgets(szData, 255, pFile);
- //去除前后空格
- StrLTrim(szData);
- StrRTrim(szData);
- if (strcmp(szKey, szData) == 0)
- return TRUE;
- }
- return FALSE;
- }
- //得到INF文件中节的数量
- __inline BOOL GetSectionData(FILE* pFile, const char* szKey, const char bIsVender)
- {
- char szData[128] = {0};
- if (bIsVender)
- strcpy_s(szData, szKey);
- else
- sprintf_s(szData, _countof(szData), "[%s]", szKey);
- if (FindSectionName(pFile, szData) == FALSE)
- return FALSE;
- RtlZeroMemory(szData, sizeof(char)*128);
- while (!feof(pFile))
- {
- char *str = NULL;
- fgets(szData, 127, pFile);
- szData[strlen(szData)-1] = 0;
- StrLTrim(szData);
- StrRTrim(szData);
- if (!*szData)
- continue;
- if (szData[0] == ';')
- continue;
- if (strchr(szData, '['))
- {
- StrLTrim(szData);
- if (szData[0] != ';')
- return 1;
- else
- continue;
- }
- if (bIsVender)
- str = strchr(szData, '=');
- else
- str = strchr(szData, ',');
- if (*str)
- {
- char szTmp[128] = {0};
- WORD pos = (WORD)(str - szData + 1);
- StrRight(szData, (short)(strlen(szData)-pos));
- StrLTrim(szData);
- StrRTrim(szData);
- FindComma(szData);
- if (bIsVender)
- {
- AnsiToUnicode(szData, strlen(szData), g_strVender[g_wVender++], 64);
- }
- else
- {
- AnsiToUnicode(szData, strlen(szData), g_strHardware[g_wHardware++], 64);
- }
- }/* end if */
- }
- return TRUE;
- }
- //得到INF文件相关数据
- BOOL GetINFData(FILE *pFile)
- {
- WORD wLoop;
- if (!g_wVender || !g_wHardware)
- InitialGlobalVar();
- if (GetSectionData(pFile, "[Manufacturer]", TRUE) == FALSE)
- return 0;
- for (wLoop = 0; wLoop < g_wVender; wLoop++)
- {
- CHAR szVender[64] = {0};
- UnicodeToAnsi(g_strVender[wLoop], _tcslen(g_strVender[wLoop]), szVender, 64);
- GetSectionData(pFile, szVender, FALSE);
- }
- if (g_wHardware != 0)
- {
- if (IsInstalled() == TRUE)//如果已经安装
- return FALSE;
- else
- return TRUE;
- }
- return FALSE;
- }
- //实质性的安装驱动
- __inline BOOL InstallClassDriver(LPCTSTR theINFName)
- {
- GUID guid = {0};
- SP_DEVINFO_DATA spDevData = {0};
- HDEVINFO hDevInfo = 0L;
- TCHAR className[MAX_CLASS_NAME_LEN] = {0};
- LPTSTR pHID = NULL;
- WORD wLoop;
- BOOL bRebootRequired;
- //取得此驱动的GUID值
- if (!SetupDiGetINFClass(theINFName, &guid, className, MAX_CLASS_NAME_LEN, 0))
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiGetINFClass"));
- return FALSE;
- }
- //创建设备信息块列表
- hDevInfo = SetupDiCreateDeviceInfoList(&guid, 0);
- if (hDevInfo == INVALID_HANDLE_VALUE)
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiCreateDeviceInfoList"));
- return FALSE;
- }
- spDevData.cbSize = sizeof(SP_DEVINFO_DATA);
- //创建设备信息块
- if (!SetupDiCreateDeviceInfo(hDevInfo, className, &guid, 0L, 0L, DICD_GENERATE_ID, &spDevData))
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiCreateDeviceInfo"));
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- return FALSE;
- }
- for (wLoop = 0; wLoop < g_wHardware; wLoop++)
- {
- if (pHID)
- LocalFree(pHID);
- pHID = (LPTSTR)LocalAlloc(LPTR, _tcslen(g_strHardware[wLoop])*2*sizeof(TCHAR));
- if (!pHID)
- {
- ShowErrorMsg(GetLastError(), _T("LocalAlloc"));
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- return FALSE;
- }
- _tcscpy_s(pHID, _tcslen(g_strHardware[wLoop])*2, g_strHardware[wLoop]);
- //设定硬件ID
- if (!SetupDiSetDeviceRegistryProperty(hDevInfo, &spDevData, SPDRP_HARDWAREID, (PBYTE)pHID,
- (DWORD)(_tcslen(g_strHardware[wLoop])*2*sizeof(TCHAR))))
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiSetDeviceRegistryProperty"));
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- LocalFree(pHID);
- return FALSE;
- }
- //调用相应的类程序来注册设备
- if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDevInfo, &spDevData))
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiCallClassInstaller"));
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- LocalFree(pHID);
- return FALSE;
- }
- bRebootRequired = FALSE;
- //安装更新和硬件ID相匹配的驱动程序
- if (!UpdateDriverForPlugAndPlayDevices(0L, g_strHardware[wLoop], theINFName,
- INSTALLFLAG_FORCE, &bRebootRequired))
- {
- DWORD dwErrorCode = GetLastError();
- //调用相应的类程序来移除设备
- if (!SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, &spDevData))
- ShowErrorMsg(GetLastError(), _T("SetupDiCallClassInstaller(Remove)"));
- ShowErrorMsg((WORD)dwErrorCode, _T("UpdateDriverForPlugAndPlayDevices"));
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- LocalFree(pHID);
- return FALSE;
- }
- LocalFree(pHID);
- pHID = NULL;
- }
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- _tprintf(_T("Install Successed\n"));
- return TRUE;
- }
- // 安装WDM驱动的测试工作
- BOOL StartInstallWDMDriver(LPCTSTR theInfName)
- {
- HDEVINFO hDevInfo = 0L;
- GUID guid = {0L};
- SP_DEVINSTALL_PARAMS spDevInst = {0L};
- TCHAR strClass[MAX_CLASS_NAME_LEN] = {0L};
- //取得此驱动的GUID值
- if (!SetupDiGetINFClass(theInfName, &guid, strClass, MAX_CLASS_NAME_LEN, 0))
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiGetINFClass"));
- return FALSE;
- }
- //得到设备信息结构的句柄
- hDevInfo = SetupDiGetClassDevs(&guid, 0L, 0L, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_PROFILE);
- if (!hDevInfo)
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiGetClassDevs"));
- return FALSE;
- }
- spDevInst.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
- //获得指定设备的安装信息
- if (!SetupDiGetDeviceInstallParams(hDevInfo, 0L, &spDevInst))
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiGetDeviceInstallParams"));
- return FALSE;
- }
- spDevInst.Flags = DI_ENUMSINGLEINF;
- spDevInst.FlagsEx = DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
- _tcscpy_s(spDevInst.DriverPath, _countof(spDevInst.DriverPath), theInfName);
- //为设备信息集或者是一个实际的设备信息单元设置或清除类安装参数
- if (!SetupDiSetDeviceInstallParams(hDevInfo, 0, &spDevInst))
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiSetDeviceInstallParams"));
- return FALSE;
- }
- //获取这个设备的驱动程序信息列表
- if (!SetupDiBuildDriverInfoList(hDevInfo, 0, SPDIT_CLASSDRIVER))
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiDeviceInstallParams"));
- return FALSE;
- }
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- //进入安装设备驱动函数
- return InstallClassDriver(theInfName);
- }
- // 卸载WDM驱动
- VOID UninstallWDMDriver(LPCTSTR theHardware)
- {
- SP_DEVINFO_DATA spDevInfoData = {0};
- HDEVINFO hDevInfo = 0L;
- WORD wIdx, wCount = 0;
- //得到设备信息结构的句柄
- hDevInfo = SetupDiGetClassDevs(0L, 0L, 0L, DIGCF_ALLCLASSES | DIGCF_PRESENT);
- if (hDevInfo == INVALID_HANDLE_VALUE)
- {
- ShowErrorMsg(GetLastError(), _T("SetupDiGetClassDevs"));
- return;
- }
- wIdx = 0;
- while (TRUE)
- {
- spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
- //找到所有的硬件设备,并且可以得到所有的硬件设备的详细信息
- if (SetupDiEnumDeviceInfo(hDevInfo, wIdx, &spDevInfoData))
- {
- char Buffer[2048] = {0};
- //可以在前面得到的指向某一个具体设备信息集合的指针中取出某一项信息
- if (SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_HARDWAREID,
- 0L, (PBYTE)Buffer, 2048, 0L))
- {
- if (!_tcscmp(theHardware, (LPTSTR)Buffer))
- {
- //从系统中删除一个注册的设备接口
- if (!SetupDiRemoveDevice(hDevInfo, &spDevInfoData))
- ShowErrorMsg(GetLastError(), _T("SetupDiRemoveDevice"));
- wCount++;
- }
- }
- }
- else
- break;
- wIdx++;
- }
- if (wCount != 0)
- _tprintf(_T("UnInstall Successed\n"));
- //销毁一个设备信息集合
- SetupDiDestroyDeviceInfoList(hDevInfo);
- InitialGlobalVar();
- return;
- }
- //INF文件路径
- const LPTSTR g_pInfPath = _T("C:\\Windows\\System32\\DriverStore\\FileRepository\\mydriver1.inf_x86_neutral_15204d1ef3d409a0\\mydriver1.inf");
- //入口函数
- int _tmain(int argc, _TCHAR* argv[])
- {
- CHAR szInfPath[MAX_PATH] = {0};
- UnicodeToAnsi(g_pInfPath, _tcslen(g_pInfPath), szInfPath, MAX_PATH);
- FILE* pInf;
- errno_t err;
- if ((err=fopen_s(&pInf, szInfPath, "r"))!=0)
- {
- _tprintf(_T("can not open file %s\n"), g_pInfPath);
- return 0;
- }
- // 获取INF文件数据
- GetINFData(pInf);
- fclose(pInf);
- // 安装WDM驱动
- if(_tcscmp(argv[1], TEXT("-Install"))==0)
- {
- if (StartInstallWDMDriver(g_pInfPath) == FALSE)
- {
- _tprintf(_T("Start Install WMD Driver failed\n"));
- return 0;
- }
- }
- // 卸载WDM驱动
- else if(_tcscmp(argv[1], TEXT("-UnInstall"))==0)
- {
- for (WORD wLoop = 0; wLoop < g_wHardware; wLoop++)
- UninstallWDMDriver(g_strHardware[wLoop]);
- }
- return 1;
- }
测试结果:
把相应EXE及其SYS INF文件拷贝的WIN7虚拟机,打开CMD执行WinInstallWin.exe -Install 显示安装成功如图:
再用DeviceTree查看结果:
可以看到设备已经添加成功
在CMD中执行 WinInstallWin.exe -UnInstall 显示卸载成功 如图:
再次使用DeviceTree查看设备 需要刷新一下DeviceTree 结果如图:
先前的设备已经卸载掉了,到此WDM驱动的安装卸载就全部结束了。
- 顶
- 0
- 踩
相关推荐
- 高级C语言教程-中断和设备驱动
- Linux设备驱动之第 2 章 建立和运行模块
- Linux入门(1)_VMware和系统分区和系统安装和远程登陆管理
- Java入门基础:linux centos下安装和配置jdk8
- Maven战笔记 - 01 简介、安装和配置、入门、坐标和依赖、仓库
- Redis 小白指南(一)- 简介、安装、GUI 和 C# 驱动介绍
- Ngnix安装和站点配置基础入门
- Qt入门浅谈-下载和安装
- 日系PLC设备支持的OPC Server入门简介,附OPC Server配置和应用案例PDF
- 《Linux设备驱动开发详解 A》一一2.4 CPLD和FPGA
- Simulink+Webots基于MPC的移动机器人轨迹追踪仿真(1)
- Blender Rigify版Bony绑定下载(Blender 2.83.6)