Skip to content

Instantly share code, notes, and snippets.

@lallousx86
Created April 24, 2017 17:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lallousx86/e4199a75c8d897377bb6b0eb9c42aacb to your computer and use it in GitHub Desktop.
Save lallousx86/e4199a75c8d897377bb6b0eb9c42aacb to your computer and use it in GitHub Desktop.
How To Get Information from Authenticode Signed Executables
// https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables
#include <windows.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <stdio.h>
#include <tchar.h>
#pragma comment(lib, "crypt32.lib")
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
typedef struct {
LPWSTR lpszProgramName;
LPWSTR lpszPublisherLink;
LPWSTR lpszMoreInfoLink;
} SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO;
BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
PSPROG_PUBLISHERINFO Info);
BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st);
BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext);
BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo,
PCMSG_SIGNER_INFO *pCounterSignerInfo);
int _tmain(int argc, TCHAR *argv[])
{
WCHAR szFileName[MAX_PATH];
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PCCERT_CONTEXT pCertContext = NULL;
BOOL fResult;
DWORD dwEncoding, dwContentType, dwFormatType;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
DWORD dwSignerInfo;
CERT_INFO CertInfo;
SPROG_PUBLISHERINFO ProgPubInfo;
SYSTEMTIME st;
ZeroMemory(&ProgPubInfo, sizeof(ProgPubInfo));
__try
{
if (argc != 2)
{
_tprintf(_T("Usage: SignedFileInfo <filename>\n"));
return 0;
}
#ifdef UNICODE
lstrcpynW(szFileName, argv[1], MAX_PATH);
#else
if (mbstowcs(szFileName, argv[1], MAX_PATH) == -1)
{
printf("Unable to convert to unicode.\n");
__leave;
}
#endif
// Get message handle and store handle from the signed file.
fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
szFileName,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&dwEncoding,
&dwContentType,
&dwFormatType,
&hStore,
&hMsg,
NULL);
if (!fResult)
{
_tprintf(_T("CryptQueryObject failed with %x\n"), GetLastError());
__leave;
}
// Get signer information size.
fResult = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
NULL,
&dwSignerInfo);
if (!fResult)
{
_tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
__leave;
}
// Allocate memory for signer information.
pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
if (!pSignerInfo)
{
_tprintf(_T("Unable to allocate memory for Signer Info.\n"));
__leave;
}
// Get Signer Information.
fResult = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
(PVOID)pSignerInfo,
&dwSignerInfo);
if (!fResult)
{
_tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
__leave;
}
// Get program name and publisher information from
// signer info structure.
if (GetProgAndPublisherInfo(pSignerInfo, &ProgPubInfo))
{
if (ProgPubInfo.lpszProgramName != NULL)
{
wprintf(L"Program Name : %s\n",
ProgPubInfo.lpszProgramName);
}
if (ProgPubInfo.lpszPublisherLink != NULL)
{
wprintf(L"Publisher Link : %s\n",
ProgPubInfo.lpszPublisherLink);
}
if (ProgPubInfo.lpszMoreInfoLink != NULL)
{
wprintf(L"MoreInfo Link : %s\n",
ProgPubInfo.lpszMoreInfoLink);
}
}
_tprintf(_T("\n"));
// Search for the signer certificate in the temporary
// certificate store.
CertInfo.Issuer = pSignerInfo->Issuer;
CertInfo.SerialNumber = pSignerInfo->SerialNumber;
pCertContext = CertFindCertificateInStore(hStore,
ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo,
NULL);
if (!pCertContext)
{
_tprintf(_T("CertFindCertificateInStore failed with %x\n"),
GetLastError());
__leave;
}
// Print Signer certificate information.
_tprintf(_T("Signer Certificate:\n\n"));
PrintCertificateInfo(pCertContext);
_tprintf(_T("\n"));
// Get the timestamp certificate signerinfo structure.
if (GetTimeStampSignerInfo(pSignerInfo, &pCounterSignerInfo))
{
// Search for Timestamp certificate in the temporary
// certificate store.
CertInfo.Issuer = pCounterSignerInfo->Issuer;
CertInfo.SerialNumber = pCounterSignerInfo->SerialNumber;
pCertContext = CertFindCertificateInStore(hStore,
ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo,
NULL);
if (!pCertContext)
{
_tprintf(_T("CertFindCertificateInStore failed with %x\n"),
GetLastError());
__leave;
}
// Print timestamp certificate information.
_tprintf(_T("TimeStamp Certificate:\n\n"));
PrintCertificateInfo(pCertContext);
_tprintf(_T("\n"));
// Find Date of timestamp.
if (GetDateOfTimeStamp(pCounterSignerInfo, &st))
{
_tprintf(_T("Date of TimeStamp : %02d/%02d/%04d %02d:%02d\n"),
st.wMonth,
st.wDay,
st.wYear,
st.wHour,
st.wMinute);
}
_tprintf(_T("\n"));
}
}
__finally
{
// Clean up.
if (ProgPubInfo.lpszProgramName != NULL)
LocalFree(ProgPubInfo.lpszProgramName);
if (ProgPubInfo.lpszPublisherLink != NULL)
LocalFree(ProgPubInfo.lpszPublisherLink);
if (ProgPubInfo.lpszMoreInfoLink != NULL)
LocalFree(ProgPubInfo.lpszMoreInfoLink);
if (pSignerInfo != NULL) LocalFree(pSignerInfo);
if (pCounterSignerInfo != NULL) LocalFree(pCounterSignerInfo);
if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
if (hStore != NULL) CertCloseStore(hStore, 0);
if (hMsg != NULL) CryptMsgClose(hMsg);
}
return 0;
}
BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext)
{
BOOL fReturn = FALSE;
LPTSTR szName = NULL;
DWORD dwData;
__try
{
// Print Serial Number.
_tprintf(_T("Serial Number: "));
dwData = pCertContext->pCertInfo->SerialNumber.cbData;
for (DWORD n = 0; n < dwData; n++)
{
_tprintf(_T("%02x "),
pCertContext->pCertInfo->SerialNumber.pbData[dwData - (n + 1)]);
}
_tprintf(_T("\n"));
// Get Issuer name size.
if (!(dwData = CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG,
NULL,
NULL,
0)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Allocate memory for Issuer name.
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
if (!szName)
{
_tprintf(_T("Unable to allocate memory for issuer name.\n"));
__leave;
}
// Get Issuer name.
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG,
NULL,
szName,
dwData)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// print Issuer name.
_tprintf(_T("Issuer Name: %s\n"), szName);
LocalFree(szName);
szName = NULL;
// Get Subject name size.
if (!(dwData = CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
NULL,
0)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Allocate memory for subject name.
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
if (!szName)
{
_tprintf(_T("Unable to allocate memory for subject name.\n"));
__leave;
}
// Get subject name.
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
szName,
dwData)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Print Subject Name.
_tprintf(_T("Subject Name: %s\n"), szName);
fReturn = TRUE;
}
__finally
{
if (szName != NULL) LocalFree(szName);
}
return fReturn;
}
LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
{
LPWSTR outputString = NULL;
outputString = (LPWSTR)LocalAlloc(LPTR,
(wcslen(inputString) + 1) * sizeof(WCHAR));
if (outputString != NULL)
{
lstrcpyW(outputString, inputString);
}
return outputString;
}
BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
PSPROG_PUBLISHERINFO Info)
{
BOOL fReturn = FALSE;
PSPC_SP_OPUS_INFO OpusInfo = NULL;
DWORD dwData;
BOOL fResult;
__try
{
// Loop through authenticated attributes and find
// SPC_SP_OPUS_INFO_OBJID OID.
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
{
// Get Size of SPC_SP_OPUS_INFO structure.
fResult = CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
NULL,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Allocate memory for SPC_SP_OPUS_INFO structure.
OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData);
if (!OpusInfo)
{
_tprintf(_T("Unable to allocate memory for Publisher Info.\n"));
__leave;
}
// Decode and get SPC_SP_OPUS_INFO structure.
fResult = CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
OpusInfo,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Fill in Program Name if present.
if (OpusInfo->pwszProgramName)
{
Info->lpszProgramName =
AllocateAndCopyWideString(OpusInfo->pwszProgramName);
}
else
Info->lpszProgramName = NULL;
// Fill in Publisher Information if present.
if (OpusInfo->pPublisherInfo)
{
switch (OpusInfo->pPublisherInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
Info->lpszPublisherLink =
AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
Info->lpszPublisherLink =
AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile);
break;
default:
Info->lpszPublisherLink = NULL;
break;
}
}
else
{
Info->lpszPublisherLink = NULL;
}
// Fill in More Info if present.
if (OpusInfo->pMoreInfo)
{
switch (OpusInfo->pMoreInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
Info->lpszMoreInfoLink =
AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
Info->lpszMoreInfoLink =
AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile);
break;
default:
Info->lpszMoreInfoLink = NULL;
break;
}
}
else
{
Info->lpszMoreInfoLink = NULL;
}
fReturn = TRUE;
break; // Break from for loop.
} // lstrcmp SPC_SP_OPUS_INFO_OBJID
} // for
}
__finally
{
if (OpusInfo != NULL) LocalFree(OpusInfo);
}
return fReturn;
}
BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st)
{
BOOL fResult;
FILETIME lft, ft;
DWORD dwData;
BOOL fReturn = FALSE;
// Loop through authenticated attributes and find
// szOID_RSA_signingTime OID.
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (lstrcmpA(szOID_RSA_signingTime,
pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
{
// Decode and get FILETIME structure.
dwData = sizeof(ft);
fResult = CryptDecodeObject(ENCODING,
szOID_RSA_signingTime,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
(PVOID)&ft,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
break;
}
// Convert to local time.
FileTimeToLocalFileTime(&ft, &lft);
FileTimeToSystemTime(&lft, st);
fReturn = TRUE;
break; // Break from for loop.
} //lstrcmp szOID_RSA_signingTime
} // for
return fReturn;
}
BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, PCMSG_SIGNER_INFO *pCounterSignerInfo)
{
PCCERT_CONTEXT pCertContext = NULL;
BOOL fReturn = FALSE;
BOOL fResult;
DWORD dwSize;
__try
{
*pCounterSignerInfo = NULL;
// Loop through unathenticated attributes for
// szOID_RSA_counterSign OID.
for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++)
{
if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId,
szOID_RSA_counterSign) == 0)
{
// Get size of CMSG_SIGNER_INFO structure.
fResult = CryptDecodeObject(ENCODING,
PKCS7_SIGNER_INFO,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
0,
NULL,
&dwSize);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Allocate memory for CMSG_SIGNER_INFO.
*pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize);
if (!*pCounterSignerInfo)
{
_tprintf(_T("Unable to allocate memory for timestamp info.\n"));
__leave;
}
// Decode and get CMSG_SIGNER_INFO structure
// for timestamp certificate.
fResult = CryptDecodeObject(ENCODING,
PKCS7_SIGNER_INFO,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
0,
(PVOID)*pCounterSignerInfo,
&dwSize);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
fReturn = TRUE;
break; // Break from for loop.
}
}
}
__finally
{
// Clean up.
if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
}
return fReturn;
}
@lallousx86
Copy link
Author

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

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

#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)

//-------------------------------------------------------------------------
typedef struct
{
LPWSTR lpszProgramName;
LPWSTR lpszPublisherLink;
LPWSTR lpszMoreInfoLink;
} SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO;

//-------------------------------------------------------------------------
bool MyVerifyCodeSign(const wchar_t *path)
{
// Initialize the WINTRUST_FILE_INFO structure
WINTRUST_FILE_INFO FileData = { 0 };
FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
FileData.pcwszFilePath = path;

GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_DATA WinTrustData = { 0 };

WinTrustData.cbStruct = sizeof(WinTrustData);
WinTrustData.dwUIChoice = WTD_UI_NONE;
WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
WinTrustData.dwProvFlags = WTD_SAFER_FLAG;
WinTrustData.pFile = &FileData;

// WinVerifyTrust verifies signatures as specified by the GUID
// and Wintrust_Data.
auto lStatus = WinVerifyTrust(
    NULL,
    &WVTPolicyGUID,
    &WinTrustData);

return (lStatus == ERROR_SUCCESS);

}

//-------------------------------------------------------------------------
LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
{
LPWSTR outputString = NULL;

outputString = (LPWSTR)LocalAlloc(LPTR, (wcslen(inputString) + 1) * sizeof(WCHAR));
if (outputString != NULL)
    lstrcpyW(outputString, inputString);

return outputString;

}

//-------------------------------------------------------------------------
BOOL GetDateOfTimeStamp(
PCMSG_SIGNER_INFO pSignerInfo,
SYSTEMTIME *st)
{
BOOL fResult;
FILETIME lft, ft;
DWORD dwData;
BOOL fReturn = FALSE;

// Loop through authenticated attributes and find
// szOID_RSA_signingTime OID.
for (DWORD n = 0, c = pSignerInfo->AuthAttrs.cAttr; n < c; n++)
{
    if (lstrcmpA(szOID_RSA_signingTime, pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) != 0)
        continue;

    // Decode and get FILETIME structure.
    dwData = sizeof(ft);
    fResult = CryptDecodeObject(ENCODING,
        szOID_RSA_signingTime,
        pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
        pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
        0,
        (PVOID)&ft,
        &dwData);

    if (!fResult)
    {
        _tprintf(_T("CryptDecodeObject failed with %x\n"),
            GetLastError());
        break;
    }

    // Convert to local time.
    FileTimeToLocalFileTime(&ft, &lft);
    FileTimeToSystemTime(&lft, st);

    fReturn = TRUE;

    break;
}

return fReturn;

}

//-------------------------------------------------------------------------
BOOL GetProgAndPublisherInfo(
PCMSG_SIGNER_INFO pSignerInfo,
PSPROG_PUBLISHERINFO Info)
{
BOOL fReturn = FALSE;
PSPC_SP_OPUS_INFO OpusInfo = NULL;
DWORD dwData;
BOOL fResult;

__try
{
    // Loop through authenticated attributes and find
    // SPC_SP_OPUS_INFO_OBJID OID.
    for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
    {
        if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
        {
            // Get Size of SPC_SP_OPUS_INFO structure.
            fResult = CryptDecodeObject(
                ENCODING,
                SPC_SP_OPUS_INFO_OBJID,
                pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
                pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
                0,
                NULL,
                &dwData);
            if (!fResult)
            {
                _tprintf(_T("CryptDecodeObject failed with %x\n"), GetLastError());
                __leave;
            }

            // Allocate memory for SPC_SP_OPUS_INFO structure.
            OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData);
            if (!OpusInfo)
            {
                _tprintf(_T("Unable to allocate memory for Publisher Info.\n"));
                __leave;
            }

            // Decode and get SPC_SP_OPUS_INFO structure.
            fResult = CryptDecodeObject(
                ENCODING,
                SPC_SP_OPUS_INFO_OBJID,
                pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
                pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
                0,
                OpusInfo,
                &dwData);
            if (!fResult)
            {
                _tprintf(_T("CryptDecodeObject failed with %x\n"),
                    GetLastError());
                __leave;
            }

            // Fill in Program Name if present.
            if (OpusInfo->pwszProgramName)
            {
                Info->lpszProgramName = AllocateAndCopyWideString(OpusInfo->pwszProgramName);
            }
            else
                Info->lpszProgramName = NULL;

            // Fill in Publisher Information if present.
            if (OpusInfo->pPublisherInfo)
            {
                switch (OpusInfo->pPublisherInfo->dwLinkChoice)
                {
                case SPC_URL_LINK_CHOICE:
                    Info->lpszPublisherLink =
                        AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl);
                    break;

                case SPC_FILE_LINK_CHOICE:
                    Info->lpszPublisherLink =
                        AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile);
                    break;

                default:
                    Info->lpszPublisherLink = NULL;
                    break;
                }
            }
            else
            {
                Info->lpszPublisherLink = NULL;
            }

            // Fill in More Info if present.
            if (OpusInfo->pMoreInfo)
            {
                switch (OpusInfo->pMoreInfo->dwLinkChoice)
                {
                case SPC_URL_LINK_CHOICE:
                    Info->lpszMoreInfoLink =
                        AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl);
                    break;

                case SPC_FILE_LINK_CHOICE:
                    Info->lpszMoreInfoLink =
                        AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile);
                    break;

                default:
                    Info->lpszMoreInfoLink = NULL;
                    break;
                }
            }
            else
            {
                Info->lpszMoreInfoLink = NULL;
            }

            fReturn = TRUE;

            break; // Break from for loop.
        } // lstrcmp SPC_SP_OPUS_INFO_OBJID                 
    } // for 
}
__finally
{
    if (OpusInfo != NULL)
        LocalFree(OpusInfo);
}

return fReturn;

}

//-------------------------------------------------------------------------
void DumpData(
LPCTSTR Title,
LPCTSTR VarName,
BYTE *Data,
DWORD nData,
bool bDevMode,
bool bRev,
DWORD nMaxCols = 0)
{
if (bDevMode)
_tprintf(_T("BYTE %s[0x%x] = { \n\t"), VarName, nData);
else
_tprintf(_T("%s"), Title);

for (DWORD n = 0, iCol = 1; n < nData; n++, ++iCol)
{
    BYTE v = Data[bRev ? nData - (n + 1) : n];
    if (bDevMode)
    {
        _tprintf(_T("0x%02x%s"), v, (n == nData - 1) ? _T("") : _T(", "));
        if (nMaxCols != 0 && iCol >= nMaxCols)
        {
            iCol = 0;
            _tprintf(_T("\n\t"));
        }
    }
    else
    {
        _tprintf(_T("%02x "), v);
    }
}

if (bDevMode)
    _tprintf(_T(" };\n"));

_tprintf(_T("\n"));

}

//-------------------------------------------------------------------------
void DumpString(
LPCTSTR Title,
LPCTSTR VarName,
LPCTSTR Value,
bool bDevMode)
{
if (bDevMode)
_tprintf(_T("CHAR %s[] = R"(%s)";\n"), VarName, Value);
else
_tprintf(_T("%s: %s\n"), Title, Value);
}

//-------------------------------------------------------------------------
BOOL PrintCertificateInfo(
PCCERT_CONTEXT pCertContext,
bool bDevMode)
{
BOOL fReturn = FALSE;
LPTSTR szName = NULL;
DWORD dwData;

__try
{
    // Print Serial Number (in reverse order)
    DumpData(
        _T("Serial Number: "),
        bDevMode ? _T("blobSerialNumber") : nullptr,
        pCertContext->pCertInfo->SerialNumber.pbData,
        pCertContext->pCertInfo->SerialNumber.cbData,
        bDevMode,
        true);

    // Print Public Key info
    DumpData(
        _T("Public key info:"),
        bDevMode ? _T("blobPublicKey") : nullptr,
        pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
        pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
        bDevMode,
        false,
        16);

    // Print Issuer UniqueID
    if (pCertContext->pCertInfo->IssuerUniqueId.cbData > 0)
    {
        DumpData(
            _T("Issuer Unique ID:"),
            bDevMode ? _T("blobIssuerUniqueId") : nullptr,
            pCertContext->pCertInfo->IssuerUniqueId.pbData,
            pCertContext->pCertInfo->IssuerUniqueId.cbData,
            bDevMode,
            false,
            16);
    }

    // Print Subject UniqueID
    if (pCertContext->pCertInfo->SubjectUniqueId.cbData > 0)
    {
        DumpData(
            _T("Subject Unique ID:"),
            bDevMode ? _T("blobSibjectUniqueId") : nullptr,
            pCertContext->pCertInfo->SubjectUniqueId.pbData,
            pCertContext->pCertInfo->SubjectUniqueId.cbData,
            bDevMode,
            false,
            16);
    }

    // Get Issuer name size.
    dwData = CertGetNameString(
        pCertContext,
        CERT_NAME_SIMPLE_DISPLAY_TYPE,
        CERT_NAME_ISSUER_FLAG,
        NULL,
        NULL,
        0);

    if (dwData == 0)
    {
        _tprintf(_T("CertGetNameString failed.\n"));
        __leave;
    }

    // Allocate memory for Issuer name.
    szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
    if (!szName)
    {
        _tprintf(_T("Unable to allocate memory for issuer name.\n"));
        __leave;
    }

    // Get Issuer name.
    if (!(CertGetNameString(
        pCertContext,
        CERT_NAME_SIMPLE_DISPLAY_TYPE,
        CERT_NAME_ISSUER_FLAG,
        NULL,
        szName,
        dwData)))
    {
        _tprintf(_T("CertGetNameString failed.\n"));
        __leave;
    }

    // print Issuer name.
    DumpString(
        _T("Issuer Name: %s\n"),
        _TEXT("szIssuerName"),
        szName,
        bDevMode);

    LocalFree(szName);
    szName = NULL;

    // Get Subject name size.
    if (!(dwData = CertGetNameString(
        pCertContext,
        CERT_NAME_SIMPLE_DISPLAY_TYPE,
        0,
        NULL,
        NULL,
        0)))
    {
        _tprintf(_T("CertGetNameString failed.\n"));
        __leave;
    }

    // Allocate memory for subject name.
    szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
    if (!szName)
    {
        _tprintf(_T("Unable to allocate memory for subject name.\n"));
        __leave;
    }

    // Get subject name.
    if (!CertGetNameString(
        pCertContext,
        CERT_NAME_SIMPLE_DISPLAY_TYPE,
        0,
        NULL,
        szName,
        dwData))
    {
        _tprintf(_T("CertGetNameString failed.\n"));
        __leave;
    }

    // Print Subject Name.
    DumpString(
        _TEXT("Subject Name:"),
        _TEXT("szSubjectName"),
        szName,
        bDevMode);

    fReturn = TRUE;
}
__finally
{
    if (szName != NULL) 
        LocalFree(szName);
}

return fReturn;

}

//-------------------------------------------------------------------------
BOOL GetTimeStampSignerInfo(
PCMSG_SIGNER_INFO pSignerInfo,
PCMSG_SIGNER_INFO *pCounterSignerInfo)
{
PCCERT_CONTEXT pCertContext = NULL;
BOOL fReturn = FALSE;
BOOL fResult;
DWORD dwSize;

__try
{
    *pCounterSignerInfo = NULL;

    // Loop through unauthenticated attributes for
    // szOID_RSA_counterSign OID.
    for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++)
    {
        if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId,
            szOID_RSA_counterSign) == 0)
        {
            // Get size of CMSG_SIGNER_INFO structure.
            fResult = CryptDecodeObject(
                ENCODING,
                PKCS7_SIGNER_INFO,
                pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
                pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
                0,
                NULL,
                &dwSize);
            if (!fResult)
            {
                _tprintf(_T("CryptDecodeObject failed with %x\n"),
                    GetLastError());
                __leave;
            }

            // Allocate memory for CMSG_SIGNER_INFO.
            *pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize);
            if (!*pCounterSignerInfo)
            {
                _tprintf(_T("Unable to allocate memory for timestamp info.\n"));
                __leave;
            }

            // Decode and get CMSG_SIGNER_INFO structure
            // for timestamp certificate.
            fResult = CryptDecodeObject(
                ENCODING,
                PKCS7_SIGNER_INFO,
                pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
                pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
                0,
                (PVOID)*pCounterSignerInfo,
                &dwSize);
            if (!fResult)
            {
                _tprintf(_T("CryptDecodeObject failed with %x\n"),
                    GetLastError());
                __leave;
            }

            fReturn = TRUE;

            break; // Break from for loop.
        }
    }
}
__finally
{
    // Clean up.
    if (pCertContext != NULL)
        CertFreeCertificateContext(pCertContext);
}

return fReturn;

}

//-------------------------------------------------------------------------
int _tmain(int argc, TCHAR *argv[])
{
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PCCERT_CONTEXT pCertContext = NULL;
BOOL fResult;
DWORD dwEncoding, dwContentType, dwFormatType;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
DWORD dwSignerInfo;
CERT_INFO CertInfo;
SPROG_PUBLISHERINFO ProgPubInfo = { 0 };
SYSTEMTIME st;

__try
{
    if (argc < 2)
    {
        _tprintf(_T("Usage: MyDumpSignInfo <filename> [devMod=1]\n"));
        return 0;
    }

    bool bDevMode = argc > 2;

    WCHAR szFileName[MAX_PATH];

#ifdef UNICODE
lstrcpynW(szFileName, argv[1], MAX_PATH);
#else
if (mbstowcs(szFileName, argv[1], MAX_PATH) == -1)
{
printf("Unable to convert to Unicode.\n");
__leave;
}
#endif

    // Check file existence
    if (GetFileAttributesW(szFileName) == INVALID_FILE_ATTRIBUTES)
    {
        _tprintf(_T("Input file not found: %s\n"), szFileName);
        return -1;
    }

    _tprintf(_T("File is %ssigned!\n"),
        MyVerifyCodeSign(szFileName) ? _T("") : _T("not properly "));

    // Get message handle and store handle from the signed file.
    fResult = CryptQueryObject(
        CERT_QUERY_OBJECT_FILE,
        szFileName,
        CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
        CERT_QUERY_FORMAT_FLAG_BINARY,
        0,
        &dwEncoding,
        &dwContentType,
        &dwFormatType,
        &hStore,
        &hMsg,
        NULL);
    if (!fResult)
    {
        _tprintf(_T("CryptQueryObject failed with %x\n"), GetLastError());
        __leave;
    }

    // Get signer information size
    fResult = CryptMsgGetParam(
        hMsg,
        CMSG_SIGNER_INFO_PARAM,
        0,
        NULL,
        &dwSignerInfo);
    if (!fResult)
    {
        _tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
        __leave;
    }

    // Allocate memory for signer information.
    pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
    if (!pSignerInfo)
    {
        _tprintf(_T("Unable to allocate memory for Signer Info.\n"));
        __leave;
    }

    // Get Signer Information.
    fResult = CryptMsgGetParam(
        hMsg,
        CMSG_SIGNER_INFO_PARAM,
        0,
        (PVOID)pSignerInfo,
        &dwSignerInfo);
    if (!fResult)
    {
        _tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
        __leave;
    }

    if (bDevMode)
        _tprintf(_TEXT("// "));
    _tprintf(_T("------------------------ Signer Info ---------------------------------\n"));

    // Get program name and publisher information from 
    // signer info structure.
    if (GetProgAndPublisherInfo(pSignerInfo, &ProgPubInfo))
    {
        if (ProgPubInfo.lpszProgramName != NULL)
            DumpString(L"Program Name :", _TEXT("szProgramName"), ProgPubInfo.lpszProgramName, bDevMode);

        if (ProgPubInfo.lpszPublisherLink != NULL)
            DumpString(L"Publisher Link :", _TEXT("szPublisherLink"), ProgPubInfo.lpszPublisherLink, bDevMode);

        if (ProgPubInfo.lpszMoreInfoLink != NULL)
            DumpString(_TEXT("MoreInfo Link :"), _TEXT("szMoreInfoLink"), ProgPubInfo.lpszMoreInfoLink, bDevMode);
    }

    _tprintf(_T("\n"));

    // Search for the signer certificate in the temporary 
    // certificate store.
    CertInfo.Issuer = pSignerInfo->Issuer;
    CertInfo.SerialNumber = pSignerInfo->SerialNumber;

    pCertContext = CertFindCertificateInStore(
        hStore,
        ENCODING,
        0,
        CERT_FIND_SUBJECT_CERT, // Find by issuer and serial number
        (PVOID)&CertInfo,
        NULL);

    if (!pCertContext)
    {
        _tprintf(_T("CertFindCertificateInStore failed with %x\n"), GetLastError());
        __leave;
    }

    // Print Signer certificate information.
    if (!bDevMode)
    {
        _tprintf(
            _T("Signer Certificate:\n")
            _T("-------------------\n\n"));
    }

    PrintCertificateInfo(pCertContext, bDevMode);
    _tprintf(_T("\n"));

    if (bDevMode)
        _tprintf(_TEXT("// "));
    _tprintf(_T("------------------ Counter Signer Info -------------------------------\n"));

    // Get the timestamp certificate signer info structure.
    if (GetTimeStampSignerInfo(pSignerInfo, &pCounterSignerInfo))
    {
        // Search for Timestamp certificate in the temporary
        // certificate store.
        CertInfo.Issuer = pCounterSignerInfo->Issuer;
        CertInfo.SerialNumber = pCounterSignerInfo->SerialNumber;

        pCertContext = CertFindCertificateInStore(hStore,
            ENCODING,
            0,
            CERT_FIND_SUBJECT_CERT,
            (PVOID)&CertInfo,
            NULL);
        if (!pCertContext)
        {
            _tprintf(_T("CertFindCertificateInStore failed with %x\n"),
                GetLastError());
            __leave;
        }

        // Print timestamp certificate information.
        if (!bDevMode)
        {
            _tprintf(
                _T("TimeStamp Certificate:\n")
                _T("----------------------\n\n"));
        }

        PrintCertificateInfo(pCertContext, bDevMode);
        _tprintf(_T("\n"));

        // Find Date of timestamp.
        if (GetDateOfTimeStamp(pCounterSignerInfo, &st))
        {
            TCHAR szBuf[100];
            _stprintf_s(
                szBuf, 
                _countof(szBuf), 
                _T("%02d/%02d/%04d %02d:%02d"),
                st.wMonth,
                st.wDay,
                st.wYear,
                st.wHour,
                st.wMinute);
            DumpString(
                _TEXT("Date of TimeStamp :"), 
                _TEXT("szDateOfTimeStamp"), 
                szBuf,
                bDevMode);
        }
        _tprintf(_T("\n"));
    }
}
__finally
{
    // Clean up.
    if (ProgPubInfo.lpszProgramName != NULL)
        LocalFree(ProgPubInfo.lpszProgramName);

    if (ProgPubInfo.lpszPublisherLink != NULL)
        LocalFree(ProgPubInfo.lpszPublisherLink);

    if (ProgPubInfo.lpszMoreInfoLink != NULL)
        LocalFree(ProgPubInfo.lpszMoreInfoLink);

    if (pSignerInfo != NULL) 
        LocalFree(pSignerInfo);

    if (pCounterSignerInfo != NULL) 
        LocalFree(pCounterSignerInfo);

    if (pCertContext != NULL) 
        CertFreeCertificateContext(pCertContext);

    if (hStore != NULL) 
        CertCloseStore(hStore, 0);

    if (hMsg != NULL) 
        CryptMsgClose(hMsg);
}
return 0;

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment