基本概念

WinVerifyTrustWindows系统中用于验证数字签名、证书链和信任状态的核心API。它可以验证文件、目录(catalog)、证书、驱动程序等对象是否可信。
WinVerifyTrustWindows提供的信任验证接口,位于wintrust.dll
它的作用是:
验证文件是否有有效的数字签名
验证签名证书是否由受信任的CA颁发
检查证书是否被吊销
验证目录文件(.cat)中的文件哈希是否可信
验证驱动程序、安装包等是否符合Windows信任策略

基本语法

1
2
3
4
5
LONG WinVerifyTrust(
[in] HWND hwnd, //调用方窗口的可选句柄
[in] GUID *pgActionID,//指定验证策略
[in] LPVOID pWVTData //包含待验证对象的信息
);

返回值
返回值是LONG类型。
常见返回值:
ERROR_SUCCESS (0):验证成功
TRUST_E_NOSIGNATURE:文件没有签名
TRUST_E_EXPLICIT_DISTRUST:被显式标记为不信任
TRUST_E_SUBJECT_NOT_TRUSTED:主题不受信任
CRYPT_E_SECURITY_SETTINGS:系统安全策略阻止验证
TRUST_E_CERT_SIGNATURE:证书签名无效
TRUST_E_REVOCATION_FAILURE:吊销检查失败
TRUST_E_UNKNOWN_CA:未知证书颁发机构

数据类型

HWND:

1
DECLARE_HANDLE            (HWND);

本质是通过预编译宏将HWND定义为指向匿名结构体的指针类型,是Windows窗口句柄的类型声明。

GUID:

1
2
3
4
5
6
typedef struct _GUID {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[ 8 ];
} GUID;

这段代码是Windows系统中GUID(Globally Unique Identifier,全局唯一标识符)的官方结构体定义,用于存储一个128位的唯一标识。GUID的核心作用是在整个系统 / 网络中唯一标记某个对象(如接口、策略、组件、文件类型等),确保不会出现重复。

通常GUID会被格式化为字符串,比如:
{00000000-0000-0000-0000-000000000000}
对应字段拆分:
Data1 → 00000000(8 位十六进制)
Data2 → 0000(4 位十六进制)
Data3 → 0000(4 位十六进制)
Data4[0-1] → 0000(4 位十六进制)
Data4[2-7] → 000000000000(12 位十六进制)

参数pWVTData:
当强制转换为WINTRUST_DATA结构时,包含信任提供程序需要处理指定作标识符的信息。
WINTRUST_DATAWindows信任验证体系中用于配置验证行为的核心结构体,你可以把它理解为给WinVerifyTrust API传递的 “验证指令集”:
告诉API要验证什么(文件 / 目录 / 证书);
告诉API怎么验证(是否显示UI、是否检查证书吊销);
告诉API验证后要做什么(是否保留验证状态)。
它的定义位于wintrust.h头文件中,是调用WinVerifyTrust时必须正确初始化的参数(尤其是cbStruct字段)。

以下是最核心的字段定义(省略了部分不常用字段)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct _WINTRUST_DATA {
DWORD cbStruct; // 结构体大小(必须设置)
LPVOID pPolicyCallbackData; // 策略回调数据(一般为NULL)
LPVOID pSIPClientData; // SIP客户端数据(一般为NULL)
DWORD dwUIChoice; // UI显示策略
DWORD fdwRevocationChecks; // 证书吊销检查策略
DWORD dwUnionChoice; // 验证对象类型(核心)
union {
struct WINTRUST_FILE_INFO_ *pFile; // 验证文件时用
struct WINTRUST_CATALOG_INFO_ *pCatalog; // 验证目录时用
struct WINTRUST_BLOB_INFO_ *pBlob; // 验证二进制BLOB时用
struct WINTRUST_SIGNER_INFO_ *pSigner; // 验证签名者时用
struct WINTRUST_CERT_INFO_ *pCert; // 验证证书时用
};
DWORD dwStateAction; // 信任状态操作
HANDLE hWVTStateData; // 信任状态数据句柄
WCHAR *pwszURLReference; // URL参考(一般为NULL)
DWORD dwProvFlags; // 提供程序标志(核心)
DWORD dwUIContext; // UI上下文(一般为0)
struct WINTRUST_SIGNATURE_SETTINGS_ *pSignatureSettings; // 签名设置(Win8+)
} WINTRUST_DATA, *PWINTRUST_DATA;

简单示例

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <windows.h>
#include <wintrust.h>
#include <stdio.h>

// 链接 wintrust.lib 库(编译时需要)
#pragma comment(lib, "wintrust.lib")

BOOL VerifyFileSignature(LPCWSTR filePath)
{
// 1. 初始化 WINTRUST_FILE_INFO 结构体(指定要验证的文件)
WINTRUST_FILE_INFO fileInfo = {0};
fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO); // 必须设置结构体大小
fileInfo.pcwszFilePath = filePath; // 文件路径
fileInfo.hFile = NULL; // 无需提前打开文件句柄(API 会自动处理)

// 2. 初始化 WINTRUST_DATA 结构体(配置验证规则)
WINTRUST_DATA wtd = {0};
wtd.cbStruct = sizeof(WINTRUST_DATA); // 必须设置结构体大小
wtd.dwUnionChoice = WTD_CHOICE_FILE; // 验证类型:文件
wtd.pFile = &fileInfo; // 关联文件信息
wtd.dwUIChoice = WTD_UI_NONE; // 静默验证(不弹出任何窗口)
wtd.fdwRevocationChecks = WTD_REVOKE_NONE; // 不检查证书吊销(加快验证)
wtd.dwProvFlags = WTD_REVOCATION_CHECK_NONE; // 禁用吊销检查
wtd.dwStateAction = 0; // 不修改信任状态

// 3. 通用验证策略 GUID(固定值,用于文件签名验证)
GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;

// 4. 调用 WinVerifyTrust 执行验证
LONG lStatus = WinVerifyTrust(NULL, &policyGUID, &wtd);

// 5. 处理验证结果
if (lStatus == ERROR_SUCCESS)
{
wprintf(L"文件 \"%s\" 签名验证通过!\n", filePath);
return TRUE;
}
else
{
wprintf(L"文件 \"%s\" 签名验证失败!错误码:0x%08X\n", filePath, lStatus);
// 常见错误码说明(帮助排查问题)
switch (lStatus)
{
case TRUST_E_NOSIGNATURE:
wprintf(L" 原因:文件没有数字签名\n");
break;
case TRUST_E_EXPLICIT_DISTRUST:
wprintf(L" 原因:签名被系统显式标记为不信任\n");
break;
case TRUST_E_SUBJECT_NOT_TRUSTED:
wprintf(L" 原因:签名证书不受信任\n");
break;
case CRYPT_E_SECURITY_SETTINGS:
wprintf(L" 原因:系统安全策略阻止了验证\n");
break;
default:
wprintf(L" 原因:其他验证错误(可参考 WinError.h 查看错误码含义)\n");
break;
}
return FALSE;
}
}

int wmain(int argc, wchar_t* argv[])
{
// 检查命令行参数
if (argc != 2)
{
wprintf(L"使用方法:%s <要验证的文件路径>\n", argv[0]);
wprintf(L"示例:%s C:\\Windows\\notepad.exe\n", argv[0]);
return 1;
}

// 调用验证函数
VerifyFileSignature(argv[1]);

return 0;
}