如何通过Windows API检查驱动是否使用吊销证书签名?
检测驱动签名证书吊销状态的正确方法
问题根源
你当前的WinVerifyTrust调用存在两个关键问题:
- 错误地通过
GetLastError()获取失败原因,WinVerifyTrust的失败信息直接通过返回的HRESULT传递,而非GetLastError。 - 未针对内核模式驱动的签名验证策略做适配,普通Authenticode验证逻辑和内核驱动的签名检查规则存在差异。
修正后的WinVerifyTrust调用
以下是调整后的代码,能正确匹配内核驱动加载时的证书吊销检查逻辑:
#include <wintrust.h> #include <softpub.h> #include <mscat.h> #pragma comment(lib, "wintrust.lib") BOOL IsDriverCertRevoked(LPCWSTR pwszFileName) { BOOL bRevoked = FALSE; HRESULT hr; WINTRUST_FILE_INFO wtfi = { 0 }; wtfi.cbStruct = sizeof(WINTRUST_FILE_INFO); wtfi.pcwszFilePath = pwszFileName; wtfi.hFile = NULL; WINTRUST_DATA wtd = { 0 }; wtd.cbStruct = sizeof(WINTRUST_DATA); wtd.dwUIChoice = WTD_UI_NONE; // 禁用UI弹窗 wtd.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN; // 检查整个证书链的吊销状态 wtd.dwUnionChoice = WTD_CHOICE_FILE; wtd.pFile = &wtfi; wtd.dwStateAction = WTD_STATEACTION_VERIFY; wtd.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | WTD_USE_DEFAULT_OSVER_CHECK; // 适配驱动OS版本验证规则 // 使用适配内核驱动的通用验证策略GUID GUID wvtProvGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2; hr = WinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &wvtProvGuid, &wtd); if (hr == CERT_E_REVOKED) { // 明确检测到证书已吊销 bRevoked = TRUE; } else if (FAILED(hr)) { // 其他验证错误(如无签名、证书过期等),可按需处理 } // 清理验证状态数据 wtd.dwStateAction = WTD_STATEACTION_CLOSE; WinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &wvtProvGuid, &wtd); return bRevoked; }
关键调整说明
- 错误处理逻辑:直接判断返回的HRESULT值,
CERT_E_REVOKED(0x800B010C)是证书吊销的明确标识。 - 验证策略匹配:使用
WINTRUST_ACTION_GENERIC_VERIFY_V2GUID,该策略覆盖了内核模式驱动的签名验证规则。 - 参数优化:添加
WTD_USE_DEFAULT_OSVER_CHECK确保驱动的OS版本兼容性检查和内核加载时的逻辑一致,避免误判。
更灵活的手动证书链检查
如果需要自定义吊销检查规则(如离线检查、指定吊销服务器),可以使用CertGetCertificateChain和CertVerifyCertificateChainPolicy手动构建并验证证书链:
BOOL CheckDriverCertRevocationManual(LPCWSTR pwszFileName) { BOOL bRevoked = FALSE; HCERTSTORE hStore = NULL; PCCERT_CONTEXT pCertContext = NULL; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_CHAIN_POLICY_PARA policyPara = { 0 }; CERT_CHAIN_POLICY_STATUS policyStatus = { 0 }; // 提取驱动文件的签名证书 if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE, pwszFileName, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, &hStore, NULL, (const void**)&pCertContext)) { goto Cleanup; } // 构建完整证书链 CERT_CHAIN_PARA chainPara = { 0 }; chainPara.cbSize = sizeof(CERT_CHAIN_PARA); if (!CertGetCertificateChain(NULL, pCertContext, NULL, hStore, &chainPara, CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, &pChainContext)) { goto Cleanup; } // 验证证书链的吊销状态 policyPara.cbSize = sizeof(CERT_CHAIN_POLICY_PARA); policyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS); if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, pChainContext, &policyPara, &policyStatus)) { goto Cleanup; } // 检查是否因吊销导致验证失败 if (policyStatus.dwError == CERT_E_REVOKED || policyStatus.dwError == CRYPT_E_REVOCATION_OFFLINE) { bRevoked = TRUE; } Cleanup: if (pChainContext) CertFreeCertificateChain(pChainContext); if (pCertContext) CertFreeCertificateContext(pCertContext); if (hStore) CertCloseStore(hStore, 0); return bRevoked; }
补充说明
- Sysinternals的SigCheck默认不启用吊销检查,需添加
-r参数触发:sigcheck.exe -r <驱动文件路径>。 - 内核驱动的吊销检查会严格遵循微软代码签名的官方规则,上述API调用完全匹配内核加载时的验证逻辑。
内容的提问来源于stack exchange,提问作者user5716274
相关产品推荐
相关产品推荐

