我把当前 main 里的 DriverEntry、控制设备创建、两个 WDF 队列、五类内核回调、前置 HVM/RXPF 初始化、INF/KMDF 配置以及最终签名脚本都追了一遍。
当前最合理的判断:少数机器返回 31,首要嫌疑是 KswordARKCallbackInitialize 的“一票否决”设计;而从 31 这个数值本身看,WdfIoQueueCreate 返回 STATUS_UNSUCCESSFUL 是最直接的对应路径。
现在无法在二者之间定案,因为 KSword 没有把“失败阶段 + 原始 NTSTATUS”持久化下来,而且回调启动期的内部日志实际上会被自己吞掉。
真正能让 KSword 整体加载失败的路径只有三段
当前 DriverEntry 中,下面三步失败才会直接把失败状态返回给系统:
- WdfDriverCreate
- KswordARKDriverCreateControlDevice
- KswordARKCallbackInitialize
HVM、IDT baseline、RX/PF、Driver Communication、Dispatch Editor、Driver Image、DynData、Redirect、Network、File Monitor 的初始化失败全部只是记录 warning,随后继续加载。因此,PDB、动态偏移、HVM 不支持、minifilter 注册失败都不是 31 的直接原因;除非其中存在尚未发现的内存破坏,这一点目前没有静态证据。
首要嫌疑:五类回调里任何一个失败,整个驱动都死
KswordARKCallbackInitialize 当前的顺序是:
创建 callback runtime
创建 AskUser 手动等待队列
注册表回调
进程回调
线程回调
映像加载回调
对象句柄回调
发布全局 runtime
注册表、进程、线程、映像回调只要有一个注册失败,代码就立即:
释放全局锁
撤销此前已经注册的所有回调
删除运行时
把原始失败状态返回 DriverEntry
DriverEntry 删除控制设备并返回失败
对象回调也只有 STATUS_ACCESS_DENIED 和 STATUS_INVALID_IMAGE_HASH 被允许降级;若是 altitude collision、资源不足或参数错误,仍然让整个驱动加载失败。
这完全符合“绝大多数人正常,少数特定机器失败”的分布:
- 注册表回调固定使用 altitude 385201.5141;另一个已加载的 KSword、分叉版本或碰巧使用同 altitude 的驱动会让 CmRegisterCallbackEx 返回 STATUS_FLT_INSTANCE_ALTITUDE_COLLISION。Microsoft 也明确说明 altitude 由 Microsoft 管理分配。
- 对象回调固定使用 385201.5142;同样可能发生 altitude collision。当前代码没有把这种冲突作为可降级状态。
- 进程创建回调在重复注册或系统达到回调数量限制时返回 STATUS_INVALID_PARAMETER。
- 映像加载回调在现代系统最多同时注册 64 个;达到限制时返回 STATUS_INSUFFICIENT_RESOURCES。装有多套 EDR、杀毒、反作弊和调试驱动的机器更容易命中这一条件。
- 线程回调注册也可能因资源不足失败。
项目链接参数已经设置了 /INTEGRITYCHECK,所以干净构建上的进程回调不应因为缺少 IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 而返回 STATUS_ACCESS_DENIED。这让“回调数量限制、固定 altitude 冲突、资源分配失败”比“缺少完整性标志”更值得优先检查。
现在为什么完全不知道是哪一个回调失败
这里有一个很明确的可观测性 bug。
KswordArkCallbackLogFrame 首先通过 g_KswordArkCallbackRuntime 找 runtime;全局 runtime 为空时,它直接丢弃日志。
但 g_KswordArkCallbackRuntime = runtime 是在五类回调全部注册成功之后才执行的。也就是说,注册表、进程、线程、映像和对象回调在初始化阶段输出的成功或失败日志都无法进入 KSword 自己的日志队列。
所以目前用户端只能看到:
StartService failed: 31
驱动内部即使知道原始 NTSTATUS,也没有可靠地把“在哪一步失败”带出来。
这个要先修,不然继续猜没有意义。
第二嫌疑:控制设备的默认 WDF 队列
控制设备创建过程中,下列步骤也是致命的:
WdfControlDeviceInitAllocate
WdfDeviceInitAssignName
WdfDeviceCreate
WdfSpinLockCreate
调试输出初始化
WdfDeviceCreateSymbolicLink
WdfIoQueueCreate(默认队列)
其中 KswordARKDriverQueueInitialize 创建了一个默认并行队列。Microsoft 文档明确列出:如果设备已经存在默认队列,或者 WDF 发生内部错误,WdfIoQueueCreate 可以返回 STATUS_UNSUCCESSFUL。STATUS_UNSUCCESSFUL 是通向 Win32 ERROR_GEN_FAILURE = 31 最直接的状态。
但是当前源码中,每个控制设备只创建了一次默认队列,没有明显的重复调用。因此:
- 若拿到的原始状态确实是 0xC0000001,优先断在 WdfIoQueueCreate。
- 若源码与实际二进制完全一致,“默认队列已经存在”不太成立;剩下的是 WDF 内部失败、实际运行的不是当前构建,或者此前初始化破坏了 WDF/device 状态。
- AskUser 队列是手动队列,不是第二个默认队列,而且已经显式设置 PowerManaged = WdfFalse。
控制设备默认队列也建议显式写成:
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
&queueConfig,
WdfIoQueueDispatchParallel
);
queueConfig.PowerManaged = WdfFalse;
queueConfig.EvtIoDeviceControl = KswordARKDriverEvtIoDeviceControl;
queueConfig.EvtIoRead = KswordARKDriverEvtIoRead;
queueConfig.EvtIoStop = NULL;
控制设备不支持电源管理队列;当前 WdfUseDefault 理应被 WDF 解析为非电源管理,但显式设为 WdfFalse 可以排除版本和配置歧义。
还有一个结构问题:当前代码在 KswordARKCallbackInitialize 之前已经执行 WdfControlFinishInitializing。也就是控制设备先对外可见,再开始建立回调运行时。应当把“创建设备”和“发布设备”拆开,等队列与 callback runtime 都完成后再 WdfControlFinishInitializing。
设备名或符号链接冲突也是实际候选
KSword 使用固定控制设备名和固定 DOS 符号链接。如果机器上还有一个旧 KSword 驱动以其他服务名加载,或者旧版本没有正确卸载,下面两步可能失败:
WdfDeviceCreate
WdfDeviceCreateSymbolicLink
这类情况会集中出现在升级过多个版本、使用过测试服务名或手动加载过不同副本的人身上,也符合“少数机器固定失败”。
复现后可立即检查:
sc.exe query type= driver state= all | findstr /i "Ksword"
reg.exe query HKLM\SYSTEM\CurrentControlSet\Services /s /f "KswordARK.sys"
同时用 WinObj 查看:
\Device\KswordARKLog
\GLOBAL??\KswordARKLog
具体名字以 KswordArkLogProtocol.h 当前定义为准。驱动启动失败后这些对象仍存在,就不是普通资源不足,而是另一实例或清理不完整。
签名和最终二进制不能排除,但应当用“是否进入 DriverEntry”判断
当前构建不是简单地对 .sys 签一次名。MSBuild 会:
- 复制 clean driver;
- 调用 CSignTool;
- 再添加 cross-certificate;
- 通过 AuthenticodeVariantGUI 生成最终变体;
- 用变体替换原始 KswordARK.sys。
这里有个发布风险:脚本最终只是用 Get-AuthenticodeSignature 打印摘要,不会因为最终状态无效而失败;变体流程失败时还会进入 non-fatal legacy test-sign fallback,即使 fallback 也失败,构建仍可能继续。
因此最终发布必须增加硬校验:
signtool.exe verify /kp /all /v .\KswordARK.sys
if ($LASTEXITCODE -ne 0) {
throw "Final kernel signature verification failed."
}
Get-FileHash .\KswordARK.sys -Algorithm SHA256
判断边界非常清楚:
- DriverEntry 的第一条 breadcrumb 都没有出现:优先查最终 .sys、签名、Code Integrity、导入函数、KMDF 绑定和系统版本。
- 已经进入 DriverEntry:签名已经通过主要加载检查,应转查 WDF、控制设备和 callback registration。
项目使用 KMDF 1.15,并且 INF 的声明范围从 Windows 10 build 16299 开始。低于 10.0.16299 的系统应直接判定为不受支持,而不是继续分析 callback。
应立即加入的启动 breadcrumb
不要只记:
"KswordARKCallbackInitialize failed"
应当保存到:
HKLM\SYSTEM\CurrentControlSet\Services\KswordARK\Parameters
LastStartStage
LastStartStatus
LastStartBuild
建议阶段编号:
typedef enum _KSWORD_START_STAGE {
KswordStartEnteredDriverEntry = 1,
KswordStartWdfDriverCreate,
KswordStartControlInitAllocate,
KswordStartDeviceAssignName,
KswordStartDeviceCreate,
KswordStartLogChannel,
KswordStartDebugOutput,
KswordStartSymbolicLink,
KswordStartDefaultQueue,
KswordStartCallbackRuntimeAllocate,
KswordStartCallbackWaitQueue,
KswordStartRegistryCallback,
KswordStartProcessCallback,
KswordStartThreadCallback,
KswordStartImageCallback,
KswordStartObjectCallback,
KswordStartReady
} KSWORD_START_STAGE;
每次调用前写 stage,失败时写原始 NTSTATUS:
static NTSTATUS
KswordStartFailure(
In KSWORD_START_STAGE Stage,
In NTSTATUS Status
)
{
DbgPrintEx(
DPFLTR_IHVDRIVER_ID,
DPFLTR_ERROR_LEVEL,
"[KswordARK] startup failure: stage=%lu status=0x%08lX\n",
(ULONG)Stage,
(ULONG)Status
);
KswordPersistStartupResult(Stage, Status); // 失败也不得影响原始返回值
return Status;
}
然后:
KswordPersistStartupStage(KswordStartDefaultQueue);
status = WdfIoQueueCreate(
Device,
&queueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue
);
if (!NT_SUCCESS(status)) {
return KswordStartFailure(
KswordStartDefaultQueue,
status
);
}
回调注册阶段也分别保存:
status = KswordArkRegistryCallbackRegister(runtime);
runtime->RegistryRegisterStatus = status;
if (NT_SUCCESS(status)) {
runtime->RegisteredCallbacksMask |=
KSWORD_ARK_CALLBACK_REGISTERED_REGISTRY;
}
else {
TraceEvents(
TRACE_LEVEL_WARNING,
TRACE_DRIVER,
"Registry callback unavailable %!STATUS!",
status
);
}
回调功能不应再阻止整个驱动加载
当前驱动已经有 RegisteredCallbacksMask,但初始化逻辑没有真正利用它做降级。正确结构是:
- runtime 分配失败:禁用 callback 模块,核心驱动继续加载;
- AskUser 队列失败:禁用 AskUser,其他 callback 仍可注册;
- 注册表回调失败:只清除 Registry capability;
- 进程回调失败:只清除 Process capability;
- 线程回调失败:只清除 Thread capability;
- 映像回调失败:只清除 Image capability;
- 对象回调失败:只清除 Object capability;
- UI 显示每项原始 NTSTATUS 和可用状态。
这样即使某台机器已经占满 image callback 槽位,用户仍然可以使用 KSword 的驱动、进程、线程、内存、句柄、内核审计等其他能力。
另外,初始化日志应改为显式接收正在构建的 runtime:
KswordArkCallbackLogFrameForRuntime(
runtime,
"Warn",
"Image callback registration failed."
);
不能在发布 g_KswordArkCallbackRuntime 之前再通过全局变量反查 runtime,否则启动日志仍会被丢掉。
我建议的定案方式
做三组诊断构建,在一台确定会返回 31 的机器上测试:
A:WdfDriverCreate + control device + 默认队列,不初始化 callback
B:A + callback manual wait queue
C:B + Registry / Process / Thread / Image / Object 逐个启用
结果会非常明确:
- A 都失败:控制设备、默认队列、WDF 或最终二进制问题;
- A 成功、B 失败:callback waiter 的 WdfIoQueueCreate;
- B 成功、某个 C 失败:对应的内核 callback 注册 API;
- 连 DriverEntry stage 1 都没有:签名、CI、导入或 KMDF/系统版本。
受影响机器同时收集:
$Since = (Get-Date).AddMinutes(-10)
Get-WinEvent -FilterHashtable @{
LogName = 'System'
StartTime = $Since
} |
Where-Object {
$_.ProviderName -in @(
'Service Control Manager',
'Microsoft-Windows-Kernel-PnP',
'Microsoft-Windows-Kernel-WDF'
)
} |
Format-List TimeCreated, Id, ProviderName, LevelDisplayName, Message
Get-WinEvent -LogName 'Microsoft-Windows-CodeIntegrity/Operational'
-MaxEvents 100 |
Format-List TimeCreated, Id, LevelDisplayName, Message
Get-FileHash .\KswordARK.sys -Algorithm SHA256
sc.exe qc KswordARK
sc.exe queryex KswordARK
Get-ComputerInfo |
Select-Object WindowsProductName, WindowsVersion, OsBuildNumber, OsArchitecture
内核调试时直接下这些断点:
bu KswordARK!DriverEntry
bu KswordARK!KswordARKDriverCreateControlDevice
bu KswordARK!KswordARKDriverQueueInitialize
bu KswordARK!KswordArkCallbackWaiterInitialize
bu KswordARK!KswordArkRegistryCallbackRegister
bu KswordARK!KswordArkProcessCallbackRegister
bu KswordARK!KswordArkThreadCallbackRegister
bu KswordARK!KswordArkImageCallbackRegister
bu KswordARK!KswordArkObjectCallbackRegister
g
在每个函数返回后看:
r rax
!error @Rax
我的最终排序是:
- callback registration 任一步失败,但当前被当作整个驱动的致命错误。
- 默认 WDF 队列创建返回 STATUS_UNSUCCESSFUL,这是数值上最贴近 31 的路径。
- 旧实例导致设备名、符号链接或固定 callback altitude 冲突。
- 最终 Authenticode 变体、签名 fallback 或实际分发二进制不一致。
- HVM、偏移、DynData 等非致命初始化产生了间接内存破坏;目前没有代码证据支持,应放最后查。
所以这不是“Windows 偶尔莫名其妙返回 31”。KSword 当前缺少启动阶段诊断,并且把本应可选的全局回调注册做成了全驱动启动门槛。先把 raw stage/status 持久化并改成 callback 降级运行,下一台复现机器一次启动就能把根因精确到某一个 API。
我把当前 main 里的 DriverEntry、控制设备创建、两个 WDF 队列、五类内核回调、前置 HVM/RXPF 初始化、INF/KMDF 配置以及最终签名脚本都追了一遍。
当前最合理的判断:少数机器返回 31,首要嫌疑是 KswordARKCallbackInitialize 的“一票否决”设计;而从 31 这个数值本身看,WdfIoQueueCreate 返回 STATUS_UNSUCCESSFUL 是最直接的对应路径。
现在无法在二者之间定案,因为 KSword 没有把“失败阶段 + 原始 NTSTATUS”持久化下来,而且回调启动期的内部日志实际上会被自己吞掉。
真正能让 KSword 整体加载失败的路径只有三段
当前 DriverEntry 中,下面三步失败才会直接把失败状态返回给系统:
HVM、IDT baseline、RX/PF、Driver Communication、Dispatch Editor、Driver Image、DynData、Redirect、Network、File Monitor 的初始化失败全部只是记录 warning,随后继续加载。因此,PDB、动态偏移、HVM 不支持、minifilter 注册失败都不是 31 的直接原因;除非其中存在尚未发现的内存破坏,这一点目前没有静态证据。
首要嫌疑:五类回调里任何一个失败,整个驱动都死
KswordARKCallbackInitialize 当前的顺序是:
创建 callback runtime
创建 AskUser 手动等待队列
注册表回调
进程回调
线程回调
映像加载回调
对象句柄回调
发布全局 runtime
注册表、进程、线程、映像回调只要有一个注册失败,代码就立即:
释放全局锁
撤销此前已经注册的所有回调
删除运行时
把原始失败状态返回 DriverEntry
DriverEntry 删除控制设备并返回失败
对象回调也只有 STATUS_ACCESS_DENIED 和 STATUS_INVALID_IMAGE_HASH 被允许降级;若是 altitude collision、资源不足或参数错误,仍然让整个驱动加载失败。
这完全符合“绝大多数人正常,少数特定机器失败”的分布:
项目链接参数已经设置了 /INTEGRITYCHECK,所以干净构建上的进程回调不应因为缺少 IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 而返回 STATUS_ACCESS_DENIED。这让“回调数量限制、固定 altitude 冲突、资源分配失败”比“缺少完整性标志”更值得优先检查。
现在为什么完全不知道是哪一个回调失败
这里有一个很明确的可观测性 bug。
KswordArkCallbackLogFrame 首先通过 g_KswordArkCallbackRuntime 找 runtime;全局 runtime 为空时,它直接丢弃日志。
但 g_KswordArkCallbackRuntime = runtime 是在五类回调全部注册成功之后才执行的。也就是说,注册表、进程、线程、映像和对象回调在初始化阶段输出的成功或失败日志都无法进入 KSword 自己的日志队列。
所以目前用户端只能看到:
StartService failed: 31
驱动内部即使知道原始 NTSTATUS,也没有可靠地把“在哪一步失败”带出来。
这个要先修,不然继续猜没有意义。
第二嫌疑:控制设备的默认 WDF 队列
控制设备创建过程中,下列步骤也是致命的:
WdfControlDeviceInitAllocate
WdfDeviceInitAssignName
WdfDeviceCreate
WdfSpinLockCreate
调试输出初始化
WdfDeviceCreateSymbolicLink
WdfIoQueueCreate(默认队列)
其中 KswordARKDriverQueueInitialize 创建了一个默认并行队列。Microsoft 文档明确列出:如果设备已经存在默认队列,或者 WDF 发生内部错误,WdfIoQueueCreate 可以返回 STATUS_UNSUCCESSFUL。STATUS_UNSUCCESSFUL 是通向 Win32 ERROR_GEN_FAILURE = 31 最直接的状态。
但是当前源码中,每个控制设备只创建了一次默认队列,没有明显的重复调用。因此:
控制设备默认队列也建议显式写成:
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
&queueConfig,
WdfIoQueueDispatchParallel
);
queueConfig.PowerManaged = WdfFalse;
queueConfig.EvtIoDeviceControl = KswordARKDriverEvtIoDeviceControl;
queueConfig.EvtIoRead = KswordARKDriverEvtIoRead;
queueConfig.EvtIoStop = NULL;
控制设备不支持电源管理队列;当前 WdfUseDefault 理应被 WDF 解析为非电源管理,但显式设为 WdfFalse 可以排除版本和配置歧义。
还有一个结构问题:当前代码在 KswordARKCallbackInitialize 之前已经执行 WdfControlFinishInitializing。也就是控制设备先对外可见,再开始建立回调运行时。应当把“创建设备”和“发布设备”拆开,等队列与 callback runtime 都完成后再 WdfControlFinishInitializing。
设备名或符号链接冲突也是实际候选
KSword 使用固定控制设备名和固定 DOS 符号链接。如果机器上还有一个旧 KSword 驱动以其他服务名加载,或者旧版本没有正确卸载,下面两步可能失败:
WdfDeviceCreate
WdfDeviceCreateSymbolicLink
这类情况会集中出现在升级过多个版本、使用过测试服务名或手动加载过不同副本的人身上,也符合“少数机器固定失败”。
复现后可立即检查:
sc.exe query type= driver state= all | findstr /i "Ksword"
reg.exe query HKLM\SYSTEM\CurrentControlSet\Services /s /f "KswordARK.sys"
同时用 WinObj 查看:
\Device\KswordARKLog
\GLOBAL??\KswordARKLog
具体名字以 KswordArkLogProtocol.h 当前定义为准。驱动启动失败后这些对象仍存在,就不是普通资源不足,而是另一实例或清理不完整。
签名和最终二进制不能排除,但应当用“是否进入 DriverEntry”判断
当前构建不是简单地对 .sys 签一次名。MSBuild 会:
这里有个发布风险:脚本最终只是用 Get-AuthenticodeSignature 打印摘要,不会因为最终状态无效而失败;变体流程失败时还会进入 non-fatal legacy test-sign fallback,即使 fallback 也失败,构建仍可能继续。
因此最终发布必须增加硬校验:
signtool.exe verify /kp /all /v .\KswordARK.sys
if ($LASTEXITCODE -ne 0) {
throw "Final kernel signature verification failed."
}
Get-FileHash .\KswordARK.sys -Algorithm SHA256
判断边界非常清楚:
项目使用 KMDF 1.15,并且 INF 的声明范围从 Windows 10 build 16299 开始。低于 10.0.16299 的系统应直接判定为不受支持,而不是继续分析 callback。
应立即加入的启动 breadcrumb
不要只记:
"KswordARKCallbackInitialize failed"
应当保存到:
HKLM\SYSTEM\CurrentControlSet\Services\KswordARK\Parameters
LastStartStage
LastStartStatus
LastStartBuild
建议阶段编号:
typedef enum _KSWORD_START_STAGE {
KswordStartEnteredDriverEntry = 1,
KswordStartWdfDriverCreate,
KswordStartControlInitAllocate,
KswordStartDeviceAssignName,
KswordStartDeviceCreate,
KswordStartLogChannel,
KswordStartDebugOutput,
KswordStartSymbolicLink,
KswordStartDefaultQueue,
KswordStartCallbackRuntimeAllocate,
KswordStartCallbackWaitQueue,
KswordStartRegistryCallback,
KswordStartProcessCallback,
KswordStartThreadCallback,
KswordStartImageCallback,
KswordStartObjectCallback,
KswordStartReady
} KSWORD_START_STAGE;
每次调用前写 stage,失败时写原始 NTSTATUS:
static NTSTATUS
KswordStartFailure(
In KSWORD_START_STAGE Stage,
In NTSTATUS Status
)
{
DbgPrintEx(
DPFLTR_IHVDRIVER_ID,
DPFLTR_ERROR_LEVEL,
"[KswordARK] startup failure: stage=%lu status=0x%08lX\n",
(ULONG)Stage,
(ULONG)Status
);
KswordPersistStartupResult(Stage, Status); // 失败也不得影响原始返回值
return Status;
}
然后:
KswordPersistStartupStage(KswordStartDefaultQueue);
status = WdfIoQueueCreate(
Device,
&queueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue
);
if (!NT_SUCCESS(status)) {
return KswordStartFailure(
KswordStartDefaultQueue,
status
);
}
回调注册阶段也分别保存:
status = KswordArkRegistryCallbackRegister(runtime);
runtime->RegistryRegisterStatus = status;
if (NT_SUCCESS(status)) {
runtime->RegisteredCallbacksMask |=
KSWORD_ARK_CALLBACK_REGISTERED_REGISTRY;
}
else {
TraceEvents(
TRACE_LEVEL_WARNING,
TRACE_DRIVER,
"Registry callback unavailable %!STATUS!",
status
);
}
回调功能不应再阻止整个驱动加载
当前驱动已经有 RegisteredCallbacksMask,但初始化逻辑没有真正利用它做降级。正确结构是:
这样即使某台机器已经占满 image callback 槽位,用户仍然可以使用 KSword 的驱动、进程、线程、内存、句柄、内核审计等其他能力。
另外,初始化日志应改为显式接收正在构建的 runtime:
KswordArkCallbackLogFrameForRuntime(
runtime,
"Warn",
"Image callback registration failed."
);
不能在发布 g_KswordArkCallbackRuntime 之前再通过全局变量反查 runtime,否则启动日志仍会被丢掉。
我建议的定案方式
做三组诊断构建,在一台确定会返回 31 的机器上测试:
A:WdfDriverCreate + control device + 默认队列,不初始化 callback
B:A + callback manual wait queue
C:B + Registry / Process / Thread / Image / Object 逐个启用
结果会非常明确:
受影响机器同时收集:
$Since = (Get-Date).AddMinutes(-10)
Get-WinEvent -FilterHashtable @{
LogName = 'System'
StartTime = $Since
} |
Where-Object {
$_.ProviderName -in @(
'Service Control Manager',
'Microsoft-Windows-Kernel-PnP',
'Microsoft-Windows-Kernel-WDF'
)
} |
Format-List TimeCreated, Id, ProviderName, LevelDisplayName, Message
Get-WinEvent
-LogName 'Microsoft-Windows-CodeIntegrity/Operational'-MaxEvents 100 |
Format-List TimeCreated, Id, LevelDisplayName, Message
Get-FileHash .\KswordARK.sys -Algorithm SHA256
sc.exe qc KswordARK
sc.exe queryex KswordARK
Get-ComputerInfo |
Select-Object WindowsProductName, WindowsVersion, OsBuildNumber, OsArchitecture
内核调试时直接下这些断点:
bu KswordARK!DriverEntry
bu KswordARK!KswordARKDriverCreateControlDevice
bu KswordARK!KswordARKDriverQueueInitialize
bu KswordARK!KswordArkCallbackWaiterInitialize
bu KswordARK!KswordArkRegistryCallbackRegister
bu KswordARK!KswordArkProcessCallbackRegister
bu KswordARK!KswordArkThreadCallbackRegister
bu KswordARK!KswordArkImageCallbackRegister
bu KswordARK!KswordArkObjectCallbackRegister
g
在每个函数返回后看:
r rax
!error @Rax
我的最终排序是:
所以这不是“Windows 偶尔莫名其妙返回 31”。KSword 当前缺少启动阶段诊断,并且把本应可选的全局回调注册做成了全驱动启动门槛。先把 raw stage/status 持久化并改成 callback 降级运行,下一台复现机器一次启动就能把根因精确到某一个 API。