为何X509Chain.Build()在DLL签名无效时仍返回True?
问题原因及解决方案
你的代码只完成了证书链有效性验证,但没有验证DLL的Authenticode签名与文件内容的一致性——这是两个完全独立的操作:
new X509Certificate2("path/To/The/Dll")仅提取DLL中嵌入的签名证书,无论DLL内容是否被篡改,这个证书都能被正常读取。X509Chain.Build()仅验证该证书能否通过你指定的根/中间证书构成信任链,完全不检查证书对应的签名是否与当前DLL的字节内容匹配。
所以即便你修改了DLL字节,只要嵌入的证书本身信任链有效,Build()就会返回true。
正确的验证方式:验证DLL的Authenticode签名完整性
要检测DLL篡改后的签名失效,需要使用专门处理Authenticode签名的API。以下是两种适配离线环境的实现方式:
方式1:使用.NET原生SignedCms类
using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; using System.IO; // 读取DLL字节 byte[] dllBytes = File.ReadAllBytes("path/To/The/Dll"); ContentInfo contentInfo = new ContentInfo(dllBytes); SignedCms signedCms = new SignedCms(contentInfo, detached: false); try { // 从DLL中解码签名信息 signedCms.Decode(dllBytes); // 配置离线验证策略:添加信任的根/中间证书,关闭吊销检查 X509Certificate2Collection extraStore = new X509Certificate2Collection(); extraStore.Add(intermediateCertificate); extraStore.Add(rootCertificate); X509ChainPolicy chainPolicy = new X509ChainPolicy(); chainPolicy.ExtraStore = extraStore; chainPolicy.RevocationMode = X509RevocationMode.NoCheck; chainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; // 执行签名+证书链双重验证 signedCms.CheckSignature(extraStore, verifySignatureOnly: false); Console.WriteLine("DLL签名有效且证书链可信"); } catch (CryptographicException ex) { Console.WriteLine($"签名验证失败:{ex.Message}"); }
方式2:使用Windows原生WinVerifyTrust API
该方式与系统级签名验证逻辑完全一致,适合需要严格匹配Windows验证规则的场景:
using System; using System.Runtime.InteropServices; public static class AuthenticodeChecker { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct WINTRUST_FILE_INFO { public uint cbStruct; public string pcwszFilePath; public IntPtr hFile; public IntPtr pgKnownSubject; } [StructLayout(LayoutKind.Sequential)] private struct WINTRUST_DATA { public uint cbStruct; public IntPtr pPolicyCallbackData; public IntPtr pSIPClientData; public uint dwUIChoice; public uint fdwRevocationChecks; public uint dwUnionChoice; public IntPtr pFile; public uint dwStateAction; public IntPtr hWVTStateData; public string pwszURLReference; public uint dwProvFlags; public uint dwUIContext; public IntPtr pSignatureSettings; } [DllImport("wintrust.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern uint WinVerifyTrust(IntPtr hwnd, IntPtr pgActionID, ref WINTRUST_DATA pWinTrustData); private static readonly IntPtr WINTRUST_ACTION_GENERIC_VERIFY_V2 = new IntPtr(unchecked((int)0xa0000003)); public static bool ValidateDllSignature(string dllPath) { WINTRUST_FILE_INFO fileInfo = new WINTRUST_FILE_INFO { cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)), pcwszFilePath = dllPath }; WINTRUST_DATA trustData = new WINTRUST_DATA { cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_DATA)), dwUIChoice = 2, // 不显示验证UI fdwRevocationChecks = 0, // 关闭吊销检查(适配离线) dwUnionChoice = 1, // 指定验证文件类型 pFile = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_FILE_INFO))), dwStateAction = 0, // 忽略状态缓存 dwProvFlags = 0x10000 | 0x20000, // 适配离线环境的验证标志 dwUIContext = 0 }; Marshal.StructureToPtr(fileInfo, trustData.pFile, false); uint verifyResult = WinVerifyTrust(IntPtr.Zero, WINTRUST_ACTION_GENERIC_VERIFY_V2, ref trustData); Marshal.FreeHGlobal(trustData.pFile); // 返回0表示签名验证通过 return verifyResult == 0; } } // 使用示例 bool isDllValid = AuthenticodeChecker.ValidateDllSignature("path/To/The/Dll");
内容的提问来源于stack exchange,提问作者Rena821
相关产品推荐
相关产品推荐

