如何使用Authenticode对二进制文件进行双重签名? [英] How to dual sign a binary with Authenticode?

查看:115
本文介绍了如何使用Authenticode对二进制文件进行双重签名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简短问题

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

How can I get information about multiple code signing certificates from an executable (.EXE/.DLL)?

期望的答案

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

The final accepted answer should propose a way to get all certificates in C#. Concept / pseudo code is ok, I don't expect you to write the full source.

有关建议该工具的中间答案,请参见我对Security.StackExchange的问题

For an intermediate answer suggesting a tool, please see my question on Security.StackExchange.

常见问题

我正在研究是否可以在插件(.DLL)上使用多个代码签名证书来检查它是否是否经过正式测试。步骤如下:

I am researching whether we could use multiple code signing certificates on a plugin (.DLL) to check whether it has been officially tested or not. This is the procedure:


  • 插件DLL就像其他任何应用程序一样由供应商签名

  • 插件DLL进入测试实验室并进行了一系列测试

  • 插件DLL被测试实验室再次签名,以便使用DLL的应用程序可以确定它是否正在使用

似乎有可能使用

 signtool /v /f <pfx> /as <dll>

可能已奏效的指示:


  • 文件大小增加

  • 该工具会打印成功消息

但是,有些问题显示了第二个签名:

However, there are some issues showing the second signature:


  • 尽管Windows资源管理器显示签名列表,但仅显示一个证书

  • C# X509Certificate.CreateFromSignedFile()方法只能返回一个证书

  • although Windows Explorer says "Signature list", it shows only one certificate
  • the C# X509Certificate.CreateFromSignedFile() method can only return one certificate

此刻,我实际上是在EXE文件而不是DLL文件上尝试我的代码,但这无关紧要。 EXE已使用受信任的根证书和时间戳进行签名。第二个签名是通过创建的我自己遵循以下步骤的证书,目前没有时间戳。

At the moment I'm actually trying my code on an EXE file rather than a DLL file, but that shouldn't matter. The EXE is already signed with a trusted root certificate and a timestamp. The second signature is created with my own certificate following these steps currently without a timestamp.

我在问问题之前所做的事情:

Things I did before asking the question:


  • 在Stackoverflow上搜索现有答案

  • 在Google上搜索工具

我到目前为止发现的唯一相关问题是如何正确地使用时间戳进行双重签名,但没有答案。

The only related question I found so far is How does one correctly dual-sign with a timestamp but it doesn't have an answer.

推荐答案

我最近实现了自己执行代码。我无法发布完整的解决方案,因为它已嵌入较大的静态分析工具中,但是下面使用 WinVerifyTrust() Windows API函数与此知识库文章

I have recently implemented code to do this myself. I can't post the full solution as it is embedded in a larger static analysis tool, but the code for a working bare-bones C# console application that enumerates the Authenticode signatures in a specified file path is provided below using the WinVerifyTrust() Windows API function with assistance from 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上提供以下输出:

Running the application against the SQL Server 2014 SP1 installer gives the following output on 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.

这篇关于如何使用Authenticode对二进制文件进行双重签名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆