友链
hellodriver
使用VS2019
项目地址
代码
// I don't like NTSTATUS, it like shit
typedef NTSTATUS _nt;/*
your driver must implement two basic event callback fucnions at least
which is:- DRIVER_INITIALIZE DriverEntry- EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd
*/// these two head files must be included in your driver code
// contains win kernel definitions for all drivers
#include <ntddk.h>
// contains win kernel definitions for drivers those who are based on WDF
#include <wdf.h>// both DRIVER_INITIALIZE and EVT_WDF_DRIVER_DEVICE_ADD are function type with parameter and return value declared, see this: https://blog.csdn.net/ma_de_hao_mei_le/article/details/126246225
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;// then DriverEntry function
// this is the main function in user mode code
// everytime we want to analyse a drvier, we need to check this function to know how does it work
_nt DriverEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath
)
{// this is the return value// well STATUS_SUCCESS macro sucks, it is too long, I prefer to use 0_nt status = 0;// idk what the fuck is this// the document from MS says it is driver configuration object, which indeed is a structWDF_DRIVER_CONFIG config;// let's print some thing, only visible for debugger// idk what is the usage of commentid and levelKdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n"));// initialize driver configuration object to register entry point for one of the call back function we mentioned at the beginning// the other call back is EntryPoint// it doesn't need to be registered// it will be called automatically if certain event comesWDF_DRIVER_CONFIG_INIT(&config,KmdfHelloWorldEvtDeviceAdd);// at last, we create driver objectstatus = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&config,WDF_NO_HANDLE);return status;
}// now we need to implement our KmdfHelloWorldEvtDeviceAdd callback function
// EvtDeviceAdd will be invoked by system when your device has arrived
// what does the doc mean when it say "your device"?
// what the fuck is "your device"?
// idk what is my device and how it arrives
// this function will initialize structures and resources that this device will use, and create device object for it
// MS doc recommends to name this EvtDeviceAdd function with a prefix, and the driver name should be this prefix
// now I understand, device arriving when you click enable in devmanager
_nt KmdfHelloWorldEvtDeviceAdd(_In_ WDFDRIVER Driver,_Inout_ PWDFDEVICE_INIT DeviceInit
)
{// the first parameter is useless because we're not going to use it// so we need to mark it as unreferenced// I'm not sure what is the point to do this// because I've never seen this in user mode C codeUNREFERENCED_PARAMETER(Driver);// allocate device object// here is how WDFDEVICE is declared https://blog.csdn.net/ma_de_hao_mei_le/article/details/126247434WDFDEVICE hDevice;// print some thing in debugger so we know that this function is executedKdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n"));_nt status = WdfDeviceCreate(&DeviceInit,WDF_NO_OBJECT_ATTRIBUTES,&hDevice);return status;
}
构建完成后在项目目录下可以找到以下几个文件
sys是驱动文件,inf是安装驱动的时候用的文件,cat是installer用于验证驱动的测试签名的文件
部署驱动
本来VS是有自动化部署的功能的,但是我玩不明白,所以只能用笨方法,手动部署
把签名给禁了先
bcdedit /set testsigning on
然后重启
把vs生成的三个文件全拖到测试机上,然后把开发机上的devcon.exe拷到测试机,注意devcon.exe的位数,要和测试机一样
然后执行如下命令进行安装即可
devcon install hellodriver.inf root\hellodriver
调试驱动程序
微软官方给了例子
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debug-universal-drivers—step-by-step-lab–echo-kernel-mode-#connectto
例子的代码可以在这里下载
这个项目会生成两个驱动程序,echo和echo_2,我们只需要看echo就行了,echo_2不用管
使用devcon把echo装上去之后,在debugger机器上把内核调试弄好,然后把echo.pdb文件的路径加到符号路径即可
.symfix
.sympath+ /path/to/echo.pdb
!sym noisy
.reload /flmvm echo
如果可以查看到如下信息,说明就成功了
可以使用!devnode 0 1命令来显示设备节点树,如果你的设备没有出现在里面,那说明你安装失败了
可以看到我们的设备是可以显示在这里面的
上面输出中的PDO是一个地址,我们可以使用!devobj PDO来查看与该驱动关联的即插即用设备信息
pdo地址是和驱动运行实例相关联的,使用!devstack pdo可以查看一驱动栈信息
源码调试
.srcpath+ 驱动程序的源代码所在路径。
在evtdeviceadd函数下断点
然后在debugee中禁用设备,然后再启用设备即可触发该断点