先搭建内核开发环境 windbg驱动调试的环境搭建。 推荐阅读微软官方文档开始使用 WinDbg(内核模式) - Windows drivers | Microsoft Learn 
windows系统内核调试 环境搭建(保姆级)_dsigntool-CSDN博客 
下载 Windows 驱动程序工具包 (WDK) - Windows drivers | Microsoft Learn 
Windows驱动程序逆向工程方法 - 🔰雨苁ℒ🔰 
驱动开发:WinDBG 配置内核双机调试 - lyshark - 博客园 
备忘录
反调试:
内核下的调试与反调试 - iBinary - 博客园 
总结
一些要用到的命令。
推荐串行接口进行调试
 
符号表环境变量
1 _NT_SYMBOL_PATH         SRV*D:\Myself_Software\Windows_soft\symbols*http://msdl.microsoft.com/download/symbols 
 
windbg内核调试操作
开启调试服务(需要关闭安全引导)
1 2 bcdedit /debug on bcdedit /dbgsettings serial debugport:1 baudrate:115200 
 
windbg attach kernel后重启即可
 
windbg常用快捷键 F5 继续
F10 逐过程
F11 逐语句
Shift+F11 单步跳出
F7 运行到行	
Ctrl + F9 在突出显示的行上切换启用断点状态
Shift + F9  添加断点
Ctrl+Shift+O 打开脚本
Ctrl+Shift+Enter 执行脚本
Ctrl+S 保存脚本
Alt+S、N 新脚本
控制台常用命令 其实控制台可以用鼠标点击选项进行操作。
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 .hh 命令访问参考命令帮助 g 运行 pa [addr] 执行到 .symfix 设置符号表或添加本地符号(.symfix+ path) .reload 加载符号表 (/f添加路径) lm 列出所有模块 lm m name v 特性模块信息 x [Options] Module!Symbol 检查符号 x /D model!name 查找符号可用通配符* sxe ld [name]	拦截模块的加载 e{b|d|q|a|f|D|a} Address [Values] 写入值到内存中 d{a|b|c|d|D|f|p|q|u|w|W} [addr]  打印内存中的值 bl 查看断点 bp	设置一个将一直处于活动状态的断点,直到其所在模块被卸载。 bp /w "@esp < 0x6ff9f8" [addr] 	条件断点 bu	设置一个断点,该断点在卸载模块时未解析,并在重新加载模块时重新启用。 bm	为符号设置一个断点。 此命令适当地使用 bu 或 bp,并允许使用通配符(*)对匹配的每个符号(如类中的所有方法)设置断点。 bc	清除列表中的断点。 使用 bc * 清除所有断点。 bd	禁用断点。 使用 bd * 禁用所有断点。 be	启用断点。 使用 be * 启用所有断点。 ba <access> <size> <address> {options} 设置在访问内存位置时触发的断点(e	执行:当 CPU 从地址中提取指令时。r	读/写:当 CPU 读取或写入地址时。w	write:当 CPU 写入地址时) .bpcmds (显示断点命令) dv 命令来显示给定帧的所有局部变量的名称和值 kp	显示堆栈和参数的完整列表。 kn	允许您查看堆栈以及旁边的帧信息。 !process 调试器扩展来显示或设置进程信息 dv dename!name 查与例程关联的区域设置变量 !process 0 0 显示所有进程的摘要信息。(0 27)输出全部 !thread 命令查看线程 .thread 设置当前线程 r 查看寄存器 !lmi 扩展显示有关模块的详细信息 !dh 扩展显示标头信息 lsf- [filename] 添加源码 .lsrcpath+ 设置本地源路径 .load [dllpath] 加载dll (加载位置待验证) .chain 查看已加载的dll  脚本: .scriptproviders(列出脚本提供程序) .scriptload [jspath](加载脚本) .scriptload(卸载脚本) .scriptrun [jspath](运行脚本) .scriptlist(列出已加载的脚本) 
 
windbg脚本(摘自官方文档JavaScript 调试器脚本 - Windows drivers | Microsoft Learn )
用vscod编写时把C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\JsProvider.d.ts放到当前目录,并在脚本文件前添加
 
js脚本可调用api调试器数据模型 - 代码命名空间 - Windows drivers | Microsoft Learn 
一个框架,来自官方。
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 host.diagnostics .debugLog ("***>; Code at the very top (root) of the script is always run \n" ); function  initializeScript ( ) {               host.diagnostics .debugLog ("***>; initializeScript was called \n" ); } function  invokeScript ( ) {               host.diagnostics .debugLog ("***>; invokeScript was called \n" ); } function  uninitializeScript ( ) {               host.diagnostics .debugLog ("***>; uninitialize was called\n" ); } function  main ( ) {               host.diagnostics .debugLog ("***>; main was called \n" ); } 
 
条件断点
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 "use strict" ; function  invokeScript ( )  {     var  ctl = host.namespace .Debugger .Utility .Control ;          var  address = host.evaluateExpression ("pszCaption" );                    if  (host.memory .readWideString (address) == "Open" ) {                  ctl.ExecuteCommand ("gc" );     }     else      {              }   } 
 
windbg的脚本开发还是挺困难的,教程也比较少微软自己提供了一个项目用于学习microsoft/WinDbg-Samples: Sample extensions, scripts, and API uses for WinDbg. 
另外一个使用脚本hugsy/windbg_js_scripts: Toy scripts for playing with WinDbg JS API 
进阶使用windbgtips (@windbgtips) / X 
时间旅行调试TTD
[InsightEngineering/Time Travel Debugging (TTD) at main · DebugPrivilege/InsightEngineering](https://github.com/DebugPrivilege/InsightEngineering/tree/main/Time  Travel Debugging (TTD))
时间旅行调试 - 概述 - Windows drivers | Microsoft Learn 
[原创]TTD调试与ttd-bindings逆向工程实践-软件逆向-看雪-安全社区|安全招聘|kanxue.com 
驱动开发环境配置 微软的教程非常的好用,下面我只提出几点需要记住的比较重要的事项。
编写 Hello World Windows 驱动程序(内核模式) - Windows drivers | Microsoft Learn 
我这里使用的是windows11 + vs2022的主机和用于调试的windows 10的虚拟机。开发框架采用KWDF。
KWDF是以调用回调函数的来执行操作的,每一个函数都对应一个事件,通过事件的触发来调用回调函数进行数据处理。由于封装的方法较多,开发比较简单。
根据微软的教程,配置好环境,我们在编写完后可以用vs直接把驱动部署在虚拟机上,其中的驱动文件位置在
1 %systemdrive%\drivertest\drivers 
 
把devcon.exe放到虚拟机的驱动位置下,通过命令来进行驱动程序的安装。(需要管理员权限)
1 devcon install XXX.inf root\XXX 
 
root\后面的内容可以在inf文件中找到(驱动程序路径)
1 2 [Standard.NT$ARCH$] %KmdfHelloWorld.DeviceDesc%=KmdfHelloWorld_Device, Root\KmdfHelloWorld 
 
源码调试时用,把pdb文件所在位置设置为本地源路径,.reload后会自动加载源码的符号。
 
在windbg的左上角点击文件,选择source file添加源代码(直接显示源代码窗口),或者用lsf- [filename] 添加源码(无窗口)。根据微软文档的解释,如果使用 WinDbg,只要程序计数器位于调试器具有其源信息的代码中,就会立即显示“源”窗口。即用源代码进行调试。在源模式下调试 - Windows drivers | Microsoft Learn 
跟随官方文档,我们的环境差不多安装完成,接下来正式进行代码编写。
驱动安装 一般驱动 工具安装:Downloads:Driver Loader 
自注册服务:
1 2 3 4 sc create [name] type= kernel start= demand binPath= [path.sys] sc start [name] sc stop [name] sc delete [name] 
 
inf文件:
这里令驱动名字为Driver1,文件为Driver1.sys和Driver1.inf(由vs生成)
devcon安装
1 devcon.exe install XXX.inf root\[name] 
 
右键文件安装也可行。
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 ; ; Driver1.inf ; [Version] Signature   = "$WINDOWS NT$" Class       = System ; TODO: specify appropriate Class ClassGuid   = {4d36e97d-e325-11ce-bfc1-08002be10318} ; TODO: specify appropriate ClassGuid Provider    = %ManufacturerName% CatalogFile = Driver1.cat DriverVer   = ; TODO: set DriverVer in stampinf property pages PnpLockdown = 1 [DestinationDirs] DefaultDestDir = 13 [SourceDisksNames] 1 = %DiskName%,,,"" [SourceDisksFiles] Driver1.sys = 1,, ;***************************************** ; Install Section ;***************************************** [Manufacturer] %ManufacturerName% = Standard,NT$ARCH$.10.0...16299 ; %13% support introduced in build 16299 [Standard.NT$ARCH$.10.0...16299] %Driver1.DeviceDesc% = Driver1_Device, Root\Driver1 ; TODO: edit hw-id [Driver1_Device.NT] CopyFiles = File_Copy [File_Copy] Driver1.sys ;-------------- Service installation [Driver1_Device.NT.Services] AddService = Driver1,%SPSVCINST_ASSOCSERVICE%, Driver1_Service_Inst ; -------------- Driver1 driver install sections [Driver1_Service_Inst] DisplayName    = %Driver1.SVCDESC% ServiceType    = 1               ; SERVICE_KERNEL_DRIVER StartType      = 3               ; SERVICE_DEMAND_START ErrorControl   = 1               ; SERVICE_ERROR_NORMAL ServiceBinary  = %13%\Driver1.sys [Driver1_Device.NT.Wdf] KmdfService = Driver1, Driver1_wdfsect [Driver1_wdfsect] KmdfLibraryVersion = $KMDFVERSION$ [Strings] SPSVCINST_ASSOCSERVICE = 0x00000002 ManufacturerName = "huanghunr" ;TODO: Replace with your manufacturer name DiskName = "Driver1 Installation Disk" Driver1.DeviceDesc = "Driver1 Device" Driver1.SVCDESC = "Driver1 Service" 
 
CTF中的驱动开发结构分析与学习 下面通过一个以diviceiocontrol进行通信的程序为例子分析一个驱动程序的一些主要要素。
Deviceiocontrol:应用程序与驱动程序通信 DeviceIoControl - 沉疴 - 博客园 
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 #include  <ntddk.h>  #include  <wdf.h>  #include  <initguid.h>  #define  Driver_IOCT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) DRIVER_INITIALIZE DriverEntry;  EVT_WDF_DRIVER_DEVICE_ADD HelloKMDFEvtDeviceAdd;  EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL HelloKMDFEvtIoDeviceControl;  NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)  {     WDF_DRIVER_CONFIG config;      WDF_DRIVER_CONFIG_INIT(&config, HelloKMDFEvtDeviceAdd);      KdPrint(("HelloKMDF: DriverEntry\n" ));  	     return  WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE); } NTSTATUS HelloKMDFEvtDeviceAdd (WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)  {     UNREFERENCED_PARAMETER(Driver);     WDFDEVICE device;     NTSTATUS status;          DECLARE_CONST_UNICODE_STRING(devName, L"\\Device\\HelloKMDF" );     WdfDeviceInitAssignName(DeviceInit, &devName);          status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device);     if  (!NT_SUCCESS(status)) return  status;          WDF_IO_QUEUE_CONFIG ioQueueConfig;     WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential);     ioQueueConfig.EvtIoDeviceControl = HelloKMDFEvtIoDeviceControl;     return  WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); } VOID HelloKMDFEvtIoDeviceControl (WDFQUEUE Queue, WDFREQUEST Request,                                   size_t  OutputBufferLength, size_t  InputBufferLength,                                  ULONG IoControlCode)  {    UNREFERENCED_PARAMETER(Queue);     UNREFERENCED_PARAMETER(OutputBufferLength);     UNREFERENCED_PARAMETER(InputBufferLength);     if  (IoControlCode == IOCTL_HELLOKMDF) {         KdPrint(("HelloKMDF: 收到 IOCTL_HELLOKMDF 指令!\n" ));     }     WdfRequestComplete(Request, STATUS_SUCCESS); } 
 
之后再去了解一下其他通信,总结点模板。