从可执行文件中读取和验证证书

15
我想要验证已签名可执行文件的证书(通过验证,我的意思是判断签名是否来自微软/Adobe/Oracle等公司)。Windows提供了用于此任务的API吗?我该如何做到这一点,我不知道。任何帮助都将不胜感激。
我正在使用Windows和C ++。我想要验证本机可执行文件,而不是.NET程序集或Java jar文件。
更新:
好的,我会尽量简短地描述我想要的内容。
1)验证PE证书。签名是否有效。当签名嵌入在PE中时,它应该起作用,并且当签名在安全目录中时也应该起作用。(我在Sysinternals论坛上找到了这个功能,并且运行良好,所以我不需要这个了)。
2)告诉文件的签署者/发布者是谁。我知道可以通过CryptQueryObject实现这一点(我找到了一个可行的示例,但无法用于安全目录),但不知道如何将其与安全目录文件一起使用。
3个回答

24

有许多API和方法可以获取和验证可执行文件的签名,并获得其他所需的附加信息。问题在于选择哪个级别(例如高级别如 WinVerifyTrust)。

从CAT或EXE文件中获取密码学上下文的最简单的API是 CryptQueryObject 函数。来自KB323809的代码示例可以帮助你了解如何解码所需的信息。如果您使用的是CAT文件,则应修改一些CryptQueryObject的参数。我建议您只使用 CERT_QUERY_CONTENT_FLAG_ALLCERT_QUERY_FORMAT_FLAG_ALL,并且 CryptQueryObject 会在内部完成所有需要的工作:

BOOL bIsSuccess;
DWORD dwEncoding, dwContentType, dwFormatType;
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PVOID pvContext = NULL;

// fill szFileName
...

// Get message handle and store handle from the signed file.
bIsSuccess = CryptQueryObject (CERT_QUERY_OBJECT_FILE,
                               szFileName,
                               CERT_QUERY_CONTENT_FLAG_ALL,
                               CERT_QUERY_FORMAT_FLAG_ALL,
                               0,
                               &dwEncoding,
                               &dwContentType,
                               &dwFormatType,
                               &hStore,
                               &hMsg,
                               &pvContext);
dwContentTypeCryptQueryObject设置,可以获取有关文件szFileName类型的基本信息。对于大多数情况下需要的pvContext将为PCCERT_CONTEXT,但如果使用“.ctl”或“.crl”文件作为输入,则可能为PCCRL_CONTEXTPCCTL_CONTEXT 。您将收到填充有来自文件szFileName中所有证书的hStore。因此,关于pvContexthStore,您可以使用CryptoAPI检查文件内容。如果您喜欢低级别的消息API,则可以使用hMsg(至少对于一些dwContentType,例如CERT_QUERY_CONTENT_PKCS7_SIGNEDCERT_QUERY_CONTENT_PKCS7_UNSIGNEDCERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED )。

要验证文件的签名,我建议您使用CertGetCertificateChainCertVerifyCertificateChainPolicy进行验证,以验证证书不仅在一般情况下有效,而且(或其所有父项)对于authenticode有效(szOID_PKIX_KP_CODE_SIGNING)。 CertGetCertificateChain可以用于不同的吊销场景。您应该使用CERT_CHAIN_POLICY_AUTHENTICODECERT_CHAIN_POLICY_AUTHENTICODE_TS进行两个单独的调用,以验证Authenticode链策略和Authenticode Time Stamp链策略都有效。

更新:我重新阅读了您当前的问题(更新部分)。您当前的问题是如何获取文件的签名者/发布者。因此,我只回答这个问题。

如果您使用sysinternal的代码进行签名验证,只需搜索以下行:

if ( !CryptCATCatalogInfoFromContext(CatalogContext, &InfoStruct, 0) )
该语句将设置 InfoStruct 的字段,以防该文件是系统Windows文件,并且已通过某个 .cat 文件验证了签名。字段 InfoStruct.wszCatalogFile 将获取 .cat 文件的名称。
例如,在我的 Windows 7 上,如果我尝试验证 C:\Windows\explorer.exe 文件的数字签名,则可以找到其哈希值的 .cat 位于 C:\Windows\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Package_1_for_KB2515325~31bf3856ad364e35~amd64~~6.1.1.0.cat
如果您使用来自KB323809的代码和上述描述的CryptQueryObject参数,您将解码位于C:\Windows\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Package_1_for_KB2515325~31bf3856ad364e35~amd64~~6.1.1.0.cat(请参见函数GetProgAndPublisherInfo)的SPC_SP_OPUS_INFO_OBJID("1.3.6.1.4.1.311.2.1.12")属性,然后您将知道...
pwszProgramName: "Windows Express Security Catalogs"
pPublisherInfo: NULL
pMoreInfo->dwLinkChoice: SPC_URL_LINK_CHOICE
pMoreInfo->pwszUrl "http://www.microsoft.com"

因此,该文件中不包含任何特殊的发布者信息。如果您检查目录的签名者,您将发现:

The signer of the .cat file: "Microsoft Windows"
The signer signed it with the certificate:
    Serial Number: 0x6115230F00000000000A
    Issuer Name: Microsoft Windows Verification PCA
    Full Issuer Name:
        CN = Microsoft Windows Verification PCA
        O = Microsoft Corporation
        L = Redmond
        S = Washington
        C = US
    Subject Name: Microsoft Windows
    Full Subject Name:
        CN = Microsoft Windows
        OU = MOPR
        O = Microsoft Corporation
        L = Redmond
        S = Washington
        C = US
The Date of TimeStamp : 28.02.2011 21:16:36
TimeStamp Certificate: 
    Serial Number: 0x6103DCF600000000000C
    Issuer Name: Microsoft Time-Stamp PCA
    Subject Name: Microsoft Time-Stamp Service

因此,您应该仅使用.cat文件的签名者,因为没有其他人签署了explorer.exe


1
@Davita:如果您尝试使用CryptQueryObject检查任何文本文件或未签名的可执行文件(如explorer.exe),则会收到CRYPT_E_NO_MATCH错误。如果您检查explorer.exe的属性,您将看不到“数字签名”选项卡,因此该文件未经签名。如果您在实现中遇到其他问题,可以向我提问。几年前,我花了很多时间编写带有代码签名的EXE、CAT等文件,所以我可能能够快速帮助您。 - Oleg
1
@Davita:不客气!我很高兴能帮到你。如果你在这个主题上遇到更多问题,我很乐意再次帮助你。 - Oleg
1
@vitr:不用谢!如果不知道你使用的场景,很难回答你的问题。你有一些CAT文件作为输入或者EXE文件(或其他签名文件)作为输入吗?如果你只有EXE文件作为输入,那么它不包含对CAT文件的引用。你想要做什么? - Oleg
1
@vitr:.CAT文件实际上是文件哈希值的列表,这些哈希值应被解释为“有效”。在许多情况下,甚至不会将文件名(exe名称)或文件路径保存为.CAT文件的属性。在某些软件产品(例如驱动程序)安装期间,Windows会将相应的.CAT文件复制到C:\Windows\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}文件夹中,并将CAT文件中的所有哈希值包含在公共索引中。这允许通过简单调用CryptCATAdminAcquireContext、CryptCATAdminCalcHashFromFileHandle函数来获取CatFileName。 - Oleg
这在内核模式下能工作吗?如何在内核模式下获取PE签名信息? - Anup
显示剩余13条评论

5

WinVerifyTrust函数会对指定的对象执行信任验证操作。如果存在支持该操作标识符的信任提供程序,则该函数将查询传递给它。

要进行证书验证,请使用CertGetCertificateChain和CertVerifyCertificateChainPolicy函数。


谢谢John,我尝试了MSDN提供的示例,几乎每次都很好用,除了当我尝试验证诸如explorer.exe之类的Windows核心文件时。它说explorer.exe没有签名,但PeExplorer告诉我explorer.exe的签名已经验证。我很困惑,不知道我错过了什么... - Davita
1
系统文件的哈希值存储在一个签名的目录文件中。请参见此处的代码:http://forum.sysinternals.com/howto-verify-the-digital-signature-of-a-file_topic19247.html - Bevan Collins
@Bevan Collins,非常感谢,它很好地工作了 :) 请问我该如何检索证书信息,例如谁签署了证书?谢谢。 - Davita
如何从Authenticode签名的可执行文件中获取信息 http://support.microsoft.com/default.aspx?scid=kb;en-us;323809 - Bevan Collins
非常感谢您,Bevan。我已经尝试了那段代码,但它在安全目录上不起作用。我不知道如何在目录中使用CryptQueryObject,并且在网上找不到任何信息。 :( - Davita

1

@Davita 我仔细阅读了上述问题并尝试解决。

我的建议是在CryptQueryObject()的第三个参数中尝试使用CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED而不是CERT_QUERY_CONTENT_FLAG_ALL


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接