直接嵌入在文件里的签名信息获取很简单,文件上右键属性-签名信息就可以看到
catlog签名稍微麻烦一下,
1.如果只是想验证签名,用WinVerifyTrust这样的high level api即可,示例代码如下(from sysinternal:https://forum.sysinternals.com/howto-verify-the-digital-signature-of-a-file_topic19247.html)
#include <windows.h>
#include <wincrypt.h>
#include <mscat.h>
#include <wintrust.h>
#include <SoftPub.h>
#pragma comment (lib, "wintrust")
BOOL CheckMSSignature111(LPCWSTR lpFileName)
{
BOOL bRet = FALSE;
HCATADMIN hCatAdmin = NULL;
if (!CryptCATAdminAcquireContext(&hCatAdmin, NULL, 0))
return FALSE;
HANDLE hFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
CryptCATAdminReleaseContext(hCatAdmin, 0);
return FALSE;
}
DWORD dwCnt = 100;
BYTE byHash[100];
CryptCATAdminCalcHashFromFileHandle(hFile, &dwCnt, byHash, 0);
CloseHandle(hFile);
LPWSTR pszMemberTag = new WCHAR[dwCnt * 2 + 1];
for (DWORD dw = 0; dw < dwCnt; ++dw)
{
wsprintfW(&pszMemberTag[dw * 2], L"%02X", byHash[dw]);
}
WINTRUST_DATA wd = { 0 };
WINTRUST_FILE_INFO wfi = { 0 };
WINTRUST_CATALOG_INFO wci = { 0 };
CATALOG_INFO ci = { 0 };
HCATINFO hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, byHash, dwCnt, 0, NULL);
if (NULL == hCatInfo)
{
wfi.cbStruct = sizeof(WINTRUST_FILE_INFO);
wfi.pcwszFilePath = lpFileName;
wfi.hFile = NULL;
wfi.pgKnownSubject = NULL;
wd.cbStruct = sizeof(WINTRUST_DATA);
wd.dwUnionChoice = WTD_CHOICE_FILE;
wd.pFile = &wfi;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOKE_NONE;
wd.dwStateAction = WTD_STATEACTION_IGNORE;
wd.dwProvFlags = WTD_SAFER_FLAG;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
}
else
{
CryptCATCatalogInfoFromContext(hCatInfo, &ci, 0);
wci.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
wci.pcwszCatalogFilePath = ci.wszCatalogFile;
wci.pcwszMemberFilePath = lpFileName;
wci.pcwszMemberTag = pszMemberTag;
wd.cbStruct = sizeof(WINTRUST_DATA);
wd.dwUnionChoice = WTD_CHOICE_CATALOG;
wd.pCatalog = &wci;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_STATEACTION_VERIFY;
wd.dwProvFlags = 0;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
}
GUID action = WINTRUST_ACTION_GENERIC_VERIFY_V2;
HRESULT hr = WinVerifyTrust(NULL, &action, &wd);
bRet = SUCCEEDED(hr);
if (NULL != hCatInfo)
CryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0);
CryptCATAdminReleaseContext(hCatAdmin, 0);
delete[] pszMemberTag;
return bRet;
}
2.如果要获取详细的签名人名称等信息,从上面的代码里CryptCATAdminEnumCatalogFromHash返回的ci.wszCatalogFile;里得到catlog文件的全路径后,继续解析,示例代码如下,(from https://support.microsoft.com/en-us/kb/323809)(入参为catlog文件的全路径,如
C:\\windows\\system32\\CatRoot\\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\\Package_4_for_KB3046017~31bf3856ad364e35~amd64~~6.1.1.1.cat"
BOOL GetSignName(LPCWSTR lpszCatFile, CString& strSignName)
{ CString strFile = lpszCatFile;
if (strFile.IsEmpty())
{
return FALSE;
}
BOOL fResult;
DWORD dwEncoding, dwContentType, dwFormatType;
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
//查询签名信息
fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
(LPVOID)strFile.GetBuffer(),
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&dwEncoding,
&dwContentType,
&dwFormatType,
&hStore,
&hMsg,
NULL);
if (!fResult)
{
WRITE_LOG(_T("CryptQueryObject failed with %x\n"), GetLastError());
return FALSE;
}
// Get signer information size.
DWORD dwSignerInfo;
fResult = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
NULL,
&dwSignerInfo);
if (!fResult)
{
WRITE_LOG(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
return FALSE;
}
// Allocate memory for signer information.
PCMSG_SIGNER_INFO pSignerInfo = NULL;
pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
if (!pSignerInfo)
{
WRITE_LOG(_T("Unable to allocate memory for Signer Info.\n"));
return FALSE;
}
// Get Signer Information.
fResult = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
(PVOID)pSignerInfo,
&dwSignerInfo);
if (!fResult)
{
WRITE_LOG(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
return FALSE;
}
// Search for the signer certificate in the temporary
// certificate store.
CERT_INFO CertInfo;
CertInfo.Issuer = pSignerInfo->Issuer;
CertInfo.SerialNumber = pSignerInfo->SerialNumber;
PCCERT_CONTEXT pCertContext = CertFindCertificateInStore(hStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo,
NULL);
if (!pCertContext)
{
WRITE_LOG(_T("CertFindCertificateInStore failed with %x\n"),
GetLastError());
return FALSE;
}
LPTSTR szName = NULL;
DWORD dwData;
if (!(dwData = CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
NULL,
0)))
{
WRITE_LOG(_T("CertGetNameString failed.\n"));
return FALSE;
}
// Allocate memory for subject name.
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
if (!szName)
{
WRITE_LOG(_T("Unable to allocate memory for subject name.\n"));
return FALSE;
}
// Get subject name.
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
szName,
dwData)))
{
WRITE_LOG(_T("CertGetNameString failed.\n"));
return FALSE;
}
strSignName = szName;
return TRUE;
}