You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

.NET环境下如何验证签名C++ DLL未被篡改

解决C#验证签名C++ DLL完整性的问题

你遇到的核心问题是:X509Certificate2.Verify() 只验证证书本身的有效性(比如是否在有效期内、是否被系统信任链认可),但完全不会验证DLL的内容和签名是否匹配——这就是为什么你修改DLL后验证还能通过的原因。

先搞懂PE文件签名的原理

Windows PE文件(DLL/EXE)的数字签名逻辑是这样的:

  1. 计算文件核心内容(排除签名存储区域)的哈希值;
  2. 用发布者证书的私钥对这个哈希值进行签名;
  3. 把签名数据、哈希算法、证书信息一起嵌入到PE文件的安全目录区域中。

你的目标要同时完成两个验证:一是签名用的是我方的合法证书,二是当前DLL内容和签名时的原始内容完全一致——也就是要确认签名里的哈希值和当前DLL内容的哈希值匹配

正确的验证方案:使用SignedCms

System.Security.Cryptography.Pkcs命名空间下的SignedCms类是专门处理PKCS#7/CMS签名的工具,它能同时完成证书有效性验证和文件完整性验证,完美解决你的问题。

以下是完整的代码示例:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;

public static bool VerifyTrustedDll(string dllPath)
{
    try
    {
        // 读取目标DLL的全部字节内容
        byte[] dllContent = File.ReadAllBytes(dllPath);
        
        // 初始化SignedCms,指定处理嵌入在文件内的签名(非分离式签名)
        SignedCms signedCms = new SignedCms(new ContentInfo(dllContent), detached: false);
        
        // 从DLL中解码提取签名数据
        signedCms.Decode(dllContent);
        
        // 核心验证步骤:true表示同时验证证书链的有效性
        // 如果DLL被篡改、签名无效或证书不被信任,这里会直接抛出CryptographicException
        signedCms.CheckSignature(true);
        
        // 额外校验:确认签名证书是我方发布的证书(防止其他合法证书签名的恶意DLL)
        X509Certificate2 signerCert = signedCms.SignerInfos[0].Certificate;
        if (signerCert.Subject != "你的证书主题(如CN=你的公司名)" || signerCert.Thumbprint != "你的证书指纹")
        {
            Console.WriteLine("签名证书不是我方发布的合法证书");
            return false;
        }
        
        // 可选:获取签名中记录的哈希信息(用于调试或自定义校验)
        SignerInfo signerInfo = signedCms.SignerInfos[0];
        string hashAlgorithm = signerInfo.DigestAlgorithm.Value.FriendlyName;
        byte[] signedHash = signerInfo.SignedAttributes[Pkcs9MessageDigest.Oid].Values[0] as byte[];
        Console.WriteLine($"签名使用的哈希算法:{hashAlgorithm}");
        Console.WriteLine("签名哈希值:" + BitConverter.ToString(signedHash).Replace("-", ""));
        
        return true;
    }
    catch (CryptographicException ex)
    {
        Console.WriteLine($"验证失败:{ex.Message}");
        return false;
    }
}

关键细节说明

  • detached: false:因为PE文件的签名是直接嵌入在文件内部的,不是单独的签名文件,所以要设置为false。
  • CheckSignature(true):这个方法会自动完成两项关键检查:一是签名用的证书是否在信任链中且有效,二是当前DLL内容的哈希值和签名中存储的哈希值是否一致——只要DLL被篡改,这里就会抛出异常。
  • 证书主题/指纹校验:即使是合法有效的证书,但如果不是我方的发布证书,也要拒绝,避免被其他信任证书签名的恶意DLL绕过验证。

为什么原来的方法无效

X509Certificate.CreateFromSignedFile(filename)只是从DLL里提取出证书文件,完全没有处理签名数据和DLL内容的绑定关系;而cert.Verify()只检查证书本身是否合法,哪怕你把证书单独复制到其他文件里,这个方法也会返回通过,和DLL是否被篡改没有任何关联。

内容的提问来源于stack exchange,提问作者Francois Nguyen

火山引擎 最新活动