Windows 数字签名获取与验证详解

在 Windows 的安全体系中,数字签名扮演着“软件身份证”的角色。它可以证明一个程序确实来自某个发布者,并且在分发的过程中没有被篡改。

当下载一个系统更新、驱动程序,或者安装第三方应用时,操作系统往往会验证数字签名,确保软件来源合法、安全。那么,作为开发者或安全研究人员,该如何编程获取并验证这些数字签名呢?

本文将通过代码示例,逐步实现一个数字签名验证工具,并解析其原理和应用场景。

为什么要验证数字签名?

在信息安全领域,数字签名主要解决两个问题:

  1. 来源认证 通过证书绑定发布者的身份,确认文件确实来自于声称的公司或组织。比如系统文件通常签名于 Microsoft Corporation
  2. 完整性保护 签名过程包含哈希计算,如果文件在传输中被篡改,签名将立刻失效。

对普通用户来说,这能防止中途被植入恶意代码;对企业来说,则能确保生产环境中运行的软件是可信的。

验证思路与 Windows API

Windows 提供了专门的 API 来处理数字签名验证,其中最关键的包括:

  • WinVerifyTrust:验证文件的数字签名是否有效;
  • WTHelperProvDataFromStateData:获取验证过程中的证书链数据;
  • WTHelperGetProvSignerFromChain:提取签名者、时间戳签名者等信息;
  • CertGetNameString:获取证书的持有人或颁发者名称;
  • CryptHashCertificate2:计算证书的 SHA1 指纹。

我们的目标是用这些 API 编写一个签名验证器,它不仅要能告诉我们签名是否有效,还能展示签名的详细信息。

定义数据结构:存储验证结果

首先,需要定义一个结构体,用来存储每次验证得到的签名信息。

通过这样的结构体,就能清晰地记录和返回验证结果,方便展示和后续处理。

调用 WinVerifyTrust 验证签名

验证的第一步就是调用 WinVerifyTrust,系统会说明这个文件的签名是否可信。

通过返回值 result 可以验证是否成功:

  • ERROR_SUCCESS:签名有效;
  • 其他值:签名无效,需要进一步分析原因,比如证书过期、吊销、不受信任等。

这相当于签名验证的入口,后续的步骤都建立在这之上。

提取签名证书信息

如果验证成功,便可以提取证书链的详细信息,包括:

  • 签名者(Signer):谁签了这个文件;
  • 颁发者(Issuer):证书由谁颁发;
  • 证书指纹(Thumbprint):用于唯一标识证书;
  • 时间戳(Timestamp):签名时刻的时间戳,确保即使证书后来过期,签名依然有效。

核心代码如下:

通过证书链,可以把签名的每一个关键细节抽取出来。

辅助函数:让结果更直观

仅仅有 API 返回的原始数据并不友好,还需要写几个辅助函数,便于转化结果。

获取证书指纹

证书指纹是证书的 SHA1 哈希,常用于唯一标识:

获取证书名称

证书包含了签名者和颁发者的名称,我们用 CertGetNameString 提取:

状态码映射

不同的错误码代表不同的签名状态,可以映射为更易懂的文字:

测试与运行结果

最后,可以这样使用:

运行结果:

这表明 explorer.exe 的签名有效,签名者是微软,签名带有可信时间戳。

参考链接