Verify digital signature of an executable file

Home Forums Discussions General Verify digital signature of an executable file

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #5090
    Anonymous

      Hello everybody!

      How can be verified the digital signature of an exe file?
      I tryed the WinVerifyTrust function, but it doesn’t work properly (the function returs TRUST_E_SUBJECT_NOT_TRUSTED when verifying “notepad.exe” file).
      Even SignTool.exe from Microsoft doesn’t recognizes “notepad.exe” file.
      SigCheck.exe from SysInternals is the only one I found so far that recognizes exe files like notepad.exe, explorer.exe as being signed by Microsoft.
      Does anyone have any idea how this can be done?
      Thanks!

      Sorin

      #6227
      Vadim Smirnov
      Keymaster

        If you look inside sigcheck.exe you will find that it works through wintrust.dll exported functions.

        .text:00402260 sub_402260      proc near               ; CODE XREF: _wmain:loc_402016p
        .text:00402260                 mov     al, byte_425860
        .text:00402265                 push    ebx
        .text:00402266                 test    al, al
        .text:00402268                 push    esi
        .text:00402269                 jnz     loc_402339
        .text:0040226F                 mov     ebx, ds:LoadLibraryW
        .text:00402275                 push    offset aWintrust_dll ; "Wintrust.dll"
        .text:0040227A                 mov     byte_425860, 1
        .text:00402281                 call    ebx ; LoadLibraryW
        .text:00402283                 mov     esi, eax
        .text:00402285                 test    esi, esi
        .text:00402287                 jnz     short loc_40228E
        .text:00402289                 pop     esi
        .text:0040228A                 xor     al, al
        .text:0040228C                 pop     ebx
        .text:0040228D                 retn
        .text:0040228E ;
        <hr class="bbcode_rule" />
        .text:0040228E
        .text:0040228E loc_40228E:                             ; CODE XREF: sub_402260+27j
        .text:0040228E                 push    edi
        .text:0040228F                 mov     edi, ds:GetProcAddress
        .text:00402295                 push    offset aWinverifytrust ; "WinVerifyTrust"
        .text:0040229A                 push    esi             ; hModule
        .text:0040229B                 call    edi ; GetProcAddress
        .text:0040229D                 push    offset aWthelpergetpro ; "WTHelperGetProvSignerFromChain"
        .text:004022A2                 push    esi             ; hModule
        .text:004022A3                 mov     WinVerifyTrustPtr, eax
        .text:004022A8                 call    edi ; GetProcAddress
        .text:004022AA                 push    offset aWthelperprovda ; "WTHelperProvDataFromStateData"
        .text:004022AF                 push    esi             ; hModule
        .text:004022B0                 mov     dword_425834, eax
        .text:004022B5                 call    edi ; GetProcAddress
        .text:004022B7                 push    offset aCryptcatadminr ; "CryptCATAdminReleaseContext"
        .text:004022BC                 push    esi             ; hModule
        .text:004022BD                 mov     dword_425838, eax
        .text:004022C2                 call    edi ; GetProcAddress
        .text:004022C4                 push    offset aCryptcatadmi_0 ; "CryptCATAdminReleaseCatalogContext"
        .text:004022C9                 push    esi             ; hModule
        .text:004022CA                 mov     dword_42583C, eax
        .text:004022CF                 call    edi ; GetProcAddress
        .text:004022D1                 push    offset aCryptcatcatalo ; "CryptCATCatalogInfoFromContext"
        .text:004022D6                 push    esi             ; hModule
        .text:004022D7                 mov     dword_42585C, eax
        .text:004022DC                 call    edi ; GetProcAddress
        .text:004022DE                 push    offset aCryptcatadmine ; "CryptCATAdminEnumCatalogFromHash"
        .text:004022E3                 push    esi             ; hModule
        .text:004022E4                 mov     dword_425854, eax
        .text:004022E9                 call    edi ; GetProcAddress
        .text:004022EB                 push    offset aCryptcatadminc ; "CryptCATAdminCalcHashFromFileHandle"
        .text:004022F0                 push    esi             ; hModule
        .text:004022F1                 mov     dword_425848, eax
        .text:004022F6                 call    edi ; GetProcAddress
        .text:004022F8                 push    offset aCryptcatadmina ; "CryptCATAdminAcquireContext"
        .text:004022FD                 push    esi             ; hModule
        .text:004022FE                 mov     dword_425840, eax
        .text:00402303                 call    edi ; GetProcAddress
        .text:00402305                 push    offset aCryptcatadmi_1 ; "CryptCATAdminAddCatalog"
        .text:0040230A                 push    esi             ; hModule
        .text:0040230B                 mov     dword_42584C, eax
        .text:00402310                 call    edi ; GetProcAddress
        .text:00402312                 push    offset aWinverifytrust ; "WinVerifyTrust"
        .text:00402317                 push    esi             ; hModule
        .text:00402318                 mov     dword_425844, eax
        .text:0040231D                 call    edi ; GetProcAddress
        .text:0040231F                 push    offset aCertnametostrw ; "CertNameToStrW"
        .text:00402324                 push    offset aCrypt32_dll ; "crypt32.dll"
        .text:00402329                 mov     WinVerifyTrustPtr, eax
        .text:0040232E                 call    ebx ; LoadLibraryW
        .text:00402330                 push    eax             ; hModule
        .text:00402331                 call    edi ; GetProcAddress
        .text:00402333                 mov     dword_425858, eax
        .text:00402338                 pop     edi
        .text:00402339
        .text:00402339 loc_402339:                             ; CODE XREF: sub_402260+9j
        .text:00402339                 mov     ecx, dword_42584C
        .text:0040233F                 xor     eax, eax
        .text:00402341                 test    ecx, ecx
        .text:00402343                 pop     esi
        .text:00402344                 pop     ebx
        .text:00402345                 setnz   al
        .text:00402348                 retn
        .text:00402348 sub_402260      endp

        WinVerifyTrust is called with WINTRUST_ACTION_GENERIC_VERIFY_V2 action ID.

        A piece of code which demonstrates usage of WinVerifyTrust can be found in the Platform SDK samples (vertrust.cpp):

        <br />
        /////////////////////////////////////////////////////////////////////////////<br />
        // IsFileTrusted<br />
        //<br />
        itvEnum IsFileTrusted(LPCWSTR lpwFile, HWND hwndParent, DWORD dwUIChoice, bool *pfIsSigned, PCCERT_CONTEXT *ppcSigner)<br />
        {<br />
        char szDebugOutput[MAX_STR_LENGTH] = {0};<br />
        <br />
        itvEnum itv = itvUnTrusted;<br />
        <br />
        if (pfIsSigned)<br />
        *pfIsSigned = false;<br />
        if (ppcSigner)<br />
        *ppcSigner  = 0;<br />
        <br />
        GUID guidAction = WINTRUST_ACTION_GENERIC_VERIFY_V2;<br />
        <br />
        WINTRUST_FILE_INFO sWintrustFileInfo;<br />
        WINTRUST_DATA      sWintrustData;<br />
        HRESULT            hr;<br />
        <br />
        memset((void*)&sWintrustFileInfo, 0x00, sizeof(WINTRUST_FILE_INFO)); // zero out<br />
        memset((void*)&sWintrustData, 0x00, sizeof(WINTRUST_DATA)); // zero out<br />
        <br />
        sWintrustFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);<br />
        sWintrustFileInfo.pcwszFilePath = lpwFile;<br />
        sWintrustFileInfo.hFile = NULL;<br />
        <br />
        sWintrustData.cbStruct            = sizeof(WINTRUST_DATA);<br />
        sWintrustData.dwUIChoice          = dwUIChoice;<br />
        sWintrustData.fdwRevocationChecks = WTD_REVOKE_NONE;<br />
        sWintrustData.dwUnionChoice       = WTD_CHOICE_FILE;<br />
        sWintrustData.pFile               = &sWintrustFileInfo;<br />
        sWintrustData.dwStateAction       = (ppcSigner) ? WTD_STATEACTION_VERIFY : 0;<br />
        <br />
        HMODULE hWinTrust = LoadLibrary(WINTRUST_DLL);<br />
        if (!hWinTrust)<br />
        {<br />
        // WinTrust is unavailable on the machine<br />
        return itvWintrustNotOnMachine;<br />
        }<br />
        PFnWinVerifyTrust pfnWinVerifyTrust = (PFnWinVerifyTrust)GetProcAddress(hWinTrust, WINTRUSTAPI_WinVerifyTrust);<br />
        PFnWTHelperProvDataFromStateData pfnWTHelperProvDataFromStateData= (PFnWTHelperProvDataFromStateData)GetProcAddress(hWinTrust, WINTRUSTAPI_WTHelperProvDataFromStateData);<br />
        PFnWTHelperGetProvSignerFromChain pfnWTHelperGetProvSignerFromChain = (PFnWTHelperGetProvSignerFromChain)GetProcAddress(hWinTrust, WINTRUSTAPI_WTHelperGetProvSignerFromChain);<br />
        PFnWTHelperGetProvCertFromChain pfnWTHelperGetProvCertFromChain = (PFnWTHelperGetProvCertFromChain)GetProcAddress(hWinTrust, WINTRUSTAPI_WTHelperGetProvCertFromChain);<br />
        if (!pfnWinVerifyTrust || !pfnWTHelperProvDataFromStateData || !pfnWTHelperGetProvSignerFromChain || !pfnWTHelperGetProvCertFromChain)<br />
        {<br />
        // WinTrust is unavailable on the machine<br />
        FreeLibrary(hWinTrust);<br />
        return itvWintrustNotOnMachine;<br />
        }<br />
        <br />
        hr = pfnWinVerifyTrust(/* UI Window Handle */ (dwUIChoice == WTD_UI_NONE) ? (HWND)INVALID_HANDLE_VALUE : hwndParent, &guidAction, &sWintrustData);<br />
        DebugMsg("[WVT] WVT returned 0x%Xn", hr);<br />
        <br />
        itv = (TRUST_E_PROVIDER_UNKNOWN == hr) ? itvWintrustNotOnMachine : ((S_OK == hr) ? itvTrusted : itvUnTrusted);<br />
        <br />
        if (itvWintrustNotOnMachine == itv)<br />
        {<br />
        // release state data<br />
        sWintrustData.dwUIChoice = WTD_UI_NONE;<br />
        sWintrustData.dwStateAction = WTD_STATEACTION_CLOSE;<br />
        pfnWinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &guidAction, &sWintrustData);<br />
        <br />
        FreeLibrary(hWinTrust);<br />
        return itv; // return immediately<br />
        }<br />
        <br />
        if (pfIsSigned)<br />
        *pfIsSigned = (TRUST_E_NOSIGNATURE == hr) ? false : true;<br />
        <br />
        if (TRUST_E_NOSIGNATURE == hr)<br />
        {<br />
        // release state data<br />
        sWintrustData.dwUIChoice = WTD_UI_NONE;<br />
        sWintrustData.dwStateAction = WTD_STATEACTION_CLOSE;<br />
        pfnWinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &guidAction, &sWintrustData);<br />
        <br />
        FreeLibrary(hWinTrust);<br />
        return itv;<br />
        }<br />
        <br />
        if (ppcSigner)<br />
        {<br />
        CRYPT_PROVIDER_DATA const *psProvData     = NULL;<br />
        CRYPT_PROVIDER_SGNR       *psProvSigner   = NULL;<br />
        CRYPT_PROVIDER_CERT       *psProvCert     = NULL;<br />
        <br />
        // grab the provider data<br />
        psProvData = pfnWTHelperProvDataFromStateData(sWintrustData.hWVTStateData);<br />
        if (psProvData)<br />
        {<br />
        // grab the signer data from the CRYPT_PROV_DATA<br />
        psProvSigner = pfnWTHelperGetProvSignerFromChain((PCRYPT_PROVIDER_DATA)psProvData, 0 /*first signer*/, FALSE /* not a counter signer */, 0);<br />
        if (psProvSigner)<br />
        {<br />
        // grab the signer cert from CRYPT_PROV_SGNR (pos 0 = signer cert; pos csCertChain-1 = root cert)<br />
        psProvCert = pfnWTHelperGetProvCertFromChain(psProvSigner, 0);<br />
        }<br />
        }<br />
        <br />
        if (!psProvCert)<br />
        {<br />
        // some failure in obtaining the signer cert data<br />
        *ppcSigner = 0;<br />
        }<br />
        else<br />
        {<br />
        // duplicate the cert<br />
        HMODULE hCrypt32 = LoadLibrary(CRYPT32_DLL);<br />
        if (hCrypt32)<br />
        {<br />
        PFnCertDuplicateCertificateContext pfnCertDuplicateCertificateContext = (PFnCertDuplicateCertificateContext)GetProcAddress(hCrypt32, CRYPTOAPI_CertDuplicateCertificateContext);<br />
        if (pfnCertDuplicateCertificateContext)<br />
        *ppcSigner = pfnCertDuplicateCertificateContext(psProvCert->pCert);<br />
        FreeLibrary(hCrypt32);<br />
        }<br />
        }<br />
        <br />
        // release state data<br />
        sWintrustData.dwUIChoice = WTD_UI_NONE;<br />
        sWintrustData.dwStateAction = WTD_STATEACTION_CLOSE;<br />
        pfnWinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &guidAction, &sWintrustData);<br />
        }<br />
        <br />
        FreeLibrary(hWinTrust);<br />
        return itv;<br />
        }<br />
        

        Hope it helps…

        #6228
        Anonymous

          Hello,

          Thanks for your reply..
          I took your advice and had a closer look at SigCheck and found out that SigCheck passes to WINTRUST_DATA structure (the third parameter of WinVerifyTrust function) a pointer to a catalog file.
          Here is how WINTRUST_DATA structure looks when WinVerifyTrust function is first called be SigCheck:

          WINTRUST_DATA members and values:
          cbStruct=48
          pPolicyCallbackData=0x00000000
          pSIPClientData=0x00000000
          dwUIChoice=2 //WTD_UI_NONE
          fdwRevocationChecks=0 //WTD_REVOKE_NONE
          dwUnionChoice=2 //WTD_CHOICE_CATALOG
          pCatalog=0x0012e570
          —>cbStruct=36
          —>dwCatalogVersion=0
          —>pcwszCatalogFilePath=0x0012e5ec “C:WINDOWSsystem32CatRoot{F750E6C3-38EE-11D1-85E5-00C04FC295EE}NT5.CAT”
          —>pcwszMemberTag=0x0012e594 “8CD65FA193E9D11D5C1D946CFC003FB03F21D2F2”
          —>pcwszMemberFilePath=0x0012f73c “c:windowsnotepad.exe”
          —>hMemberFile=0x00000000
          —>pbCalculatedFileHash=0x0012e55c
          —>cbCalculatedFileHash=20
          —>pcCatalogContext=0x00000000
          dwStateAction=1 //WTD_STATEACTION_VERIFY
          hWVTStateData=0x00000000
          pwszURLReference=0x00000000
          dwProvFlags=0
          dwUIContext=0 //WTD_UICONTEXT_EXECUTE

          How could I determine what catalog file should be used for a specified file?
          Thanks!

          Sorin

          #6229
          Vadim Smirnov
          Keymaster

            I have never dig deep into file signing, but I’d guess that in case of notepad.exe the signature is not embedded into the executable, but the whole CAT file is signed instead.

            How could I determine what catalog file should be used for a specified file?

            I think you should use CryptCATXXX functions for this. Probably CryptCATAdminCalcHashFromFileHandle to get the file hash and then enumerate catalogs which contain the specified hash with CryptCATAdminEnumCatalogFromHash.

            #6230
            Anonymous

              Hi,

              Thanks SerpentFly for your kind answers. It really helped….
              Indeed using CryptCATXXX functions I maneged to obtain a pointer to CATALOG_INFO for WINTRUST_DATA structure that I needed to pass to WinVerifyTrust() and the function returns the corect result.

              Sorin

              #6231
              Anonymous

                I have a problem…
                After WinVerifyTrust() function returnes a dozen of threads remain opened.
                Why is this happen?

                Sorin

                #6232
                eboev
                Participant

                  how you fill WINTRUST_CATALOG_INFO structure?

                  #6233
                  eboev
                  Participant

                    Hello 🙂
                    Please deminstrate me your code for filling WINTRUST_CATALOG_INFO structure 🙂

                    #6234
                    Anonymous

                      Hello,

                      The WINTRUST_CATALOG_INFO is filled like this:

                      //*****************************************************************************************//

                      WINTRUST_CATALOG_INFO CatalogData = {0};
                      CATALOG_INFO CatInfo = {0};
                      DWORD dw;
                      BYTE byHash[100];
                      wchar_t* pwszMemberTag = NULL;

                      /*…*/

                      // Initialize the WINTRUST_CATALOG_INFO structure.
                      CatalogData.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
                      CatalogData.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
                      CatalogData.pcwszMemberTag = pwszMemberTag;
                      CatalogData.pcwszMemberFilePath = pwszSourceFile;
                      CatalogData.pbCalculatedFileHash = byHash;
                      CatalogData.cbCalculatedFileHash = cbHash;

                      //*****************************************************************************************//

                      The pwszMemberTag variable it’s calculated as follows:

                      //*****************************************************************************************//

                      pwszMemberTag = (wchar_t*) malloc(sizeof(wchar_t) * (2 * cbHash + 1));
                      for ( dw = 0; dw < cbHash; ++dw )
                      {
                      wsprintfW( &pwszMemberTag[dw * 2], L”%02X”, byHash[dw] );
                      }

                      //*****************************************************************************************//

                      The other variables that fill the WINTRUST_CATALOG_INFO structure are obtained using CryptCatXXX functions.

                      Good luck!

                      Sorin

                    Viewing 9 posts - 1 through 9 (of 9 total)
                    • You must be logged in to reply to this topic.