gpt4 book ai didi

c# - 如何使用 Authenticode 对二进制文件进行双重签名?

转载 作者:太空狗 更新时间:2023-10-29 20:07:33 28 4
gpt4 key购买 nike

简短的问题

如何从可执行文件 (.EXE/.DLL) 中获取有关多个代码签名证书的信息?

预期的答案

最终接受的答案应该提出一种在 C# 中获取所有证书的方法。概念/伪代码还可以,我不指望你写出完整的源代码。

有关建议工具的中间答案,请参阅 my question on Security.StackExchange .

长问题

我正在研究是否可以在插件 (.DLL) 上使用多个代码签名证书来检查它是否已经过官方测试。这是程序:

  • 插件 DLL 与任何其他应用程序一样由供应商签名
  • 插件 DLL 进入测试实验室并进行一系列测试
  • 插件 DLL 由测试实验室再次签名,以便使用 DLL 的应用程序可以确定它是否使用经过测试的插件

似乎可以使用

第二次签署 DLL
 signtool /v /f <pfx> /as <dll>

这可能有效的迹象:

  • 文件变大了
  • 该工具打印一条成功消息

但是,显示第二个签名存在一些问题:

  • 虽然 Windows 资源管理器显示“签名列表”,但它只显示一个证书
  • C# X509Certificate.CreateFromSignedFile() 方法只能返回一个证书

目前我实际上是在 EXE 文件而不是 DLL 文件上尝试我的代码,但这应该无关紧要。 EXE 已经使用受信任的根证书和时间戳进行了签名。第二个签名是用 my own certificate following these steps 创建的目前没有时间戳。

提问前我做的事情:

  • 在 Stackoverflow 上搜索现有答案
  • 在 Google 上搜索工具

到目前为止我发现的唯一相关问题是 How does one correctly dual-sign with a timestamp但它没有答案。

最佳答案

我最近实现了自己执行此操作的代码。我无法发布完整的解决方案,因为它嵌入在更大的静态分析工具中,但下面使用 WinVerifyTrust() 提供了一个工作的准系统 C# 控制台应用程序的代码,该应用程序枚举指定文件路径中的 Authenticode 签名。 Windows API 函数在 this Knowledge Base article 的帮助下.

注意事项:

  1. 仅 Windows 8 和 Windows Server 2012(或更高版本)支持枚举多个证书。早期版本的 Windows 只会报告存在零个或一个证书。
  2. 此处提供的代码仅处理有效签名的文件和没有 Authenticode 签名的文件。它不能正确处理带有无效签名的文件。这是留给读者的练习。

代码如下:

using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace ReadAuthenticodeSignatures
{
internal static class Program
{
internal static void Main(string[] args)
{
string fileName = args[0];

IntPtr hWind = IntPtr.Zero;

Guid WINTRUST_ACTION_GENERIC_VERIFY_V2 = new Guid("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}");
byte[] actionIdBytes = WINTRUST_ACTION_GENERIC_VERIFY_V2.ToByteArray();

IntPtr pcwszFilePath = Marshal.StringToHGlobalAuto(fileName);

try
{
WINTRUST_FILE_INFO File = new WINTRUST_FILE_INFO()
{
cbStruct = Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)),
pcwszFilePath = pcwszFilePath,
hFile = IntPtr.Zero,
pgKnownSubject = IntPtr.Zero,
};

IntPtr ptrFile = Marshal.AllocHGlobal(File.cbStruct);

try
{
Marshal.StructureToPtr(File, ptrFile, false);

WINTRUST_DATA WVTData = new WINTRUST_DATA()
{
cbStruct = Marshal.SizeOf(typeof(WINTRUST_DATA)),
pPolicyCallbackData = IntPtr.Zero,
pSIPClientData = IntPtr.Zero,
dwUIChoice = WTD_UI_NONE,
fdwRevocationChecks = WTD_REVOKE_NONE,
dwUnionChoice = WTD_CHOICE_FILE,
pFile = ptrFile,
dwStateAction = WTD_STATEACTION_IGNORE,
hWVTStateData = IntPtr.Zero,
pwszURLReference = IntPtr.Zero,
dwProvFlags = WTD_REVOCATION_CHECK_NONE,
dwUIContext = WTD_UICONTEXT_EXECUTE,
pSignatureSettings = IntPtr.Zero,
};

// N.B. Use of this member is only supported on Windows 8 and Windows Server 2012 (and later)
WINTRUST_SIGNATURE_SETTINGS signatureSettings = default(WINTRUST_SIGNATURE_SETTINGS);

bool canUseSignatureSettings = Environment.OSVersion.Version > new Version(6, 2, 0, 0);
IntPtr pSignatureSettings = IntPtr.Zero;

if (canUseSignatureSettings)
{
// Setup WINTRUST_SIGNATURE_SETTINGS to get the number of signatures in the file
signatureSettings = new WINTRUST_SIGNATURE_SETTINGS()
{
cbStruct = Marshal.SizeOf(typeof(WINTRUST_SIGNATURE_SETTINGS)),
dwIndex = 0,
dwFlags = WSS_GET_SECONDARY_SIG_COUNT,
cSecondarySigs = 0,
dwVerifiedSigIndex = 0,
pCryptoPolicy = IntPtr.Zero,
};

pSignatureSettings = Marshal.AllocHGlobal(signatureSettings.cbStruct);
}

try
{
if (pSignatureSettings != IntPtr.Zero)
{
Marshal.StructureToPtr(signatureSettings, pSignatureSettings, false);
WVTData.pSignatureSettings = pSignatureSettings;
}

IntPtr pgActionID = Marshal.AllocHGlobal(actionIdBytes.Length);

try
{
Marshal.Copy(actionIdBytes, 0, pgActionID, actionIdBytes.Length);

IntPtr pWVTData = Marshal.AllocHGlobal(WVTData.cbStruct);

try
{
Marshal.StructureToPtr(WVTData, pWVTData, false);

int hRESULT = WinVerifyTrust(hWind, pgActionID, pWVTData);

if (hRESULT == 0)
{
if (pSignatureSettings != IntPtr.Zero)
{
// Read back the signature settings
signatureSettings = (WINTRUST_SIGNATURE_SETTINGS)Marshal.PtrToStructure(pSignatureSettings, typeof(WINTRUST_SIGNATURE_SETTINGS));
}

int signatureCount = signatureSettings.cSecondarySigs + 1;

Console.WriteLine("File: {0}", fileName);
Console.WriteLine("Authenticode signatures: {0}", signatureCount);
Console.WriteLine();

for (int dwIndex = 0; dwIndex < signatureCount; dwIndex++)
{
if (pSignatureSettings != IntPtr.Zero)
{
signatureSettings.dwIndex = dwIndex;
signatureSettings.dwFlags = WSS_VERIFY_SPECIFIC;

Marshal.StructureToPtr(signatureSettings, pSignatureSettings, false);
}

WVTData.dwStateAction = WTD_STATEACTION_VERIFY;
WVTData.hWVTStateData = IntPtr.Zero;

Marshal.StructureToPtr(WVTData, pWVTData, false);

hRESULT = WinVerifyTrust(hWind, pgActionID, pWVTData);

try
{
if (hRESULT == 0)
{
WVTData = (WINTRUST_DATA)Marshal.PtrToStructure(pWVTData, typeof(WINTRUST_DATA));

IntPtr ptrProvData = WTHelperProvDataFromStateData(WVTData.hWVTStateData);

CRYPT_PROVIDER_DATA provData = (CRYPT_PROVIDER_DATA)Marshal.PtrToStructure(ptrProvData, typeof(CRYPT_PROVIDER_DATA));

for (int idxSigner = 0; idxSigner < provData.csSigners; idxSigner++)
{
IntPtr ptrProvSigner = WTHelperGetProvSignerFromChain(ptrProvData, idxSigner, false, 0);

CRYPT_PROVIDER_SGNR ProvSigner = (CRYPT_PROVIDER_SGNR)Marshal.PtrToStructure(ptrProvSigner, typeof(CRYPT_PROVIDER_SGNR));
CMSG_SIGNER_INFO Signer = (CMSG_SIGNER_INFO)Marshal.PtrToStructure(ProvSigner.psSigner, typeof(CMSG_SIGNER_INFO));

if (Signer.HashAlgorithm.pszObjId != IntPtr.Zero)
{
string objId = Marshal.PtrToStringAnsi(Signer.HashAlgorithm.pszObjId);

if (objId != null)
{
Oid hashOid = Oid.FromOidValue(objId, OidGroup.All);

if (hashOid != null)
{
Console.WriteLine("Hash algorithm of signature {0}: {1}.", dwIndex + 1, hashOid.FriendlyName);
}
}
}

IntPtr ptrCert = WTHelperGetProvCertFromChain(ptrProvSigner, idxSigner);

CRYPT_PROVIDER_CERT cert = (CRYPT_PROVIDER_CERT)Marshal.PtrToStructure(ptrCert, typeof(CRYPT_PROVIDER_CERT));

if (cert.cbStruct > 0)
{
X509Certificate2 certificate = new X509Certificate2(cert.pCert);
Console.WriteLine("Certificate thumbprint of signature {0}: {1}", dwIndex + 1, certificate.Thumbprint);
}

if (ProvSigner.sftVerifyAsOf.dwHighDateTime != provData.sftSystemTime.dwHighDateTime &&
ProvSigner.sftVerifyAsOf.dwLowDateTime != provData.sftSystemTime.dwLowDateTime)
{
DateTime timestamp = DateTime.FromFileTimeUtc(((long)ProvSigner.sftVerifyAsOf.dwHighDateTime << 32) | (uint)ProvSigner.sftVerifyAsOf.dwLowDateTime);
Console.WriteLine("Timestamp of signature {0}: {1}", dwIndex + 1, timestamp);
}
}
}
}
finally
{
WVTData.dwStateAction = WTD_STATEACTION_CLOSE;
Marshal.StructureToPtr(WVTData, pWVTData, false);

hRESULT = WinVerifyTrust(hWind, pgActionID, pWVTData);
}

Console.WriteLine();
}
}
else if ((uint)hRESULT == 0x800b0100)
{
Console.WriteLine("{0} has no Authenticode signatures.", fileName);
}
}
finally
{
Marshal.FreeHGlobal(pWVTData);
}
}
finally
{
Marshal.FreeHGlobal(pgActionID);
}
}
finally
{
if (pSignatureSettings != IntPtr.Zero)
{
Marshal.FreeHGlobal(pSignatureSettings);
}
}
}
finally
{
Marshal.FreeHGlobal(ptrFile);
}
}
finally
{
Marshal.FreeHGlobal(pcwszFilePath);
}

Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}

private const int SGNR_TYPE_TIMESTAMP = 0x00000010;
private const int WTD_UI_NONE = 2;
private const int WTD_CHOICE_FILE = 1;
private const int WTD_REVOKE_NONE = 0;
private const int WTD_REVOKE_WHOLECHAIN = 1;
private const int WTD_STATEACTION_IGNORE = 0;
private const int WTD_STATEACTION_VERIFY = 1;
private const int WTD_STATEACTION_CLOSE = 2;
private const int WTD_REVOCATION_CHECK_NONE = 16;
private const int WTD_REVOCATION_CHECK_CHAIN = 64;
private const int WTD_UICONTEXT_EXECUTE = 0;
private const int WSS_VERIFY_SPECIFIC = 0x00000001;
private const int WSS_GET_SECONDARY_SIG_COUNT = 0x00000002;

[DllImport("wintrust.dll")]
private static extern int WinVerifyTrust(IntPtr hWind, IntPtr pgActionID, IntPtr pWVTData);

[DllImport("wintrust.dll")]
private static extern IntPtr WTHelperProvDataFromStateData(IntPtr hStateData);

[DllImport("wintrust.dll")]
private static extern IntPtr WTHelperGetProvSignerFromChain(IntPtr pProvData, int idxSigner, bool fCounterSigner, int idxCounterSigner);

[DllImport("wintrust.dll")]
private static extern IntPtr WTHelperGetProvCertFromChain(IntPtr pSgnr, int idxCert);

[StructLayout(LayoutKind.Sequential)]
private struct WINTRUST_DATA
{
internal int cbStruct;
internal IntPtr pPolicyCallbackData;
internal IntPtr pSIPClientData;
internal int dwUIChoice;
internal int fdwRevocationChecks;
internal int dwUnionChoice;
internal IntPtr pFile;
internal int dwStateAction;
internal IntPtr hWVTStateData;
internal IntPtr pwszURLReference;
internal int dwProvFlags;
internal int dwUIContext;
internal IntPtr pSignatureSettings;
}

[StructLayout(LayoutKind.Sequential)]
private struct WINTRUST_SIGNATURE_SETTINGS
{
internal int cbStruct;
internal int dwIndex;
internal int dwFlags;
internal int cSecondarySigs;
internal int dwVerifiedSigIndex;
internal IntPtr pCryptoPolicy;
}

[StructLayout(LayoutKind.Sequential)]
private struct WINTRUST_FILE_INFO
{
internal int cbStruct;
internal IntPtr pcwszFilePath;
internal IntPtr hFile;
internal IntPtr pgKnownSubject;
}

[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_PROVIDER_DATA
{
internal int cbStruct;
internal IntPtr pWintrustData;
internal bool fOpenedFile;
internal IntPtr hWndParent;
internal IntPtr pgActionID;
internal IntPtr hProv;
internal int dwError;
internal int dwRegSecuritySettings;
internal int dwRegPolicySettings;
internal IntPtr psPfns;
internal int cdwTrustStepErrors;
internal IntPtr padwTrustStepErrors;
internal int chStores;
internal IntPtr pahStores;
internal int dwEncoding;
internal IntPtr hMsg;
internal int csSigners;
internal IntPtr pasSigners;
internal int csProvPrivData;
internal IntPtr pasProvPrivData;
internal int dwSubjectChoice;
internal IntPtr pPDSip;
internal IntPtr pszUsageOID;
internal bool fRecallWithState;
internal System.Runtime.InteropServices.ComTypes.FILETIME sftSystemTime;
internal IntPtr pszCTLSignerUsageOID;
internal int dwProvFlags;
internal int dwFinalError;
internal IntPtr pRequestUsage;
internal int dwTrustPubSettings;
internal int dwUIStateFlags;
}

[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_PROVIDER_SGNR
{
internal int cbStruct;
internal System.Runtime.InteropServices.ComTypes.FILETIME sftVerifyAsOf;
internal int csCertChain;
internal IntPtr pasCertChain;
internal int dwSignerType;
internal IntPtr psSigner;
internal int dwError;
internal int csCounterSigners;
internal IntPtr pasCounterSigners;
internal IntPtr pChainContext;
}

[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_PROVIDER_CERT
{
internal int cbStruct;
internal IntPtr pCert;
internal bool fCommercial;
internal bool fTrustedRoot;
internal bool fSelfSigned;
internal bool fTestCert;
internal int dwRevokedReason;
internal int dwConfidence;
internal int dwError;
internal IntPtr pTrustListContext;
internal bool fTrustListSignerCert;
internal IntPtr pCtlContext;
internal int dwCtlError;
internal bool fIsCyclic;
internal IntPtr pChainElement;
}

[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_ALGORITHM_IDENTIFIER
{
internal IntPtr pszObjId;
internal CRYPT_INTEGER_BLOB Parameters;
}

[StructLayout(LayoutKind.Sequential)]
private struct CMSG_SIGNER_INFO
{
internal int dwVersion;
internal CRYPT_INTEGER_BLOB Issuer;
internal CRYPT_INTEGER_BLOB SerialNumber;
internal CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
internal CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
internal CRYPT_INTEGER_BLOB EncryptedHash;
internal CRYPT_ATTRIBUTES AuthAttrs;
internal CRYPT_ATTRIBUTES UnauthAttrs;
}

[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_INTEGER_BLOB
{
internal int cbData;
internal IntPtr pbData;
}

[StructLayout(LayoutKind.Sequential)]
private struct CRYPT_ATTRIBUTES
{
internal int cAttr;
internal IntPtr rgAttr;
}
}
}

针对 SQL Server 2014 SP1 安装程序运行应用程序会在 Windows 8.1 上提供以下输出:

File: SQLServer2014SP1-KB3058865-x64-ENU.exe
Authenticode signatures: 2

Hash algorithm of signature 1: sha1.
Certificate thumbprint of signature 1: 67B1757863E3EFF760EA9EBB02849AF07D3A8080
Timestamp of signature 1: 22/04/2015 06:03:40

Hash algorithm of signature 2: sha256.
Certificate thumbprint of signature 2: 76DAF3E30F95B244CA4D6107E0243BB97F7DF965
Timestamp of signature 2: 22/04/2015 06:03:51

Press enter to exit.

关于c# - 如何使用 Authenticode 对二进制文件进行双重签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21547311/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com