Home › Forums › Discussions › General › Verify digital signature of an executable file
- This topic has 8 replies, 3 voices, and was last updated 15 years, 3 months ago by Anonymous.
-
AuthorPosts
-
May 7, 2007 at 11:16 am #5090Anonymous
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
May 8, 2007 at 8:14 am #6227If 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…
May 9, 2007 at 7:49 am #6228AnonymousHello,
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_EXECUTEHow could I determine what catalog file should be used for a specified file?
Thanks!Sorin
May 9, 2007 at 8:32 am #6229I 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.
May 11, 2007 at 7:43 am #6230AnonymousHi,
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
May 21, 2007 at 5:12 pm #6231AnonymousI have a problem…
After WinVerifyTrust() function returnes a dozen of threads remain opened.
Why is this happen?Sorin
April 1, 2009 at 8:28 am #6232how you fill WINTRUST_CATALOG_INFO structure?
April 1, 2009 at 8:29 am #6233Hello 🙂
Please deminstrate me your code for filling WINTRUST_CATALOG_INFO structure 🙂September 16, 2009 at 1:04 pm #6234AnonymousHello,
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
-
AuthorPosts
- You must be logged in to reply to this topic.