title: Amended code to retrieve dual signature information from PE executable in Windows?
body: <p>I've been struggling for awhile to amend <a href="https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables" rel="nofollow noreferrer">this code sample</a> from Microsoft that shows (somewhat outdated) way how to retrieve a code signature information from an executable file. It works but it doesn't retrieve information if a binary file is dual-signed.</p>
  
  <p>So I did some research and tried to rewrite it to make it recognize dual-signatures that are present in many modern executables in Windows. Unfortunately there are very few (nebulous) suggestion available (<a href="https://stackoverflow.com/questions/36931928/how-to-retrieve-information-from-multiple-dual-code-signatures-on-an-executable">1</a>), (<a href="https://social.msdn.microsoft.com/Forums/en-US/40dcf50b-c637-4d7d-b0c0-598a61f96f8c/rfc3161-timestamp-information-in-digital-signature-authenticode?forum=windowsgeneraldevelopmentissues" rel="nofollow noreferrer">2</a>), such as those to use <code>UnauthenticatedAttributes</code> and <code>szOID_NESTED_SIGNATURE</code> (whatever that means) but only to retrieve a time stamp.</p>
  
  <p>So I attempted to rewrite that Microsoft code, and here's what I got:</p>
  
  <p><em>(To build it simply copy it into Visual Studio console project &amp; change the .exe file path. The code that deals with dual-signatures is in the <code>PrintDualSignatureInfo()</code> function.)</em></p>
  
  <pre><code>#include "stdafx.h"
  
  //SOURCE:
  //      https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables
  //
  
  #include &lt;windows.h&gt;
  #include &lt;wincrypt.h&gt;
  #include &lt;wintrust.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;tchar.h&gt;
  #include &lt;atlconv.h&gt;
  
  #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);
  void PrintSignatureAlgorithm(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo);
  void PrintDualSignatureInfo(PCMSG_SIGNER_INFO pSignerInfo);
  void PrintCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, LPCTSTR pStrCertName);
  
  
  int main()
  {
       WCHAR szFileName[MAX_PATH]; 
      HCERTSTORE hStore = NULL;
      HCRYPTMSG hMsg = NULL; 
      BOOL fResult;   
      DWORD dwEncoding, dwContentType, dwFormatType;
      PCMSG_SIGNER_INFO pSignerInfo = NULL;
      DWORD dwSignerInfo;
      SPROG_PUBLISHERINFO ProgPubInfo;
  
      ZeroMemory(&amp;ProgPubInfo, sizeof(ProgPubInfo));
      __try
      {
          LPCTSTR pExePath = L"C:\\Users\\UserName\\Downloads\\procmon.exe";  //works
          //pExePath = L"C:\\Users\\UserName\\Downloads\\putty.exe";      //doesnt work
  
          lstrcpynW(szFileName, pExePath, MAX_PATH);
  
          // 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,
                                     &amp;dwEncoding,
                                     &amp;dwContentType,
                                     &amp;dwFormatType,
                                     &amp;hStore,
                                     &amp;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, 
                                     &amp;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, 
                                     &amp;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, &amp;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"));
  
          // Print Signer certificate information.
          PrintCertificateInfo(hStore, pSignerInfo, L"Signer Certificate");
  
  
          //Look for dual signature
          PrintDualSignatureInfo(pSignerInfo);
  
      }
      __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 (hStore != NULL) CertCloseStore(hStore, 0);
          if (hMsg != NULL) CryptMsgClose(hMsg);
      }
      return 0;
  }
  
  
  
  void PrintCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, LPCTSTR pStrCertName)
  {
  
      if(hStore &amp;&amp;
          pSignerInfo)
      {
          PCCERT_CONTEXT pCertContext = NULL;
          CERT_INFO CertInfo = {0};
          PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
          SYSTEMTIME st;
  
          __try
          {
              // Search for the signer certificate in the temporary 
              // certificate store.
              CertInfo.Issuer = pSignerInfo-&gt;Issuer;
              CertInfo.SerialNumber = pSignerInfo-&gt;SerialNumber;
  
              pCertContext = CertFindCertificateInStore(hStore,
                                                        ENCODING,
                                                        0,
                                                        CERT_FIND_SUBJECT_CERT,
                                                        (PVOID)&amp;CertInfo,
                                                        NULL);
              if (!pCertContext)
              {
                  _tprintf(_T("CertFindCertificateInStore failed with %x\n"),
                      GetLastError());
                  __leave;
              }
  
              // Print Signer certificate information.
              _tprintf(L"%s:\n\n", pStrCertName);     //(_T("Signer Certificate:\n\n"));        
              PrintCertificateInfo(pCertContext);
              _tprintf(_T("\n"));
  
  
  
              // Get the timestamp certificate signerinfo structure.
              if (GetTimeStampSignerInfo(pSignerInfo, &amp;pCounterSignerInfo))
              {
                  // Search for Timestamp certificate in the temporary
                  // certificate store.
                  CertInfo.Issuer = pCounterSignerInfo-&gt;Issuer;
                  CertInfo.SerialNumber = pCounterSignerInfo-&gt;SerialNumber;
  
                  pCertContext = CertFindCertificateInStore(hStore,
                                                      ENCODING,
                                                      0,
                                                      CERT_FIND_SUBJECT_CERT,
                                                      (PVOID)&amp;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, &amp;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
          {
              if (pCounterSignerInfo != NULL)
                  LocalFree(pCounterSignerInfo);
  
              if (pCertContext != NULL)
                  CertFreeCertificateContext(pCertContext);
          }
      }
  
  }
  
  
  
  void PrintDualSignatureInfo(PCMSG_SIGNER_INFO pSignerInfo)
  {
      if(pSignerInfo)
      {
  
          for(DWORD a = 0; a &lt; pSignerInfo-&gt;UnauthAttrs.cAttr; a++)
          {
              if(pSignerInfo-&gt;UnauthAttrs.rgAttr[a].pszObjId &amp;&amp;
                  lstrcmpiA(pSignerInfo-&gt;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-&gt;UnauthAttrs.rgAttr[a].rgValue-&gt;pbData,
                          pSignerInfo-&gt;UnauthAttrs.rgAttr[a].rgValue-&gt;cbData,
                          TRUE))
                      {
                          DWORD dwSignerInfo = 0;
                          ::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &amp;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, &amp;dwSignerInfo))
                                  {
                                      CRYPT_DATA_BLOB p7Data;
                                      p7Data.cbData = pSignerInfo-&gt;UnauthAttrs.rgAttr[a].rgValue-&gt;cbData;
                                      p7Data.pbData = pSignerInfo-&gt;UnauthAttrs.rgAttr[a].rgValue-&gt;pbData;
  
                                      HCERTSTORE hStore = ::CertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 0, &amp;p7Data);
                                      if(hStore)
                                      {
                                          // Print Signer certificate information.
                                          PrintCertificateInfo(hStore, pSignerInfo2, L"Dual Signer Certificate");
  
                                          //Close
                                          ::CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
                                      }
                                  }
  
                                  //Free mem
                                  delete[] pSignerInfo2;
                                  pSignerInfo2 = NULL;
                              }
                          }
                      }
  
                      //Close message
                      ::CryptMsgClose(hMsg);
                  }
  
              }
          }
  
  
      }
  
  }
  
  
  void PrintSignatureAlgorithm(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo)
  {
      if(pSigAlgo &amp;&amp;
          pSigAlgo-&gt;pszObjId)
      {
          PCCRYPT_OID_INFO pCOI = ::CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pSigAlgo-&gt;pszObjId, 0);
          if(pCOI &amp;&amp;
              pCOI-&gt;pwszName)
          {
              _tprintf(L"%s", pCOI-&gt;pwszName);
          }
          else
          {
              USES_CONVERSION;
              _tprintf(L"%s",  A2W(pSigAlgo-&gt;pszObjId));
          }
      }
  }
  
  
  BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext)
  {
      BOOL fReturn = FALSE;
      LPTSTR szName = NULL;
      DWORD dwData;
  
      __try
      {
          // Print Serial Number.
          _tprintf(_T("Serial Number: "));
          dwData = pCertContext-&gt;pCertInfo-&gt;SerialNumber.cbData;
          for (DWORD n = 0; n &lt; dwData; n++)
          {
              _tprintf(_T("%02x "),
                pCertContext-&gt;pCertInfo-&gt;SerialNumber.pbData[dwData - (n + 1)]);
          }
          _tprintf(_T("\n"));
  
  
          //Hashing algoriths
          _tprintf(L"Signature Algorithm: ");
          PrintSignatureAlgorithm(&amp;pCertContext-&gt;pCertInfo-&gt;SignatureAlgorithm);
          _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 &lt; pSignerInfo-&gt;AuthAttrs.cAttr; n++)
          {           
              if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID, 
                          pSignerInfo-&gt;AuthAttrs.rgAttr[n].pszObjId) == 0)
              {
                  // Get Size of SPC_SP_OPUS_INFO structure.
                  fResult = CryptDecodeObject(ENCODING,
                              SPC_SP_OPUS_INFO_OBJID,
                              pSignerInfo-&gt;AuthAttrs.rgAttr[n].rgValue[0].pbData,
                              pSignerInfo-&gt;AuthAttrs.rgAttr[n].rgValue[0].cbData,
                              0,
                              NULL,
                              &amp;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-&gt;AuthAttrs.rgAttr[n].rgValue[0].pbData,
                              pSignerInfo-&gt;AuthAttrs.rgAttr[n].rgValue[0].cbData,
                              0,
                              OpusInfo,
                              &amp;dwData);
                  if (!fResult)
                  {
                      _tprintf(_T("CryptDecodeObject failed with %x\n"),
                          GetLastError());
                      __leave;
                  }
  
                  // Fill in Program Name if present.
                  if (OpusInfo-&gt;pwszProgramName)
                  {
                      Info-&gt;lpszProgramName =
                          AllocateAndCopyWideString(OpusInfo-&gt;pwszProgramName);
                  }
                  else
                      Info-&gt;lpszProgramName = NULL;
  
                  // Fill in Publisher Information if present.
                  if (OpusInfo-&gt;pPublisherInfo)
                  {
  
                      switch (OpusInfo-&gt;pPublisherInfo-&gt;dwLinkChoice)
                      {
                          case SPC_URL_LINK_CHOICE:
                              Info-&gt;lpszPublisherLink =
                                  AllocateAndCopyWideString(OpusInfo-&gt;pPublisherInfo-&gt;pwszUrl);
                              break;
  
                          case SPC_FILE_LINK_CHOICE:
                              Info-&gt;lpszPublisherLink =
                                  AllocateAndCopyWideString(OpusInfo-&gt;pPublisherInfo-&gt;pwszFile);
                              break;
  
                          default:
                              Info-&gt;lpszPublisherLink = NULL;
                              break;
                      }
                  }
                  else
                  {
                      Info-&gt;lpszPublisherLink = NULL;
                  }
  
                  // Fill in More Info if present.
                  if (OpusInfo-&gt;pMoreInfo)
                  {
                      switch (OpusInfo-&gt;pMoreInfo-&gt;dwLinkChoice)
                      {
                          case SPC_URL_LINK_CHOICE:
                              Info-&gt;lpszMoreInfoLink =
                                  AllocateAndCopyWideString(OpusInfo-&gt;pMoreInfo-&gt;pwszUrl);
                              break;
  
                          case SPC_FILE_LINK_CHOICE:
                              Info-&gt;lpszMoreInfoLink =
                                  AllocateAndCopyWideString(OpusInfo-&gt;pMoreInfo-&gt;pwszFile);
                              break;
  
                          default:
                              Info-&gt;lpszMoreInfoLink = NULL;
                              break;
                      }
                  }               
                  else
                  {
                      Info-&gt;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 &lt; pSignerInfo-&gt;AuthAttrs.cAttr; n++)
      {           
          if (lstrcmpA(szOID_RSA_signingTime, 
                      pSignerInfo-&gt;AuthAttrs.rgAttr[n].pszObjId) == 0)
          {               
              // Decode and get FILETIME structure.
              dwData = sizeof(ft);
              fResult = CryptDecodeObject(ENCODING,
                          szOID_RSA_signingTime,
                          pSignerInfo-&gt;AuthAttrs.rgAttr[n].rgValue[0].pbData,
                          pSignerInfo-&gt;AuthAttrs.rgAttr[n].rgValue[0].cbData,
                          0,
                          (PVOID)&amp;ft,
                          &amp;dwData);
              if (!fResult)
              {
                  _tprintf(_T("CryptDecodeObject failed with %x\n"),
                      GetLastError());
                  break;
              }
  
              // Convert to local time.
              FileTimeToLocalFileTime(&amp;ft, &amp;lft);
              FileTimeToSystemTime(&amp;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 &lt; pSignerInfo-&gt;UnauthAttrs.cAttr; n++)
          {
              if (lstrcmpA(pSignerInfo-&gt;UnauthAttrs.rgAttr[n].pszObjId, 
                           szOID_RSA_counterSign) == 0)
              {
                  // Get size of CMSG_SIGNER_INFO structure.
                  fResult = CryptDecodeObject(ENCODING,
                             PKCS7_SIGNER_INFO,
                             pSignerInfo-&gt;UnauthAttrs.rgAttr[n].rgValue[0].pbData,
                             pSignerInfo-&gt;UnauthAttrs.rgAttr[n].rgValue[0].cbData,
                             0,
                             NULL,
                             &amp;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-&gt;UnauthAttrs.rgAttr[n].rgValue[0].pbData,
                             pSignerInfo-&gt;UnauthAttrs.rgAttr[n].rgValue[0].cbData,
                             0,
                             (PVOID)*pCounterSignerInfo,
                             &amp;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;
  }
  </code></pre>
  
  <p>Unfortunately what I came up with doesn't always work correctly when dealing with dual signatures.</p>
  
  <p>For instance, a <strong>working example</strong>. If I run it on Sysiternal's <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/procmon" rel="nofollow noreferrer">ProcMon</a>, that has a dual-signature as we can see from Windows Explorer:</p>
  
  <p><a href="https://i.stack.imgur.com/8PRG2.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8PRG2.png" alt="enter image description here"></a></p>
  
  <p>My code correctly retrieves both <code>SHA1</code> and <code>SHA256</code> signatures:</p>
  
  <p><a href="https://i.stack.imgur.com/n90hF.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/n90hF.png" alt="enter image description here"></a></p>
  
  <p>But, here's a <strong>non-working</strong> example. If I run it on some other dual-signed file, say <a href="https://the.earth.li/~sgtatham/putty/latest/w64/putty.exe" rel="nofollow noreferrer">Putty</a> executable, which also has a dual signature:</p>
  
  <p><a href="https://i.stack.imgur.com/AW8SE.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/AW8SE.png" alt="enter image description here"></a></p>
  
  <p>The code above retrieves the same <code>SHA256</code> cert twice:</p>
  
  <p><a href="https://i.stack.imgur.com/VfRUa.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/VfRUa.png" alt="enter image description here"></a></p>
  
  <p>Any idea why?</p>
  
  <p>PS. This doesn't just happen with the Putty's signature. There are other dual-signed executables that exhibit the same behavior.</p>