DriverEntry.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // DriverEntry.cpp - KMDF 驱动入口
  2. // 职责:初始化 WDF 驱动对象、注册 EvtDeviceAdd(PnP 过滤驱动)
  3. // 创建控制设备 \\.\CommModifyKit 接收 DLL 的 IOCTL
  4. // 注意:本驱动作为串口设备类的 UpperFilters 加载
  5. // 当 PnP Manager 创建串口 PDO 时,调用 EvtDeviceAdd attach 过滤设备
  6. #include <ntddk.h>
  7. #include <wdf.h>
  8. #include <initguid.h> // 必须在包含定义 GUID 的头文件之前
  9. #include <ntddser.h> // GUID_DEVINTERFACE_COMPORT
  10. #include "DeviceContext.h"
  11. #include "QueueCallback.h"
  12. #include "ClientConnection.h"
  13. #include "SerialFilter.h"
  14. extern "C" {
  15. DRIVER_INITIALIZE DriverEntry;
  16. EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd;
  17. EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
  18. EVT_WDF_OBJECT_CONTEXT_CLEANUP EvtDeviceContextCleanup;
  19. } // extern "C"
  20. // PnP 回调使用 C++ 链接(WDF 宏内部处理)
  21. EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware;
  22. namespace commkit_driver {
  23. // 全局驱动对象(仅用于内部日志/调试)
  24. static WDFDRIVER g_wdf_driver = nullptr;
  25. } // namespace commkit_driver
  26. extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object,
  27. PUNICODE_STRING registry_path) {
  28. DbgPrint("[CommModifyKit] DriverEntry ENTERED\n");
  29. NTSTATUS status;
  30. WDF_DRIVER_CONFIG cfg;
  31. // 初始化全局客户端连接管理器
  32. commkit_driver::GetClientConnection().Initialize();
  33. // 初始化 WDF 配置
  34. WDF_DRIVER_CONFIG_INIT(&cfg, EvtDeviceAdd);
  35. cfg.EvtDriverUnload = EvtDriverUnload;
  36. // 创建 WDF 驱动对象
  37. status = WdfDriverCreate(driver_object, registry_path,
  38. WDF_NO_OBJECT_ATTRIBUTES, &cfg,
  39. &commkit_driver::g_wdf_driver);
  40. if (!NT_SUCCESS(status)) {
  41. return status;
  42. }
  43. // 初始化 ClientConnection(创建控制设备)
  44. status = commkit_driver::CreateControlDevice(commkit_driver::g_wdf_driver);
  45. if (!NT_SUCCESS(status)) {
  46. DbgPrint("[CommModifyKit] CreateControlDevice FAILED 0x%08X\n", status);
  47. return status;
  48. }
  49. DbgPrint("[CommModifyKit] DriverEntry OK, EvtDeviceAdd registered\n");
  50. return STATUS_SUCCESS;
  51. }
  52. extern "C" NTSTATUS EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT init) {
  53. UNREFERENCED_PARAMETER(driver);
  54. InterlockedIncrement(&g_diag_evt_device_add_count);
  55. NTSTATUS status;
  56. // 1. 标记为过滤设备
  57. WdfFdoInitSetFilter(init);
  58. // 2. 注册 PnP 电源回调
  59. WDF_PNPPOWER_EVENT_CALLBACKS pnp_callbacks;
  60. WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_callbacks);
  61. pnp_callbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware;
  62. WdfDeviceInitSetPnpPowerEventCallbacks(init, &pnp_callbacks);
  63. // 3. 注册 WDM IRP 预处理回调
  64. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  65. init, commkit_driver::SerialFilter::DispatchRead,
  66. IRP_MJ_READ, nullptr, 0);
  67. if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
  68. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  69. init, commkit_driver::SerialFilter::DispatchWrite,
  70. IRP_MJ_WRITE, nullptr, 0);
  71. if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
  72. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  73. init, commkit_driver::SerialFilter::DispatchDeviceControl,
  74. IRP_MJ_DEVICE_CONTROL, nullptr, 0);
  75. if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
  76. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  77. init, commkit_driver::SerialFilter::DispatchCreate,
  78. IRP_MJ_CREATE, nullptr, 0);
  79. if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
  80. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  81. init, commkit_driver::SerialFilter::DispatchClose,
  82. IRP_MJ_CLOSE, nullptr, 0);
  83. if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
  84. status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
  85. init, commkit_driver::SerialFilter::DispatchCleanup,
  86. IRP_MJ_CLEANUP, nullptr, 0);
  87. if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
  88. InterlockedIncrement(&g_diag_irp_preprocess_ok);
  89. // 4. SDDL: WDF filter device 不支持 WdfDeviceInitAssignSDDLString
  90. // 它会返回 STATUS_INVALID_SECURITY_DESCR (0xC0000079)
  91. // Filter device 会继承下层设备 (serial.sys) 的安全描述符
  92. // 不需要显式设置 SDDL
  93. InterlockedIncrement(&g_diag_sddl_ok);
  94. // 5. 创建 WDF 设备
  95. WDFDEVICE device;
  96. WDF_OBJECT_ATTRIBUTES attrs;
  97. WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, DEVICE_CONTEXT);
  98. attrs.EvtCleanupCallback = EvtDeviceContextCleanup;
  99. status = WdfDeviceCreate(&init, &attrs, &device);
  100. if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
  101. InterlockedIncrement(&g_diag_device_create_ok);
  102. // 6. 初始化设备上下文
  103. PDEVICE_CONTEXT ctx = DeviceGetContext(device);
  104. ctx->ComNumber = 0;
  105. ctx->MonitoringEnabled = FALSE;
  106. ctx->RingBuffer = nullptr;
  107. ctx->WdfDevice = device;
  108. ctx->LowerDevice = WdfDeviceWdmGetAttachedDevice(device);
  109. // 7. 注册到全局端口表
  110. commkit_driver::GetClientConnection().RegisterFilterDevice(device);
  111. return STATUS_SUCCESS;
  112. }
  113. NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
  114. WDFCMRESLIST resources,
  115. WDFCMRESLIST resources_translated) {
  116. UNREFERENCED_PARAMETER(resources);
  117. UNREFERENCED_PARAMETER(resources_translated);
  118. NTSTATUS status;
  119. PDEVICE_CONTEXT ctx = DeviceGetContext(device);
  120. InterlockedIncrement(&g_diag_prepare_hardware_count);
  121. // 从 PnP 属性解析 COM 编号
  122. // 方式:获取 DevicePropertyFriendlyName 或 DevicePropertyDeviceDescription,
  123. // 匹配 "COM%d" 模式
  124. WDFMEMORY memory;
  125. status = WdfDeviceAllocAndQueryProperty(
  126. device, DevicePropertyFriendlyName, NonPagedPoolNx, 0, &memory);
  127. if (!NT_SUCCESS(status)) {
  128. // 尝试 DeviceDescription 作为后备
  129. status = WdfDeviceAllocAndQueryProperty(
  130. device, DevicePropertyDeviceDescription, NonPagedPoolNx, 0, &memory);
  131. }
  132. if (NT_SUCCESS(status)) {
  133. PWCHAR name = (PWCHAR)WdfMemoryGetBuffer(memory, nullptr);
  134. if (name) {
  135. // 打印 FriendlyName/DeviceDescription 前 40 字符用于诊断
  136. DbgPrint("[CommModifyKit] FriendlyName='%ws'\n", name);
  137. // 解析 "COMx" 模式(可能出现在 "COMx (port)" 或 "通信端口 (COMx)" 等格式中)
  138. ULONG name_len = (ULONG)wcslen(name);
  139. for (ULONG i = 0; i + 3 <= name_len; i++) {
  140. if ((name[i] == L'C' || name[i] == L'c') &&
  141. (name[i+1] == L'O' || name[i+1] == L'o') &&
  142. (name[i+2] == L'M' || name[i+2] == L'm')) {
  143. if (name[i+3] >= L'0' && name[i+3] <= L'9') {
  144. ULONG num = 0;
  145. ULONG j = i + 3;
  146. while (j < name_len && name[j] >= L'0' && name[j] <= L'9') {
  147. num = num * 10 + (name[j] - L'0');
  148. j++;
  149. }
  150. if (num > 0 && num <= 256) {
  151. ctx->ComNumber = num;
  152. break;
  153. }
  154. }
  155. }
  156. }
  157. }
  158. WdfObjectDelete(memory);
  159. }
  160. // 后备方案:FriendlyName/DeviceDescription 均未解析出 COM 编号时,
  161. // 从 PDO 名称查询 HKLM\HARDWARE\DEVICEMAP\SERIALCOMM 获取 "COMx" 映射
  162. if (ctx->ComNumber == 0) {
  163. WDFMEMORY pdo_memory;
  164. status = WdfDeviceAllocAndQueryProperty(
  165. device, DevicePropertyPhysicalDeviceObjectName,
  166. NonPagedPoolNx, 0, &pdo_memory);
  167. if (NT_SUCCESS(status)) {
  168. PWCHAR pdo_name = (PWCHAR)WdfMemoryGetBuffer(pdo_memory, nullptr);
  169. if (pdo_name && pdo_name[0] != L'\0') {
  170. UNICODE_STRING key_path;
  171. RtlInitUnicodeString(&key_path,
  172. L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\SERIALCOMM");
  173. OBJECT_ATTRIBUTES obj_attr;
  174. InitializeObjectAttributes(&obj_attr, &key_path,
  175. OBJ_CASE_INSENSITIVE, nullptr, nullptr);
  176. HANDLE hkey;
  177. status = ZwOpenKey(&hkey, KEY_READ, &obj_attr);
  178. if (NT_SUCCESS(status)) {
  179. UNICODE_STRING value_name;
  180. RtlInitUnicodeString(&value_name, pdo_name);
  181. UCHAR result_buf[256] = {0};
  182. ULONG result_len = 0;
  183. status = ZwQueryValueKey(hkey, &value_name,
  184. KeyValuePartialInformation,
  185. result_buf, sizeof(result_buf), &result_len);
  186. if (NT_SUCCESS(status)) {
  187. KEY_VALUE_PARTIAL_INFORMATION* kv_info =
  188. (KEY_VALUE_PARTIAL_INFORMATION*)result_buf;
  189. if (kv_info->Type == REG_SZ && kv_info->DataLength >= sizeof(WCHAR)) {
  190. PWCHAR com_name = (PWCHAR)kv_info->Data;
  191. ULONG com_len = kv_info->DataLength / sizeof(WCHAR);
  192. // 解析 "COMx"
  193. if (com_len >= 4 &&
  194. (com_name[0] == L'C' || com_name[0] == L'c') &&
  195. (com_name[1] == L'O' || com_name[1] == L'o') &&
  196. (com_name[2] == L'M' || com_name[2] == L'm') &&
  197. com_name[3] >= L'0' && com_name[3] <= L'9') {
  198. ULONG num = 0;
  199. ULONG j = 3;
  200. while (j < com_len &&
  201. com_name[j] >= L'0' && com_name[j] <= L'9') {
  202. num = num * 10 + (com_name[j] - L'0');
  203. j++;
  204. }
  205. if (num > 0 && num <= 256) {
  206. ctx->ComNumber = num;
  207. }
  208. }
  209. }
  210. }
  211. ZwClose(hkey);
  212. }
  213. }
  214. WdfObjectDelete(pdo_memory);
  215. }
  216. }
  217. // 后备方案 2:查询本设备注册的 GUID_DEVINTERFACE_COMPORT 接口
  218. // 虚拟串口可能不在 SERIALCOMM 中,但会注册 COMPORT 接口
  219. // 注意:必须传入本设备 PDO,不能传 nullptr 枚举所有设备后用 IoGetDeviceObjectPointer 打开,
  220. // 因为那会发送 IRP_MJ_CREATE 到正在初始化的设备栈,导致死锁
  221. if (ctx->ComNumber == 0) {
  222. PDEVICE_OBJECT currentPdo = WdfDeviceWdmGetPhysicalDevice(device);
  223. if (currentPdo) {
  224. PWSTR interfaceList = nullptr;
  225. status = IoGetDeviceInterfaces(
  226. &GUID_DEVINTERFACE_COMPORT,
  227. currentPdo, // 仅查询本设备的接口
  228. DEVICE_INTERFACE_INCLUDE_NONACTIVE,
  229. &interfaceList);
  230. if (NT_SUCCESS(status) && interfaceList) {
  231. PWCHAR p = interfaceList;
  232. while (*p && ctx->ComNumber == 0) {
  233. ULONG len = (ULONG)wcslen(p);
  234. // 从符号链接路径解析 COM 编号(如 "\\?\COM12")
  235. for (ULONG i = 0; i + 3 <= len; i++) {
  236. if ((p[i] == L'C' || p[i] == L'c') &&
  237. (p[i+1] == L'O' || p[i+1] == L'o') &&
  238. (p[i+2] == L'M' || p[i+2] == L'm') &&
  239. p[i+3] >= L'0' && p[i+3] <= L'9') {
  240. ULONG num = 0;
  241. ULONG j = i + 3;
  242. while (j < len && p[j] >= L'0' && p[j] <= L'9') {
  243. num = num * 10 + (p[j] - L'0');
  244. j++;
  245. }
  246. if (num > 0 && num <= 256) {
  247. ctx->ComNumber = num;
  248. break;
  249. }
  250. }
  251. }
  252. p += len + 1;
  253. }
  254. ExFreePool(interfaceList);
  255. }
  256. }
  257. }
  258. // 更新端口表中的 COM 编号
  259. commkit_driver::GetClientConnection().UpdatePortComNumber(device, ctx->ComNumber);
  260. DbgPrint("[CommModifyKit] EvtDevicePrepareHardware OK, ComNumber=%u\n", ctx->ComNumber);
  261. return STATUS_SUCCESS;
  262. }
  263. // 设备上下文清理回调:设备移除时注销端口表条目
  264. VOID EvtDeviceContextCleanup(WDFOBJECT object) {
  265. WDFDEVICE device = (WDFDEVICE)object;
  266. PDEVICE_CONTEXT ctx = DeviceGetContext(device);
  267. if (ctx && ctx->ComNumber != 0) {
  268. commkit_driver::GetClientConnection().UnregisterFilterDevice(ctx->ComNumber);
  269. }
  270. }
  271. extern "C" VOID EvtDriverUnload(WDFDRIVER driver) {
  272. UNREFERENCED_PARAMETER(driver);
  273. commkit_driver::GetClientConnection().Cleanup();
  274. commkit_driver::g_wdf_driver = nullptr;
  275. }