|
|
@@ -10,7 +10,9 @@
|
|
|
#include "DeviceContext.h"
|
|
|
#include "QueueCallback.h"
|
|
|
#include "ClientConnection.h"
|
|
|
-#include "SerialFilter.h"
|
|
|
+#include "SerialFilter.h" // g_sequence_counter
|
|
|
+#include "EventRingBuffer.h" // EventRingBuffer
|
|
|
+#include "../common/CommKitEvents.h" // COMMKIT_OP_OPEN / OP_CLOSE
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
@@ -67,56 +69,68 @@ extern "C" NTSTATUS EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT init) {
|
|
|
UNREFERENCED_PARAMETER(driver);
|
|
|
|
|
|
InterlockedIncrement(&g_diag_evt_device_add_count);
|
|
|
+ DbgPrint("[CommModifyKit] >>> EvtDeviceAdd ENTER (count=%ld)\n", g_diag_evt_device_add_count);
|
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
// 1. 标记为过滤设备
|
|
|
WdfFdoInitSetFilter(init);
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: WdfFdoInitSetFilter OK\n");
|
|
|
|
|
|
// 2. 注册 PnP 电源回调
|
|
|
WDF_PNPPOWER_EVENT_CALLBACKS pnp_callbacks;
|
|
|
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_callbacks);
|
|
|
pnp_callbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware;
|
|
|
WdfDeviceInitSetPnpPowerEventCallbacks(init, &pnp_callbacks);
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: PnpPower callbacks registered\n");
|
|
|
+
|
|
|
+ // 2.5 不使用 WdfDeviceInitSetFileObjectConfig
|
|
|
+ // -----------------------------------------------
|
|
|
+ // 原因:WdfDeviceInitSetFileObjectConfig 会让 WDF 为每个 CREATE 创建
|
|
|
+ // WDFFILEOBJECT,并在 WdfDeviceWdmDispatchPreprocessedIrp 中强制查找它。
|
|
|
+ // 当 WDFFILEOBJECT 查找失败时(异步 SEND_AND_FORGET 转发时序问题、
|
|
|
+ // 或 FileObject 不匹配),WDF 返回 STATUS_FILE_FORCED_CLOSED (0xC0000182),
|
|
|
+ // 导致其他工具的 READ/WRITE IRP 全部失败。
|
|
|
+ //
|
|
|
+ // 改用 IRP_MJ_CREATE/CLOSE 预处理回调手动追踪文件打开/关闭和捕获 FileObject。
|
|
|
+ // 没有 WdfDeviceInitSetFileObjectConfig,WdfDeviceWdmDispatchPreprocessedIrp
|
|
|
+ // 不再查找 WDFFILEOBJECT,直接转发 IRP 到下层设备。
|
|
|
|
|
|
// 3. 注册 WDM IRP 预处理回调
|
|
|
- status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
|
|
|
- init, commkit_driver::SerialFilter::DispatchRead,
|
|
|
- IRP_MJ_READ, nullptr, 0);
|
|
|
- if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
|
|
|
-
|
|
|
- status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
|
|
|
- init, commkit_driver::SerialFilter::DispatchWrite,
|
|
|
- IRP_MJ_WRITE, nullptr, 0);
|
|
|
- if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
|
|
|
-
|
|
|
- status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
|
|
|
- init, commkit_driver::SerialFilter::DispatchDeviceControl,
|
|
|
- IRP_MJ_DEVICE_CONTROL, nullptr, 0);
|
|
|
- if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
|
|
|
-
|
|
|
status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
|
|
|
init, commkit_driver::SerialFilter::DispatchCreate,
|
|
|
IRP_MJ_CREATE, nullptr, 0);
|
|
|
if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: IRP_MJ_CREATE preprocess registered\n");
|
|
|
|
|
|
status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
|
|
|
init, commkit_driver::SerialFilter::DispatchClose,
|
|
|
IRP_MJ_CLOSE, nullptr, 0);
|
|
|
if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: IRP_MJ_CLOSE preprocess registered\n");
|
|
|
|
|
|
status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
|
|
|
- init, commkit_driver::SerialFilter::DispatchCleanup,
|
|
|
- IRP_MJ_CLEANUP, nullptr, 0);
|
|
|
+ init, commkit_driver::SerialFilter::DispatchRead,
|
|
|
+ IRP_MJ_READ, nullptr, 0);
|
|
|
if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: IRP_MJ_READ preprocess registered\n");
|
|
|
|
|
|
+ status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
|
|
|
+ init, commkit_driver::SerialFilter::DispatchWrite,
|
|
|
+ IRP_MJ_WRITE, nullptr, 0);
|
|
|
+ if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: IRP_MJ_WRITE preprocess registered\n");
|
|
|
+
|
|
|
+ // IRP_MJ_CLEANUP / IRP_MJ_DEVICE_CONTROL 不注册预处理回调。
|
|
|
+ // CLEANUP 由 WDF 自动转发(过滤驱动模式)。
|
|
|
+ // DEVICE_CONTROL 由 WDF 自动转发给下层设备,串口 IOCTL(波特率/DCB 等)
|
|
|
+ // 由虚拟串口驱动直接处理。
|
|
|
InterlockedIncrement(&g_diag_irp_preprocess_ok);
|
|
|
|
|
|
// 4. SDDL: WDF filter device 不支持 WdfDeviceInitAssignSDDLString
|
|
|
// 它会返回 STATUS_INVALID_SECURITY_DESCR (0xC0000079)
|
|
|
// Filter device 会继承下层设备 (serial.sys) 的安全描述符
|
|
|
// 不需要显式设置 SDDL
|
|
|
- InterlockedIncrement(&g_diag_sddl_ok);
|
|
|
|
|
|
// 5. 创建 WDF 设备
|
|
|
WDFDEVICE device;
|
|
|
@@ -124,8 +138,14 @@ extern "C" NTSTATUS EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT init) {
|
|
|
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, DEVICE_CONTEXT);
|
|
|
attrs.EvtCleanupCallback = EvtDeviceContextCleanup;
|
|
|
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: calling WdfDeviceCreate...\n");
|
|
|
status = WdfDeviceCreate(&init, &attrs, &device);
|
|
|
- if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
|
|
|
+ if (!NT_SUCCESS(status)) {
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: WdfDeviceCreate FAILED 0x%08X\n", status);
|
|
|
+ InterlockedExchange(&g_diag_last_failure_status, status);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: WdfDeviceCreate OK device=%p\n", device);
|
|
|
|
|
|
InterlockedIncrement(&g_diag_device_create_ok);
|
|
|
|
|
|
@@ -136,9 +156,25 @@ extern "C" NTSTATUS EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT init) {
|
|
|
ctx->RingBuffer = nullptr;
|
|
|
ctx->WdfDevice = device;
|
|
|
ctx->LowerDevice = WdfDeviceWdmGetAttachedDevice(device);
|
|
|
+ ctx->SavedFileObject = nullptr;
|
|
|
+ KeInitializeSpinLock(&ctx->FileObjectLock);
|
|
|
+
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: ctx initialized, LowerDevice=%p\n", ctx->LowerDevice);
|
|
|
+
|
|
|
+ // 注意:不再设置过滤设备 / 下层设备的 SecurityDescriptor。
|
|
|
+ // 之前直接覆盖 ctx->LowerDevice->SecurityDescriptor 是严重错误:
|
|
|
+ // 1. 下层设备不归本驱动管理(由虚拟串口驱动创建)
|
|
|
+ // 2. 原始 SD 内存被泄漏
|
|
|
+ // 3. 时机错误:EvtDeviceAdd 中下层设备可能未完成初始化
|
|
|
+ // 4. 破坏下层驱动的内部状态,导致 CreateFile 异常失败
|
|
|
+ // 过滤设备是未命名的,其 SD 不参与 CreateFile 的安全检查
|
|
|
+ // (I/O Manager 查的是命名设备即下层 FDO 的 SD)。
|
|
|
+ // 若需放宽非 elevated 进程的访问权限,应通过 INF 文件在设备类
|
|
|
+ // 注册表项 HKLM\...\Control\Class\{Ports GUID}\Security 中设置。
|
|
|
|
|
|
// 7. 注册到全局端口表
|
|
|
commkit_driver::GetClientConnection().RegisterFilterDevice(device);
|
|
|
+ DbgPrint("[CommModifyKit] EvtDeviceAdd: RegisterFilterDevice done, EvtDeviceAdd COMPLETE\n");
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
}
|
|
|
@@ -153,6 +189,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
PDEVICE_CONTEXT ctx = DeviceGetContext(device);
|
|
|
|
|
|
InterlockedIncrement(&g_diag_prepare_hardware_count);
|
|
|
+ DbgPrint("[CommModifyKit] EvtDevicePrepareHardware ENTER\n");
|
|
|
|
|
|
// 从 PnP 属性解析 COM 编号
|
|
|
// 方式:获取 DevicePropertyFriendlyName 或 DevicePropertyDeviceDescription,
|
|
|
@@ -161,6 +198,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
status = WdfDeviceAllocAndQueryProperty(
|
|
|
device, DevicePropertyFriendlyName, NonPagedPoolNx, 0, &memory);
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: FriendlyName query failed 0x%08X, trying DeviceDescription\n", status);
|
|
|
// 尝试 DeviceDescription 作为后备
|
|
|
status = WdfDeviceAllocAndQueryProperty(
|
|
|
device, DevicePropertyDeviceDescription, NonPagedPoolNx, 0, &memory);
|
|
|
@@ -170,7 +208,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
PWCHAR name = (PWCHAR)WdfMemoryGetBuffer(memory, nullptr);
|
|
|
if (name) {
|
|
|
// 打印 FriendlyName/DeviceDescription 前 40 字符用于诊断
|
|
|
- DbgPrint("[CommModifyKit] FriendlyName='%ws'\n", name);
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: name='%ws'\n", name);
|
|
|
// 解析 "COMx" 模式(可能出现在 "COMx (port)" 或 "通信端口 (COMx)" 等格式中)
|
|
|
ULONG name_len = (ULONG)wcslen(name);
|
|
|
for (ULONG i = 0; i + 3 <= name_len; i++) {
|
|
|
@@ -186,6 +224,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
}
|
|
|
if (num > 0 && num <= 256) {
|
|
|
ctx->ComNumber = num;
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: parsed COM%u from name\n", num);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -198,6 +237,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
// 后备方案:FriendlyName/DeviceDescription 均未解析出 COM 编号时,
|
|
|
// 从 PDO 名称查询 HKLM\HARDWARE\DEVICEMAP\SERIALCOMM 获取 "COMx" 映射
|
|
|
if (ctx->ComNumber == 0) {
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: trying SERIALCOMM registry fallback\n");
|
|
|
WDFMEMORY pdo_memory;
|
|
|
status = WdfDeviceAllocAndQueryProperty(
|
|
|
device, DevicePropertyPhysicalDeviceObjectName,
|
|
|
@@ -205,6 +245,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
PWCHAR pdo_name = (PWCHAR)WdfMemoryGetBuffer(pdo_memory, nullptr);
|
|
|
if (pdo_name && pdo_name[0] != L'\0') {
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: PDO name='%ws'\n", pdo_name);
|
|
|
UNICODE_STRING key_path;
|
|
|
RtlInitUnicodeString(&key_path,
|
|
|
L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\SERIALCOMM");
|
|
|
@@ -229,6 +270,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
if (kv_info->Type == REG_SZ && kv_info->DataLength >= sizeof(WCHAR)) {
|
|
|
PWCHAR com_name = (PWCHAR)kv_info->Data;
|
|
|
ULONG com_len = kv_info->DataLength / sizeof(WCHAR);
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: SERIALCOMM value='%ws'\n", com_name);
|
|
|
// 解析 "COMx"
|
|
|
if (com_len >= 4 &&
|
|
|
(com_name[0] == L'C' || com_name[0] == L'c') &&
|
|
|
@@ -244,11 +286,16 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
}
|
|
|
if (num > 0 && num <= 256) {
|
|
|
ctx->ComNumber = num;
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: parsed COM%u from SERIALCOMM\n", num);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ } else {
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: SERIALCOMM query failed 0x%08X\n", status);
|
|
|
}
|
|
|
ZwClose(hkey);
|
|
|
+ } else {
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: ZwOpenKey(SERIALCOMM) failed 0x%08X\n", status);
|
|
|
}
|
|
|
}
|
|
|
WdfObjectDelete(pdo_memory);
|
|
|
@@ -260,6 +307,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
// 注意:必须传入本设备 PDO,不能传 nullptr 枚举所有设备后用 IoGetDeviceObjectPointer 打开,
|
|
|
// 因为那会发送 IRP_MJ_CREATE 到正在初始化的设备栈,导致死锁
|
|
|
if (ctx->ComNumber == 0) {
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: trying GUID_DEVINTERFACE_COMPORT fallback\n");
|
|
|
PDEVICE_OBJECT currentPdo = WdfDeviceWdmGetPhysicalDevice(device);
|
|
|
if (currentPdo) {
|
|
|
PWSTR interfaceList = nullptr;
|
|
|
@@ -272,6 +320,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
PWCHAR p = interfaceList;
|
|
|
while (*p && ctx->ComNumber == 0) {
|
|
|
ULONG len = (ULONG)wcslen(p);
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: interface='%ws'\n", p);
|
|
|
// 从符号链接路径解析 COM 编号(如 "\\?\COM12")
|
|
|
for (ULONG i = 0; i + 3 <= len; i++) {
|
|
|
if ((p[i] == L'C' || p[i] == L'c') &&
|
|
|
@@ -286,6 +335,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
}
|
|
|
if (num > 0 && num <= 256) {
|
|
|
ctx->ComNumber = num;
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: parsed COM%u from interface\n", num);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -293,6 +343,8 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
p += len + 1;
|
|
|
}
|
|
|
ExFreePool(interfaceList);
|
|
|
+ } else {
|
|
|
+ DbgPrint("[CommModifyKit] PrepareHardware: IoGetDeviceInterfaces failed 0x%08X or empty\n", status);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -300,7 +352,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
// 更新端口表中的 COM 编号
|
|
|
commkit_driver::GetClientConnection().UpdatePortComNumber(device, ctx->ComNumber);
|
|
|
|
|
|
- DbgPrint("[CommModifyKit] EvtDevicePrepareHardware OK, ComNumber=%u\n", ctx->ComNumber);
|
|
|
+ DbgPrint("[CommModifyKit] EvtDevicePrepareHardware COMPLETE, ComNumber=%u\n", ctx->ComNumber);
|
|
|
return STATUS_SUCCESS;
|
|
|
}
|
|
|
|
|
|
@@ -308,11 +360,29 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
|
|
|
VOID EvtDeviceContextCleanup(WDFOBJECT object) {
|
|
|
WDFDEVICE device = (WDFDEVICE)object;
|
|
|
PDEVICE_CONTEXT ctx = DeviceGetContext(device);
|
|
|
- if (ctx && ctx->ComNumber != 0) {
|
|
|
+ if (!ctx) return;
|
|
|
+
|
|
|
+ // 释放保存的 FileObject
|
|
|
+ KIRQL old_irql;
|
|
|
+ KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
|
|
|
+ PFILE_OBJECT saved = ctx->SavedFileObject;
|
|
|
+ ctx->SavedFileObject = nullptr;
|
|
|
+ KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
|
|
|
+ if (saved) {
|
|
|
+ ObDereferenceObject(saved);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ctx->ComNumber != 0) {
|
|
|
commkit_driver::GetClientConnection().UnregisterFilterDevice(ctx->ComNumber);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 文件打开/关闭/数据捕获现在通过 IRP_MJ_CREATE/CLOSE/READ/WRITE 预处理回调处理
|
|
|
+// (见 SerialFilter.cpp 中的 DispatchCreate/DispatchClose/DispatchRead/DispatchWrite)。
|
|
|
+// 不再使用 WdfDeviceInitSetFileObjectConfig + EvtDeviceFileCreate/EvtFileClose/EvtFileCleanup,
|
|
|
+// 因为 WdfDeviceInitSetFileObjectConfig 会导致 WdfDeviceWdmDispatchPreprocessedIrp
|
|
|
+// 强制查找 WDFFILEOBJECT,查找失败时返回 STATUS_FILE_FORCED_CLOSED (0xC0000182)。
|
|
|
+
|
|
|
extern "C" VOID EvtDriverUnload(WDFDRIVER driver) {
|
|
|
UNREFERENCED_PARAMETER(driver);
|
|
|
commkit_driver::GetClientConnection().Cleanup();
|