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

如何检测已签名C# DLL的文件完整性与真实性?

如何验证已签名C# DLL的文件完整性(不仅仅是证书有效性)

你遇到的问题很典型:当前代码只验证了证书本身的合法性,但没有验证证书对这个DLL的签名是否与文件内容匹配。当你用Resource Hacker修改DLL资源后,文件的哈希值已经改变,但证书本身依然有效,所以Verify()方法自然会返回true——它本来就不负责检查文件是否被篡改。

为什么你的现有代码无法检测篡改?

X509Certificate2.Verify()的作用是验证证书自身的有效性:比如是否在有效期内、是否属于受信任的根证书颁发机构、是否被吊销等。它完全不涉及对DLL文件内容的校验,所以哪怕文件被改得面目全非,只要证书本身没问题,这个方法就会返回true。

正确的解决方案:验证文件签名完整性

要检测文件是否被篡改,你需要验证证书对DLL的签名是否有效——也就是确认当前文件的哈希值和签名时生成的哈希值一致,且签名确实由对应证书签发。最可靠的方式是使用SignedCms类(处理PKCS#7签名,也就是Authenticode签名),它会同时校验签名完整性和证书链有效性。

修改后的代码示例:

public ValidatorResult CheckDll()
{
    try
    {
        // 读取完整的DLL文件内容
        byte[] fileContent = File.ReadAllBytes(dllFilepath);

        // 初始化SignedCms来解析文件中的Authenticode签名
        var signedCms = new SignedCms(new ContentInfo(fileContent));
        signedCms.Decode(fileContent);

        // 验证签名:参数true表示同时验证证书链的有效性
        bool isSignatureValid = signedCms.CheckSignature(true);

        if (!isSignatureValid)
        {
            return new ValidatorResult(ValidatorResult.DllStatus.INVALID_SIGNATURE);
        }

        // 可选:进一步自定义证书链验证规则(比如检查吊销状态)
        X509Certificate2 signingCert = signedCms.SignerInfos[0].Certificate;
        using (var chain = new X509Chain())
        {
            // 配置链验证策略,比如启用在线吊销检查
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            // 可以添加自定义信任根等
            if (!chain.Build(signingCert))
            {
                return new ValidatorResult(ValidatorResult.DllStatus.INVALID_CERTIFICATE_CHAIN);
            }
        }

        return new ValidatorResult(ValidatorResult.DllStatus.VALID);
    }
    catch (CryptographicException)
    {
        // 签名解码失败或验证不通过
        return new ValidatorResult(ValidatorResult.DllStatus.INVALID_SIGNATURE);
    }
    catch (IOException)
    {
        // 文件读取失败
        return new ValidatorResult(ValidatorResult.DllStatus.FILE_ACCESS_ERROR);
    }
}

代码说明

  1. SignedCms的作用:它会解析DLL中的Authenticode签名,提取出签名时生成的文件哈希,然后和当前文件的哈希做比对,同时验证签名是否由对应的证书签发。
  2. CheckSignature(true):这个参数true会触发证书链的验证,确保签名证书是受信任的、未过期且未被吊销。如果只需要验证文件完整性(不关心证书是否受信任),可以传false,但一般建议同时验证证书链。
  3. 自定义链验证:你可以通过X509ChainPolicy调整验证规则,比如是否允许离线吊销检查、是否添加自定义信任根等,适配你的具体场景。

补充:针对强名称签名的情况

如果你的DLL同时有.NET强名称签名(而非Authenticode数字签名),可以使用StrongNameSignatureVerificationEx方法来验证:

[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
private static extern bool StrongNameSignatureVerificationEx(string wszFilePath, bool fForceVerification, ref bool pfWasVerified);

// 使用示例
bool wasVerified = false;
bool isStrongNameValid = StrongNameSignatureVerificationEx(dllFilepath, true, ref wasVerified);

但注意:强名称签名主要用于防止篡改和确保版本一致性,它不涉及证书信任链的验证,所以如果是要验证第三方发布的DLL,还是推荐用Authenticode签名的验证方式。

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

火山引擎 最新活动