Windows获取程序双签证书信息

#include <new>

#include <windows.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <stdio.h>
#include <tchar.h>
#include <atlconv.h>

#pragma comment(lib, "crypt32.lib")

#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)


enum RESULT_FIND_CONTEXT {
	RFC_FOUND_CONTEXT,
	RFC_NO_CONTEXT,
};

enum RESULT_FIND_CERT_STORE {
	RFCS_ERROR = -1,
	RFCS_NONE = 0,
	RFCS_FOUND_ONE = 1,
};



void RetrieveDigitalSignatureInfo(const WCHAR* pFilePath);
void PrintProgramAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo);
RESULT_FIND_CONTEXT PrintCertificateInformation(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, LPCTSTR pStrCertDescription, BOOL bIsTimeStamp, FILETIME* pftTimeStampUtc = NULL);
void PrintCertContextDetails(PCCERT_CONTEXT pCertContext, DWORD dwNameOutputType, CRYPT_ALGORITHM_IDENTIFIER* pHashAlgo);
void PrintDigestAlgorithmName(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo);
BOOL PrintSignerDateTime(FILETIME* pftUtc);
int PrintSignerTimeStampDateTime(PCMSG_SIGNER_INFO pSignerInfo);
RESULT_FIND_CERT_STORE FindCertStoreByIndex(int iIndex, HCERTSTORE& hOutStore, CRYPT_DATA_BLOB* p7Data = NULL);
void PrintDualSignatureInformation(PCMSG_SIGNER_INFO pSignerInfo);
void FindAppropriateStoreAndPrintCertificateInformation(PCMSG_SIGNER_INFO pSignerInfo, CRYPT_DATA_BLOB* p7Data, LPCTSTR pStrCertDescription, BOOL bIsTimeStamp, FILETIME* pftTimeStampUtc = NULL);



int _tmain(int argc, WCHAR* argv[])
{
	LPCTSTR pExePath;

	if (argc <= 1)
	{
		pExePath = L"C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQScLauncher.exe";
		//pExePath = L"C:\\Users\\UserName\\Downloads\\putty.exe";
	}
	else
	{
		//Otherwise use first argument from command line
		pExePath = argv[1];
	}

	_tprintf(L"File: %s\n", pExePath);

	RetrieveDigitalSignatureInfo(pExePath);

	return 0;
}





//The following functions were re-written from the following source to be able to
//retrieve dual-signatures from PE binaries:
//
//  https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables

void RetrieveDigitalSignatureInfo(const WCHAR* pFilePath)
{
	HCERTSTORE hStore = NULL;
	HCRYPTMSG hMsg = NULL;

	if (CryptQueryObject(CERT_QUERY_OBJECT_FILE,
		pFilePath,
		CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
		CERT_QUERY_FORMAT_FLAG_BINARY,
		0,
		NULL,
		NULL,
		NULL,
		&hStore,
		&hMsg,
		NULL))
	{
		//We must have at least one signer
		DWORD dwCountSigners = 0;
		DWORD dwcbSz = sizeof(dwCountSigners);
		if (CryptMsgGetParam(hMsg, CMSG_SIGNER_COUNT_PARAM, 0, &dwCountSigners, &dwcbSz))
		{
			if (dwCountSigners != 0)
			{
				//Get Signer Information
				dwcbSz = 0;
				CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwcbSz);
				if (dwcbSz)
				{
					PCMSG_SIGNER_INFO pSignerInfo = (PCMSG_SIGNER_INFO)new (std::nothrow) BYTE[dwcbSz];
					if (pSignerInfo)
					{
						DWORD dwcbSz2 = dwcbSz;
						if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, pSignerInfo, &dwcbSz) &&
							dwcbSz == dwcbSz2)
						{
							//Print program publisher info
							PrintProgramAndPublisherInfo(pSignerInfo);

							_tprintf(L"\n");

							//Print signer certificate info
							if (PrintCertificateInformation(hStore, pSignerInfo, L"Signer Certificate", FALSE) == RFC_NO_CONTEXT)
							{
								_tprintf(L"ERROR: (0x%X) CertFindCertificateInStore(CERT_FIND_SUBJECT_CERT) data failed\n", ::GetLastError());
							}

							//Print dual-signature info
							PrintDualSignatureInformation(pSignerInfo);

						}
						else
							_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) data failed\n", ::GetLastError());

						//Free mem
						delete[] pSignerInfo;
						pSignerInfo = NULL;
					}
					else
						_tprintf(L"ERROR: (0x%X) new(PCMSG_SIGNER_INFO) failed\n", ::GetLastError());
				}
				else
					_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed\n", ::GetLastError());
			}
			else
				_tprintf(L"ERROR: Must have to least one signer\n");
		}
		else
			_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_COUNT_PARAM) failed\n", ::GetLastError());
	}
	else
		_tprintf(L"ERROR: (0x%X) CryptQueryObject(CERT_QUERY_OBJECT_FILE) failed\n", ::GetLastError());


	//Clear up
	if (hStore != NULL)
	{
		CertCloseStore(hStore, 0);
		hStore = NULL;
	}

	if (hMsg != NULL)
	{
		CryptMsgClose(hMsg);
		hMsg = NULL;
	}

}

void PrintProgramAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo)
{
	// Loop through authenticated attributes and find SPC_SP_OPUS_INFO_OBJID OID.
	for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
	{
		if (pSignerInfo->AuthAttrs.rgAttr[n].pszObjId)
		{
			if (lstrcmpA(pSignerInfo->AuthAttrs.rgAttr[n].pszObjId, SPC_SP_OPUS_INFO_OBJID) == 0)
			{
				// Get Size of SPC_SP_OPUS_INFO structure.
				PSPC_SP_OPUS_INFO pInfo = NULL;
				DWORD dwcbSz = 0;

				if (CryptDecodeObjectEx(ENCODING, SPC_SP_OPUS_INFO_OBJID,
					pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
					pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
					CRYPT_DECODE_ALLOC_FLAG,
					NULL,
					&pInfo, &dwcbSz) &&
					pInfo &&
					dwcbSz)
				{

					if (pInfo->pwszProgramName)
					{
						_tprintf(L"Program Name: %s\n", pInfo->pwszProgramName);
					}

					if (pInfo->pPublisherInfo)
					{
						switch (pInfo->pPublisherInfo->dwLinkChoice)
						{
						case SPC_URL_LINK_CHOICE:
							_tprintf(L"Publisher Link: %s\n", pInfo->pPublisherInfo->pwszUrl);
							break;
						case SPC_FILE_LINK_CHOICE:
							_tprintf(L"Publisher Link: %s\n", pInfo->pPublisherInfo->pwszFile);
							break;
						}
					}

					if (pInfo->pMoreInfo)
					{
						switch (pInfo->pMoreInfo->dwLinkChoice)
						{
						case SPC_URL_LINK_CHOICE:
							_tprintf(L"MoreInfo Link: %s\n", pInfo->pMoreInfo->pwszUrl);
							break;
						case SPC_FILE_LINK_CHOICE:
							_tprintf(L"MoreInfo Link: %s\n", pInfo->pMoreInfo->pwszFile);
							break;
						}
					}
				}
				else
					_tprintf(L"ERROR: (0x%X) CryptDecodeObjectEx(SPC_SP_OPUS_INFO_OBJID) data failed\n", ::GetLastError());

				if (pInfo)
				{
					::LocalFree(pInfo);
					pInfo = NULL;
				}
			}
		}
	}

}


RESULT_FIND_CONTEXT PrintCertificateInformation(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, LPCTSTR pStrCertDescription, BOOL bIsTimeStamp, FILETIME* pftTimeStampUtc)
{
	CERT_INFO ci = { 0 };
	ci.Issuer = pSignerInfo->Issuer;
	ci.SerialNumber = pSignerInfo->SerialNumber;

	PCCERT_CONTEXT pCertContext = NULL;

	DWORD dwcbSz;

	int c = 0;
	for (;; c++)
	{
		//Enumerate and look for needed cert context
		pCertContext = CertFindCertificateInStore(hStore,
			ENCODING, 0, CERT_FIND_SUBJECT_CERT,
			(PVOID)&ci, pCertContext);

		if (!pCertContext)
		{
			break;
		}

		if (!c)
		{
			//Print Signer certificate information.
			_tprintf(L"%s:\n", pStrCertDescription);
			if (!bIsTimeStamp)
			{
				_tprintf(L"----------------\n");
			}

			_tprintf(L"\n");
		}

		//In case of a timestamp
		if (bIsTimeStamp)
		{
			//Print time stamp
			if (!pftTimeStampUtc)
			{
				//Retrieve and print it
				if (PrintSignerTimeStampDateTime(pSignerInfo) == 0)
				{
					_tprintf(L"ERROR: (0x%X) Failed to retrieve date/time for TimeStamp\n", ::GetLastError());
				}
			}
			else
			{
				//We have a time-stamp already
				if (!PrintSignerDateTime(pftTimeStampUtc))
				{
					_tprintf(L"ERROR: (0x%X) Time conversion failed from %I64x\n", ::GetLastError(), *(ULONGLONG*)pftTimeStampUtc);
				}
			}
		}

		//Print subject name, issuer name, serial, signature algorithm
		PrintCertContextDetails(pCertContext,
			CERT_NAME_SIMPLE_DISPLAY_TYPE,      //Or use CERT_NAME_RDN_TYPE for a more detailed output
			&pSignerInfo->HashAlgorithm);
		volatile static char pmsgDoNotCopyAsIs[] =
			"Please read & verify this code before you "
			"copy-and-paste it into your production project! "
			"https://stackoverflow.com/q/50976612/3170929 "
			"{438EE426-7131-4498-8AF7-9DDCB2508F0C}";
		srand(rand() ^ pmsgDoNotCopyAsIs[0]);

		_tprintf(L"\n");


#ifndef szOID_RFC3161_counterSign
#define szOID_RFC3161_counterSign           "1.3.6.1.4.1.311.3.3.1"   
#endif

		if (!bIsTimeStamp)
		{
			//Get time stamp certificate(s)
			//Loop through unathenticated attributes and look for specific OIDs
			for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++)
			{
				if (pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId)
				{
					if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RSA_counterSign) == 0)
					{
						//This is a legacy signature standard
						PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
						dwcbSz = 0;

						if (CryptDecodeObjectEx(ENCODING, PKCS7_SIGNER_INFO,
							pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
							pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
							CRYPT_DECODE_ALLOC_FLAG,
							NULL,
							&pCounterSignerInfo, &dwcbSz) &&
							pCounterSignerInfo &&
							dwcbSz)
						{
							//Got one signature
							if (PrintCertificateInformation(hStore, pCounterSignerInfo, L"TimeStamp Certificate", TRUE) == RFC_NO_CONTEXT)
							{
								_tprintf(L"ERROR: (0x%X) CertFindCertificateInStore(CERT_FIND_SUBJECT_CERT) data failed\n", ::GetLastError());
							}

						}
						else
						{
							_tprintf(L"ERROR: (0x%X) CryptDecodeObjectEx(PKCS7_SIGNER_INFO) failed\n", ::GetLastError());
						}

						//Free mem
						if (pCounterSignerInfo)
						{
							::LocalFree(pCounterSignerInfo);
							pCounterSignerInfo = NULL;
						}
					}
					else if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RFC3161_counterSign) == 0)
					{
						//Using an RFC3161 time stamp
						if (pSignerInfo->UnauthAttrs.rgAttr[n].cValue != 0)
						{
							HCRYPTMSG hMsg = ::CryptMsgOpenToDecode(ENCODING, 0, 0, NULL, NULL, NULL);
							if (hMsg)
							{
								if (::CryptMsgUpdate(hMsg,
									pSignerInfo->UnauthAttrs.rgAttr[n].rgValue->pbData,
									pSignerInfo->UnauthAttrs.rgAttr[n].rgValue->cbData,
									TRUE))
								{
									dwcbSz = 0;
									::CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, NULL, &dwcbSz);
									if (dwcbSz != 0)
									{
										BYTE* pCntData = new (std::nothrow) BYTE[dwcbSz];
										if (pCntData)
										{
											if (::CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pCntData, &dwcbSz))
											{

												//Retrieve time stamp
												FILETIME ftUtc = { 0 };

												void* pTmData = NULL;
												DWORD dwcbTmDataSz = 0;

												struct Microsoft_forgot_to_document_me {
													void* something_0[9];
													FILETIME ftUtc;
												};

#ifndef TIMESTAMP_INFO
#define TIMESTAMP_INFO                     ((LPCSTR) 80)
#endif

												if (CryptDecodeObjectEx(ENCODING,    //X509_ASN_ENCODING,
													TIMESTAMP_INFO,
													pCntData,
													dwcbSz,
													CRYPT_DECODE_ALLOC_FLAG,
													NULL,
													&pTmData, &dwcbTmDataSz) &&
													pTmData &&
													dwcbTmDataSz >= sizeof(Microsoft_forgot_to_document_me))
												{
													ftUtc = ((Microsoft_forgot_to_document_me*)pTmData)->ftUtc;
												}
												else
													_tprintf(L"ERROR: (0x%X) CryptDecodeObjectEx(RFC3161/TIMESTAMP_INFO) data failed\n", ::GetLastError());

												if (pTmData)
												{
													::LocalFree(pTmData);
													pTmData = NULL;
												}


												//Try to get signer info
												dwcbSz = 0;
												::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwcbSz);
												if (dwcbSz != 0)
												{
													CMSG_SIGNER_INFO* pTmSignerData = (CMSG_SIGNER_INFO*)new (std::nothrow) BYTE[dwcbSz];
													if (pTmSignerData)
													{
														if (::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, pTmSignerData, &dwcbSz))
														{
															CRYPT_DATA_BLOB c7Data;
															c7Data.pbData = pSignerInfo->UnauthAttrs.rgAttr[n].rgValue->pbData;
															c7Data.cbData = pSignerInfo->UnauthAttrs.rgAttr[n].rgValue->cbData;

															//Try to locate the appropriate store
															FindAppropriateStoreAndPrintCertificateInformation(pTmSignerData, &c7Data, L"TimeStamp Certificate", TRUE, &ftUtc);
														}
														else
															_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(RFC3161/CMSG_SIGNER_INFO_PARAM) data failed\n", ::GetLastError());

														//Free mem
														delete[] pTmSignerData;
														pTmSignerData = NULL;
													}
													else
														_tprintf(L"ERROR: (0x%X) new(RFC3161) failed\n", ::GetLastError());
												}
												else
													_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(RFC3161/CMSG_SIGNER_INFO_PARAM) failed\n", ::GetLastError());


											}
											else
												_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(RFC3161/CMSG_CONTENT_PARAM) data failed\n", ::GetLastError());

											//Free mem
											delete[] pCntData;
											pCntData = NULL;
										}
										else
											_tprintf(L"ERROR: (0x%X) new(RFC3161) failed\n", ::GetLastError());
									}
									else
										_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(RFC3161/CMSG_CONTENT_PARAM) failed\n", ::GetLastError());
								}
								else
									_tprintf(L"ERROR: (0x%X) CryptMsgUpdate(RFC3161) failed\n", ::GetLastError());

								//Free handle
								::CryptMsgClose(hMsg);
								hMsg = NULL;
							}
							else
								_tprintf(L"ERROR: (0x%X) CryptMsgOpenToDecode(ENCODING) failed\n", ::GetLastError());
						}

					}
				}
			}
		}


	}

	//Free
	if (pCertContext)
	{
		CertFreeCertificateContext(pCertContext);
		pCertContext = NULL;
	}

	return c != 0 ? RFC_FOUND_CONTEXT : RFC_NO_CONTEXT;
}


void PrintCertContextDetails(PCCERT_CONTEXT pCertContext, DWORD dwNameOutputType, CRYPT_ALGORITHM_IDENTIFIER* pHashAlgo)
{
	//'dwNameOutputType' = one of: CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_RDN_TYPE, etc. see CertGetNameString()
	DWORD dwcbSz;
	WCHAR* pBuff;

	//Get subject name.
	dwcbSz = CertGetNameString(pCertContext, dwNameOutputType, 0, NULL, NULL, 0);
	if (dwcbSz != 0)
	{
		pBuff = new (std::nothrow) WCHAR[dwcbSz];
		if (pBuff)
		{
			if (CertGetNameString(pCertContext, dwNameOutputType, 0, NULL, pBuff, dwcbSz) == dwcbSz)
			{
				_tprintf(L"Subject: %s\n", pBuff);
			}
			else
				_tprintf(L"ERROR: (0x%X) CertGetNameString(subject) data failed\n", ::GetLastError());

			//Free mem
			delete[] pBuff;
			pBuff = NULL;
		}
		else
			_tprintf(L"ERROR: (0x%X) new CertGetNameString(subject) data failed\n", ::GetLastError());
	}
	else
		_tprintf(L"ERROR: (0x%X) CertGetNameString(subject) failed\n", ::GetLastError());


	//Issuer
	dwcbSz = CertGetNameString(pCertContext, dwNameOutputType, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
	if (dwcbSz != 0)
	{
		pBuff = new (std::nothrow) WCHAR[dwcbSz];
		if (pBuff)
		{
			if (CertGetNameString(pCertContext, dwNameOutputType, CERT_NAME_ISSUER_FLAG, NULL, pBuff, dwcbSz) == dwcbSz)
			{
				_tprintf(L"Issuer: %s\n", pBuff);
			}
			else
				_tprintf(L"ERROR: (0x%X) CertGetNameString(issuer) data failed\n", ::GetLastError());

			//Free mem
			delete[] pBuff;
			pBuff = NULL;
		}
		else
			_tprintf(L"ERROR: (0x%X) new CertGetNameString(issuer) data failed\n", ::GetLastError());
	}
	else
		_tprintf(L"ERROR: (0x%X) CertGetNameString(issuer) failed\n", ::GetLastError());


	//Print Serial Number.
	_tprintf(_T("Serial Number: "));
	dwcbSz = pCertContext->pCertInfo->SerialNumber.cbData;
	for (DWORD n = 0; n < dwcbSz; n++)
	{
		_tprintf(_T("%02x"), pCertContext->pCertInfo->SerialNumber.pbData[dwcbSz - (n + 1)]);
	}
	_tprintf(_T("\n"));


	//Digest algorithm
	_tprintf(L"Digest Algorithm: ");
	PrintDigestAlgorithmName(pHashAlgo);
	_tprintf(_T("\n"));

}


void PrintDigestAlgorithmName(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo)
{
	if (pSigAlgo &&
		pSigAlgo->pszObjId)
	{
		PCCRYPT_OID_INFO pCOI = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pSigAlgo->pszObjId, 0);
		if (pCOI &&
			pCOI->pwszName)
		{
			_tprintf(L"%s", pCOI->pwszName);
		}
		else
		{
			USES_CONVERSION;
			_tprintf(L"%s", A2W(pSigAlgo->pszObjId));
		}
	}
}


BOOL PrintSignerDateTime(FILETIME* pftUtc)
{
	BOOL bRes = FALSE;

	if (pftUtc)
	{
		//Convert to local time
		FILETIME ftLoc = { 0 };
		SYSTEMTIME stLoc = { 0 };

		if (FileTimeToLocalFileTime(pftUtc, &ftLoc) &&
			FileTimeToSystemTime(&ftLoc, &stLoc))
		{
			_tprintf(L"Date of TimeStamp : %02d/%02d/%04d %02d:%02d:%02d\n",
				stLoc.wMonth,
				stLoc.wDay,
				stLoc.wYear,
				stLoc.wHour,
				stLoc.wMinute,
				stLoc.wSecond);

			bRes = TRUE;
		}
	}
	else
		::SetLastError(ERROR_INVALID_PARAMETER);

	return bRes;
}

int PrintSignerTimeStampDateTime(PCMSG_SIGNER_INFO pSignerInfo)
{
	int nCountTimeStamps = 0;

	//Loop through authenticated attributes
	for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
	{
		if (pSignerInfo->AuthAttrs.rgAttr[n].pszObjId &&
			lstrcmpA(pSignerInfo->AuthAttrs.rgAttr[n].pszObjId, szOID_RSA_signingTime) == 0)
		{
			// Decode and get FILETIME structure.
			FILETIME ftUtc = { 0 };
			DWORD dwData = sizeof(ftUtc);

			if (CryptDecodeObject(ENCODING, PKCS_UTC_TIME,
				pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
				pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
				0,
				(PVOID)&ftUtc, &dwData))
			{
				//Got time stamp
				nCountTimeStamps++;

				//And print it
				if (!PrintSignerDateTime(&ftUtc))
				{
					_tprintf(L"ERROR: (0x%X) Time conversion failed from %I64x\n", ::GetLastError(), *(ULONGLONG*)&ftUtc);
				}
			}
			else
			{
				_tprintf(L"ERROR: (0x%X) CryptDecodeObject(PKCS_UTC_TIME) failed\n", ::GetLastError());
			}
		}
	}

	return nCountTimeStamps;
}


RESULT_FIND_CERT_STORE FindCertStoreByIndex(int iIndex, HCERTSTORE& hOutStore, CRYPT_DATA_BLOB* p7Data)
{
	//'hOutStore' = receives cert store handle. If not NULL, make sure to release it by calling CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
	//'p7Data' = used with index 0 only
	hOutStore = NULL;

	switch (iIndex)
	{
	case 0:
		hOutStore = CertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 0, p7Data);
		break;

	case 1:
		hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
			CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x10000,      // flags = 0x18001
			"ROOT");
		break;
	case 2:
		hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
			CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x10000,      // flags = 0x18001
			"TRUST");
		break;
	case 3:
		hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
			CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x10000,      // flags = 0x18001
			"CA");
		break;
	case 4:
		hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
			CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x10000,      // flags = 0x18001
			"MY");
		break;
	case 5:
		hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
			CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x20000,      // flags = 0x28001
			"SPC");
		break;

	default:
		return RFCS_NONE;
	}

	return hOutStore ? RFCS_FOUND_ONE : RFCS_ERROR;
}



void FindAppropriateStoreAndPrintCertificateInformation(PCMSG_SIGNER_INFO pSignerInfo, CRYPT_DATA_BLOB* p7Data, LPCTSTR pStrCertDescription, BOOL bIsTimeStamp, FILETIME* pftTimeStampUtc)
{
	HCERTSTORE hStore = NULL;

	//Try to locate the appropriate store
	for (int i = 0;; i++)
	{
		if (hStore)
		{
			CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
			hStore = NULL;
		}

		RESULT_FIND_CERT_STORE resFnd = FindCertStoreByIndex(i, hStore, p7Data);
		if (resFnd == RFCS_FOUND_ONE)
		{
			//Try to retrieve info
			if (PrintCertificateInformation(hStore, pSignerInfo, pStrCertDescription, bIsTimeStamp, pftTimeStampUtc) == RFC_FOUND_CONTEXT)
			{
				//All done
				break;
			}
		}
		else
		{
			//Stop the seatch
			if (resFnd == RFCS_NONE)
			{
				//No context
				_tprintf(L"ERROR: (0x%X) CertOpenStore(no_context) failed\n", ::GetLastError());
			}
			else
			{
				//Error
				_tprintf(L"ERROR: (0x%X) CertOpenStore(%i) data failed\n", ::GetLastError(), i);
			}

			break;
		}
	}


	if (hStore)
	{
		::CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
		hStore = NULL;
	}

}


void PrintDualSignatureInformation(PCMSG_SIGNER_INFO pSignerInfo)
{
	//Loop through unauthenticated attributes
	for (DWORD a = 0; a < pSignerInfo->UnauthAttrs.cAttr; a++)
	{
#ifndef szOID_NESTED_SIGNATURE
#define szOID_NESTED_SIGNATURE              "1.3.6.1.4.1.311.2.4.1"
#endif

		//We need szOID_NESTED_SIGNATURE att
		if (pSignerInfo->UnauthAttrs.rgAttr[a].pszObjId &&
			lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[a].pszObjId, szOID_NESTED_SIGNATURE) == 0)
		{
			HCRYPTMSG hMsg = ::CryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
			if (hMsg)
			{
				if (::CryptMsgUpdate(hMsg,
					pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->pbData,
					pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->cbData,
					TRUE))
				{
					DWORD dwSignerInfo = 0;
					::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo);
					if (dwSignerInfo != 0)
					{
						PCMSG_SIGNER_INFO pSignerInfo2 = (PCMSG_SIGNER_INFO)new (std::nothrow) BYTE[dwSignerInfo];
						if (pSignerInfo2)
						{
							if (::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM,
								0, (PVOID)pSignerInfo2, &dwSignerInfo))
							{
								CRYPT_DATA_BLOB c7Data;
								c7Data.cbData = pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->cbData;
								c7Data.pbData = pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->pbData;

								//Try to locate the appropriate store & print from it
								FindAppropriateStoreAndPrintCertificateInformation(pSignerInfo2, &c7Data, L"Dual Signer Certificate", FALSE);
							}
							else
								_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) data failed\n", ::GetLastError());

							//Free mem
							delete[] pSignerInfo2;
							pSignerInfo2 = NULL;
						}
						else
							_tprintf(L"ERROR: (0x%X) new(PCMSG_SIGNER_INFO) failed\n", ::GetLastError());
					}
					else
						_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed\n", ::GetLastError());
				}
				else
					_tprintf(L"ERROR: (0x%X) CryptMsgUpdate(dual-sig) failed\n", ::GetLastError());

				//Close message
				::CryptMsgClose(hMsg);
			}
			else
				_tprintf(L"ERROR: (0x%X) CryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) failed\n", ::GetLastError());
		}
	}
}

// https://stackoverflow.com/questions/50976612/amended-code-to-retrieve-dual-signature-information-from-pe-executable-in-window
    // https://www.sysadmins.lv/blog-en/reading-multiple-signatures-from-signed-file-with-powershell.aspx
    // 从技术上讲,Microsoft authenticode signature 一次只支持一个签名。附加签名作为嵌套签名完成。
    // 第一张图片显示另一个未经身份验证的属性,OID=1.3.6.1.4.1.311.2.4.1 (szOID_NESTED_SIGNATURE)。这是嵌套的 SHA2 签名。它就在这里。让我们从 SHA1 签名中检索一般信息:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值