Verifying PE Signatures - Revisited

Just starting out? Need help? Post your questions and find answers here.
fluent
User
User
Posts: 68
Joined: Sun Jan 24, 2021 10:57 am

Verifying PE Signatures - Revisited

Post by fluent »

I've been trying to revive an old code example (first posted by Flower)… I feel I'm almost there, but verifying Authenticode signatures are still failing for notepad.exe and iexplore.exe for instance. (The result should be 1, not 0. See example below)
Hopefully an API guru will see what's wrong here.

Note: The code is mostly based on this article: https://docs.microsoft.com/en-us/window ... -a-pe-file

Code: Select all

EnableExplicit

#WINTRUST_MAX_HEADER_BYTES_TO_MAP_DEFAULT = $00A00000
#WINTRUST_MAX_HASH_BYTES_TO_MAP_DEFAULT = $00100000
#WTD_UI_ALL = 1
#WTD_UI_NONE = 2
#WTD_UI_NOBAD = 3
#WTD_UI_NOGOOD = 4
#WTD_REVOKE_NONE = $00000000
#WTD_REVOKE_WHOLECHAIN = $00000001
#WTD_CHOICE_FILE = 1
#WTD_CHOICE_CATALOG = 2
#WTD_CHOICE_BLOB = 3
#WTD_CHOICE_SIGNER = 4
#WTD_CHOICE_CERT = 5
#WTD_STATEACTION_IGNORE = $00000000
#WTD_STATEACTION_VERIFY = $00000001
#WTD_STATEACTION_CLOSE = $00000002
#WTD_STATEACTION_AUTO_CACHE = $00000003
#WTD_STATEACTION_AUTO_CACHE_FLUSH = $00000004
#WTD_PROV_FLAGS_MASK = $0000FFFF
#WTD_USE_IE4_TRUST_FLAG = $00000001
#WTD_NO_IE4_CHAIN_FLAG = $00000002
#WTD_NO_POLICY_USAGE_FLAG = $00000004
#WTD_REVOCATION_CHECK_NONE = $00000010
#WTD_REVOCATION_CHECK_END_CERT = $00000020
#WTD_REVOCATION_CHECK_CHAIN = $00000040
#WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = $00000080
#WTD_SAFER_FLAG = $00000100
#WTD_HASH_ONLY_FLAG = $00000200
#WTD_USE_DEFAULT_OSVER_CHECK = $00000400
#WTD_LIFETIME_SIGNING_FLAG = $00000800
#WTD_CACHE_ONLY_URL_RETRIEVAL = $00001000
#WTD_UICONTEXT_EXECUTE = 0
#WTD_UICONTEXT_INSTALL = 1
#WTCI_DONT_OPEN_STORES = $00000001
#WTCI_OPEN_ONLY_ROOT = $00000002
#WTCI_USE_LOCAL_MACHINE = $00000004
#WTPF_TRUSTTEST = $00000020
#WTPF_TESTCANBEVALID = $00000080
#WTPF_IGNOREEXPIRATION = $00000100
#WTPF_IGNOREREVOKATION = $00000200
#WTPF_OFFLINEOK_IND = $00000400
#WTPF_OFFLINEOK_COM = $00000800
#WTPF_OFFLINEOKNBU_IND = $00001000
#WTPF_OFFLINEOKNBU_COM = $00002000
#WTPF_VERIFY_V1_OFF = $00010000
#WTPF_IGNOREREVOCATIONONTS = $00020000
#WTPF_ALLOWONLYPERTRUST = $00040000
#TRUSTERROR_STEP_WVTPARAMS = 0
#TRUSTERROR_STEP_FILEIO = 2
#TRUSTERROR_STEP_SIP = 3
#TRUSTERROR_STEP_SIPSUBJINFO = 5
#TRUSTERROR_STEP_CATALOGFILE = 6
#TRUSTERROR_STEP_CERTSTORE = 7
#TRUSTERROR_STEP_MESSAGE = 8
#TRUSTERROR_STEP_MSG_SIGNERCOUNT = 9
#TRUSTERROR_STEP_MSG_INNERCNTTYPE = 10
#TRUSTERROR_STEP_MSG_INNERCNT = 11
#TRUSTERROR_STEP_MSG_STORE = 12
#TRUSTERROR_STEP_MSG_SIGNERINFO = 13
#TRUSTERROR_STEP_MSG_SIGNERCERT = 14
#TRUSTERROR_STEP_MSG_CERTCHAIN = 15
#TRUSTERROR_STEP_MSG_COUNTERSIGINFO = 16
#TRUSTERROR_STEP_MSG_COUNTERSIGCERT = 17
#TRUSTERROR_STEP_VERIFY_MSGHASH = 18
#TRUSTERROR_STEP_VERIFY_MSGINDIRECTDATA = 19
#TRUSTERROR_STEP_FINAL_WVTINIT = 30
#TRUSTERROR_STEP_FINAL_INITPROV = 31
#TRUSTERROR_STEP_FINAL_OBJPROV = 32
#TRUSTERROR_STEP_FINAL_SIGPROV = 33
#TRUSTERROR_STEP_FINAL_CERTPROV = 34
#TRUSTERROR_STEP_FINAL_CERTCHKPROV = 35
#TRUSTERROR_STEP_FINAL_POLICYPROV = 36
#TRUSTERROR_STEP_FINAL_UIPROV = 37
#TRUSTERROR_MAX_STEPS = 38
#CPD_USE_NT5_CHAIN_FLAG = $80000000
#CPD_REVOCATION_CHECK_NONE = $00010000
#CPD_REVOCATION_CHECK_END_CERT = $00020000
#CPD_REVOCATION_CHECK_CHAIN = $00040000
#CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = $00080000
#CPD_UISTATE_MODE_PROMPT = $00000000
#CPD_UISTATE_MODE_BLOCK = $00000001
#CPD_UISTATE_MODE_ALLOW = $00000002
#CPD_UISTATE_MODE_MASK = $00000003
#CERT_CONFIDENCE_SIG = $10000000
#CERT_CONFIDENCE_TIME = $01000000
#CERT_CONFIDENCE_TIMENEST = $00100000
#CERT_CONFIDENCE_AUTHIDEXT = $00010000
#CERT_CONFIDENCE_HYGIENE = $00001000
#CERT_CONFIDENCE_HIGHEST = $11111000
#DWACTION_ALLOCANDFILL = 1
#DWACTION_FREE = 2
#szOID_TRUSTED_CODESIGNING_CA_LIST = "1.3.6.1.4.1.311.2.2.1"
#szOID_TRUSTED_CLIENT_AUTH_CA_LIST = "1.3.6.1.4.1.311.2.2.2"
#szOID_TRUSTED_SERVER_AUTH_CA_LIST = "1.3.6.1.4.1.311.2.2.3"
#SPC_TIME_STAMP_REQUEST_OBJID = "1.3.6.1.4.1.311.3.2.1"
#SPC_INDIRECT_DATA_OBJID = "1.3.6.1.4.1.311.2.1.4"
#SPC_SP_AGENCY_INFO_OBJID = "1.3.6.1.4.1.311.2.1.10"
#SPC_STATEMENT_TYPE_OBJID = "1.3.6.1.4.1.311.2.1.11"
#SPC_SP_OPUS_INFO_OBJID = "1.3.6.1.4.1.311.2.1.12"
#SPC_CERT_EXTENSIONS_OBJID = "1.3.6.1.4.1.311.2.1.14"
#SPC_PE_IMAGE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.15"
#SPC_RAW_FILE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.18"
#SPC_STRUCTURED_STORAGE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.19"
#SPC_JAVA_CLASS_DATA_OBJID = "1.3.6.1.4.1.311.2.1.20"
#SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID = "1.3.6.1.4.1.311.2.1.21"
#SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID = "1.3.6.1.4.1.311.2.1.22"
#SPC_CAB_DATA_OBJID = "1.3.6.1.4.1.311.2.1.25"
#SPC_GLUE_RDN_OBJID = "1.3.6.1.4.1.311.2.1.25"
#SPC_MINIMAL_CRITERIA_OBJID = "1.3.6.1.4.1.311.2.1.26"
#SPC_FINANCIAL_CRITERIA_OBJID = "1.3.6.1.4.1.311.2.1.27"
#SPC_LINK_OBJID = "1.3.6.1.4.1.311.2.1.28"
#SPC_SIGINFO_OBJID = "1.3.6.1.4.1.311.2.1.30"
#SPC_PE_IMAGE_PAGE_HASHES_V1_OBJID = "1.3.6.1.4.1.311.2.3.1"
#SPC_PE_IMAGE_PAGE_HASHES_V2_OBJID = "1.3.6.1.4.1.311.2.3.2"
#CAT_NAMEVALUE_OBJID = "1.3.6.1.4.1.311.12.2.1"
#CAT_MEMBERINFO_OBJID = "1.3.6.1.4.1.311.12.2.2"
#SPC_SP_AGENCY_INFO_STRUCT =(2000)
#SPC_MINIMAL_CRITERIA_STRUCT =(2001)
#SPC_FINANCIAL_CRITERIA_STRUCT =(2002)
#SPC_INDIRECT_DATA_CONTENT_STRUCT =(2003)
#SPC_PE_IMAGE_DATA_STRUCT =(2004)
#SPC_LINK_STRUCT =(2005)
#SPC_STATEMENT_TYPE_STRUCT =(2006)
#SPC_SP_OPUS_INFO_STRUCT =(2007)
#SPC_CAB_DATA_STRUCT =(2008)
#SPC_JAVA_CLASS_DATA_STRUCT =(2009)
#SPC_SIGINFO_STRUCT =(2130)
#CAT_NAMEVALUE_STRUCT =(2221)
#CAT_MEMBERINFO_STRUCT =(2222)
#SPC_UUID_LENGTH = 16
#WIN_CERT_REVISION_1_0 =($0100)
#WIN_CERT_REVISION_2_0 =($0200)
#WIN_CERT_TYPE_X509 =($0001)
#WIN_CERT_TYPE_PKCS_SIGNED_DATA =($0002)
#WIN_CERT_TYPE_RESERVED_1 =($0003)
#WIN_CERT_TYPE_TS_STACK_SIGNED =($0004)
#WT_TRUSTDBDIALOG_NO_UI_FLAG = $00000001
#WT_TRUSTDBDIALOG_ONLY_PUB_TAB_FLAG = $00000002
#WT_TRUSTDBDIALOG_WRITE_LEGACY_REG_FLAG = $00000100
#WT_TRUSTDBDIALOG_WRITE_IEAK_STORE_FLAG = $00000200

Structure WINTRUST_DATA
  cbStruct.l
  *pPolicyCallbackData
  *pSIPClientData
  dwUIChoice.l
  fdwRevocationChecks.l
  dwUnionChoice.l
  *pPointer
  dwStateAction.l
  hWVTStateData.l
  *pwszURLReference
  dwProvFlags.l
  dwUIContext.l
EndStructure

Structure WINTRUST_FILE_INFO
  cbStruct.l
  *pcwszFilePath
  hFile.l
  *pgKnownSubject
EndStructure

Structure WINTRUST_CATALOG_INFO
  cbStruct.l
  dwCatalogVersion.l
  *pcwszCatalogFilePath
  *pcwszMemberTag
  *pcwszMemberFilePath
  hMemberFile.l
EndStructure

Structure CATALOG_INFO
  cbStruct.l
  wszCatalogFile.b[520]
EndStructure

#WTD_CHOICE_FILE = 1
#WTD_CHOICE_CATALOG = 2
#WTD_UI_NONE = 2
#WTD_REVOKE_NONE = 0
#WTD_STATEACTION_IGNORE = 0
#WTD_STATEACTION_VERIFY = 1
#WTD_SAFER_FLAG = 256

define CLIB

CLIB=OpenLibrary(#PB_Any,"wintrust.dll")

Prototype     CryptCATAdminAcquireContext(*phCatAdmin, *pgSubsystem, dwFlags.l)
Prototype     CryptCATAdminReleaseContext(hCatAdmin.l, dwFlags.l)
Prototype     CryptCATAdminCalcHashFromFileHandle(hFile.l, *pcbHash, *pbHash, dwFlags.l)
Prototype     CryptCATAdminEnumCatalogFromHash(hCatAdmin.l, *pbHash, cbHash.l, dwFlags.l, *phPrevCatInfo)
Prototype     CryptCATCatalogInfoFromContext(hCatInfo.l, *psCatInfo, dwFlags.l)
Prototype     CryptCATAdminReleaseCatalogContext(hCatAdmin.l, hCatInfo.l, dwFlags.l)
Prototype     WinVerifyTrust(HWND.l, *pgActionID, *pWVTData)

global CryptCATAdminAcquireContext.CryptCATAdminAcquireContext                   = GetFunction(CLIB,"CryptCATAdminAcquireContext")  
global CryptCATAdminReleaseContext.CryptCATAdminReleaseContext                   = GetFunction(CLIB,"CryptCATAdminReleaseContext")  
global CryptCATAdminCalcHashFromFileHandle.CryptCATAdminCalcHashFromFileHandle   = GetFunction(CLIB,"CryptCATAdminCalcHashFromFileHandle")  
global CryptCATAdminEnumCatalogFromHash.CryptCATAdminEnumCatalogFromHash         = GetFunction(CLIB,"CryptCATAdminEnumCatalogFromHash")  
global CryptCATCatalogInfoFromContext.CryptCATCatalogInfoFromContext             = GetFunction(CLIB,"CryptCATCatalogInfoFromContext")  
global CryptCATAdminReleaseCatalogContext.CryptCATAdminReleaseCatalogContext     = GetFunction(CLIB,"CryptCATAdminReleaseCatalogContext")  
global WinVerifyTrust.WinVerifyTrust                                             = GetFunction(CLIB,"WinVerifyTrust")

debug WinVerifyTrust


Procedure CheckFileTrust(FilePath.s)
  Define bRet.l
  Define wd.WINTRUST_DATA
  Define wfi.WINTRUST_FILE_INFO
  Define wci.WINTRUST_CATALOG_INFO
  Define ci.CATALOG_INFO
  Define hCatAdmin.i
  Define bRet.l, hFile.l
  Define hr.l
  Define pszMemberTag.s
  Define dwCnt.l
  Dim byHash.b(99)
  Define dw.l
  Define hCatInfo.l
  
  ClearStructure(@wd, WINTRUST_DATA)
  ClearStructure(@wfi, WINTRUST_FILE_INFO)
  ClearStructure(@wci, WINTRUST_CATALOG_INFO)
  ClearStructure(@ci, CATALOG_INFO)
  
  bRet = #False
  hCatAdmin = #Null
  
  If(Not(CryptCATAdminAcquireContext(@hCatAdmin, #Null, 0)))
    debug "!!!!"
    ProcedureReturn #False
  EndIf
  
  ;********************
  ;Open file
  ;********************
  hFile = CreateFile_(@FilePath, #GENERIC_READ, #FILE_SHARE_READ, #Null, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, #Null)
  
  If (hFile = #INVALID_HANDLE_VALUE)
    Debug ("CheckFileTrust(): CreateFile FAILED, GetLastError = " + Hex(GetLastError_()))
    CryptCATAdminReleaseContext(hCatAdmin, 0)
    ProcedureReturn #False
  EndIf
  
  dwCnt = 100
  CryptCATAdminCalcHashFromFileHandle(hFile, @dwCnt, @byHash(), 0)
  
  ;********************
  ;Close file
  ;********************
  CloseHandle_(hFile)
  
  ;********************
  ;Compute member tag
  ;********************
  For dw = 0 To dwCnt - 1
    pszMemberTag + Right("0" + Hex(byHash(dw)), 2)
  Next
  
         Debug ("CheckFileTrust(): MemberTag = " + pszMemberTag)
  
  hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, @byHash(), dwCnt, 0, #Null)
  
  If (hCatInfo = #Null)
    Debug ("CheckFileTrust(): CryptCATAdminEnumCatalogFromHash FAILED, start verifying embedded signature.")
    wd\cbStruct = SizeOf(wd)
    
    ; Use default code signing EKU.
    wd\pPolicyCallbackData = #Null
    
    ; No data to pass to SIP.
    wd\pSIPClientData = #Null
    
    ; Disable WVT UI.
    wd\dwUIChoice = #WTD_UI_NONE
    
    ; No revocation checking.
    wd\fdwRevocationChecks = #WTD_REVOKE_NONE
    
    ; Verify an embedded signature on a file.
    wd\dwUnionChoice = #WTD_CHOICE_FILE
    
    ; Default verification.
    wd\dwStateAction = #WTD_STATEACTION_IGNORE
    
    ; Not applicable for default verification of embedded signature.
    wd\hWVTStateData = #Null
    
    ; Not used.
    wd\pwszURLReference = #Null
    
    ; Default.
    wd\dwProvFlags = #WTD_SAFER_FLAG
    
    ; This is not applicable if there is no UI because it changes
    ; the UI to accommodate running applications instead of
    ; installing applications.
    wd\dwUIContext = #Null
    
    ; Set pFile.
    wfi\cbStruct = SizeOf(WINTRUST_FILE_INFO)
    wfi\pcwszFilePath = @FilePath
    wfi\hFile = #Null
    wfi\pgKnownSubject = #Null
    wd\pPointer = @wfi
  Else
    If(Not(CryptCATCatalogInfoFromContext(hCatInfo, @ci, 0)))
      Debug ("CheckFileTrust(): CryptCATCatalogInfoFromContext FAILED, GetLastError = " + Hex(GetLastError_()))
    EndIf
    wci\cbStruct = SizeOf(wci)
    wci\pcwszCatalogFilePath = @ci\wszCatalogFile[0]
    debug peekS(wci\pcwszCatalogFilePath)
    debug FilePath
    wci\pcwszMemberFilePath = @FilePath
    wci\pcwszMemberTag = @pszMemberTag
    
    wd\cbStruct = SizeOf(wd)
    wd\dwUnionChoice = #WTD_CHOICE_CATALOG
    wd\pPointer = @wci
    wd\dwUIChoice = #WTD_UI_NONE
    wd\fdwRevocationChecks = #WTD_REVOKE_NONE
    wd\dwStateAction = #WTD_STATEACTION_VERIFY
    wd\dwProvFlags = 0
    wd\hWVTStateData = #Null
    wd\pwszURLReference = #Null
  EndIf
  
  Define action.GUID
  
  ;********************
  ; WINTRUST_ACTION_GENERIC_VERIFY_V2 (Authenticode)
  ;********************
  With action
    \Data1 = $AAC56B
    \Data2 = $CD44
    \Data3 = $11D0
    \Data4[0] = $8C
    \Data4[1] = $C2
    \Data4[2] = $00
    \Data4[3] = $C0
    \Data4[4] = $4F
    \Data4[5] = $C2
    \Data4[6] = $95
    \Data4[7] = $EE
  EndWith
  
  hr = WinVerifyTrust(#INVALID_HANDLE_VALUE, @action, @wd)
  debug "hr: 0x" + hex(hr)
  If (hCatInfo <> #Null)
    CryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0)
  EndIf
  
  CryptCATAdminReleaseContext(hCatAdmin, 0)
  
  If (hr = 0)
    wd\dwStateAction = #WTD_STATEACTION_CLOSE
    WinVerifyTrust(#INVALID_HANDLE_VALUE, @action, @wd)
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
  
EndProcedure


 Define.s szFile = "C:\Program Files\Internet Explorer\iexplore.exe"

debug szFile + " - " + CheckFileTrust(szFile)

  Define.s szFile = "c:\windows\system32\notepad.exe"

debug szFile + " - " + CheckFileTrust(szFile)
fluent
User
User
Posts: 68
Joined: Sun Jan 24, 2021 10:57 am

Re: Verifying PE Signatures - Revisited

Post by fluent »

Ha! It seems that the above code is (at least partly) obsolete, and the following API functions are needed to verify catalog-based signatures under modern Windows versions (to support SHA256 hashes in addition to SHA1):

CryptCATAdminAcquireContext2

Edit: removed link as it lacked some essential information - still researching
fluent
User
User
Posts: 68
Joined: Sun Jan 24, 2021 10:57 am

Re: Verifying PE Signatures - Revisited

Post by fluent »

Seems I got it working, but only on x86.
Verification fails under x64.
Help welcome :)

(My OS, if that matters: Windows 10 1909)

Code: Select all


;************************************************

; EnableExplicit

#WINTRUST_MAX_HEADER_BYTES_TO_MAP_DEFAULT = $00A00000
#WINTRUST_MAX_HASH_BYTES_TO_MAP_DEFAULT = $00100000
#WTD_UI_ALL = 1
#WTD_UI_NONE = 2
#WTD_UI_NOBAD = 3
#WTD_UI_NOGOOD = 4
#WTD_REVOKE_NONE = $00000000
#WTD_REVOKE_WHOLECHAIN = $00000001
#WTD_CHOICE_FILE = 1
#WTD_CHOICE_CATALOG = 2
#WTD_CHOICE_BLOB = 3
#WTD_CHOICE_SIGNER = 4
#WTD_CHOICE_CERT = 5
#WTD_STATEACTION_IGNORE = $00000000
#WTD_STATEACTION_VERIFY = $00000001
#WTD_STATEACTION_CLOSE = $00000002
#WTD_STATEACTION_AUTO_CACHE = $00000003
#WTD_STATEACTION_AUTO_CACHE_FLUSH = $00000004
#WTD_PROV_FLAGS_MASK = $0000FFFF
#WTD_USE_IE4_TRUST_FLAG = $00000001
#WTD_NO_IE4_CHAIN_FLAG = $00000002
#WTD_NO_POLICY_USAGE_FLAG = $00000004
#WTD_REVOCATION_CHECK_NONE = $00000010
#WTD_REVOCATION_CHECK_END_CERT = $00000020
#WTD_REVOCATION_CHECK_CHAIN = $00000040
#WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = $00000080
#WTD_SAFER_FLAG = $00000100
#WTD_HASH_ONLY_FLAG = $00000200
#WTD_USE_DEFAULT_OSVER_CHECK = $00000400
#WTD_LIFETIME_SIGNING_FLAG = $00000800
#WTD_CACHE_ONLY_URL_RETRIEVAL = $00001000
#WTD_UICONTEXT_EXECUTE = 0
#WTD_UICONTEXT_INSTALL = 1
#WTCI_DONT_OPEN_STORES = $00000001
#WTCI_OPEN_ONLY_ROOT = $00000002
#WTCI_USE_LOCAL_MACHINE = $00000004
#WTPF_TRUSTTEST = $00000020
#WTPF_TESTCANBEVALID = $00000080
#WTPF_IGNOREEXPIRATION = $00000100
#WTPF_IGNOREREVOKATION = $00000200
#WTPF_OFFLINEOK_IND = $00000400
#WTPF_OFFLINEOK_COM = $00000800
#WTPF_OFFLINEOKNBU_IND = $00001000
#WTPF_OFFLINEOKNBU_COM = $00002000
#WTPF_VERIFY_V1_OFF = $00010000
#WTPF_IGNOREREVOCATIONONTS = $00020000
#WTPF_ALLOWONLYPERTRUST = $00040000
#TRUSTERROR_STEP_WVTPARAMS = 0
#TRUSTERROR_STEP_FILEIO = 2
#TRUSTERROR_STEP_SIP = 3
#TRUSTERROR_STEP_SIPSUBJINFO = 5
#TRUSTERROR_STEP_CATALOGFILE = 6
#TRUSTERROR_STEP_CERTSTORE = 7
#TRUSTERROR_STEP_MESSAGE = 8
#TRUSTERROR_STEP_MSG_SIGNERCOUNT = 9
#TRUSTERROR_STEP_MSG_INNERCNTTYPE = 10
#TRUSTERROR_STEP_MSG_INNERCNT = 11
#TRUSTERROR_STEP_MSG_STORE = 12
#TRUSTERROR_STEP_MSG_SIGNERINFO = 13
#TRUSTERROR_STEP_MSG_SIGNERCERT = 14
#TRUSTERROR_STEP_MSG_CERTCHAIN = 15
#TRUSTERROR_STEP_MSG_COUNTERSIGINFO = 16
#TRUSTERROR_STEP_MSG_COUNTERSIGCERT = 17
#TRUSTERROR_STEP_VERIFY_MSGHASH = 18
#TRUSTERROR_STEP_VERIFY_MSGINDIRECTDATA = 19
#TRUSTERROR_STEP_FINAL_WVTINIT = 30
#TRUSTERROR_STEP_FINAL_INITPROV = 31
#TRUSTERROR_STEP_FINAL_OBJPROV = 32
#TRUSTERROR_STEP_FINAL_SIGPROV = 33
#TRUSTERROR_STEP_FINAL_CERTPROV = 34
#TRUSTERROR_STEP_FINAL_CERTCHKPROV = 35
#TRUSTERROR_STEP_FINAL_POLICYPROV = 36
#TRUSTERROR_STEP_FINAL_UIPROV = 37
#TRUSTERROR_MAX_STEPS = 38
#CPD_USE_NT5_CHAIN_FLAG = $80000000
#CPD_REVOCATION_CHECK_NONE = $00010000
#CPD_REVOCATION_CHECK_END_CERT = $00020000
#CPD_REVOCATION_CHECK_CHAIN = $00040000
#CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = $00080000
#CPD_UISTATE_MODE_PROMPT = $00000000
#CPD_UISTATE_MODE_BLOCK = $00000001
#CPD_UISTATE_MODE_ALLOW = $00000002
#CPD_UISTATE_MODE_MASK = $00000003
#CERT_CONFIDENCE_SIG = $10000000
#CERT_CONFIDENCE_TIME = $01000000
#CERT_CONFIDENCE_TIMENEST = $00100000
#CERT_CONFIDENCE_AUTHIDEXT = $00010000
#CERT_CONFIDENCE_HYGIENE = $00001000
#CERT_CONFIDENCE_HIGHEST = $11111000
#DWACTION_ALLOCANDFILL = 1
#DWACTION_FREE = 2
#szOID_TRUSTED_CODESIGNING_CA_LIST = "1.3.6.1.4.1.311.2.2.1"
#szOID_TRUSTED_CLIENT_AUTH_CA_LIST = "1.3.6.1.4.1.311.2.2.2"
#szOID_TRUSTED_SERVER_AUTH_CA_LIST = "1.3.6.1.4.1.311.2.2.3"
#SPC_TIME_STAMP_REQUEST_OBJID = "1.3.6.1.4.1.311.3.2.1"
#SPC_INDIRECT_DATA_OBJID = "1.3.6.1.4.1.311.2.1.4"
#SPC_SP_AGENCY_INFO_OBJID = "1.3.6.1.4.1.311.2.1.10"
#SPC_STATEMENT_TYPE_OBJID = "1.3.6.1.4.1.311.2.1.11"
#SPC_SP_OPUS_INFO_OBJID = "1.3.6.1.4.1.311.2.1.12"
#SPC_CERT_EXTENSIONS_OBJID = "1.3.6.1.4.1.311.2.1.14"
#SPC_PE_IMAGE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.15"
#SPC_RAW_FILE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.18"
#SPC_STRUCTURED_STORAGE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.19"
#SPC_JAVA_CLASS_DATA_OBJID = "1.3.6.1.4.1.311.2.1.20"
#SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID = "1.3.6.1.4.1.311.2.1.21"
#SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID = "1.3.6.1.4.1.311.2.1.22"
#SPC_CAB_DATA_OBJID = "1.3.6.1.4.1.311.2.1.25"
#SPC_GLUE_RDN_OBJID = "1.3.6.1.4.1.311.2.1.25"
#SPC_MINIMAL_CRITERIA_OBJID = "1.3.6.1.4.1.311.2.1.26"
#SPC_FINANCIAL_CRITERIA_OBJID = "1.3.6.1.4.1.311.2.1.27"
#SPC_LINK_OBJID = "1.3.6.1.4.1.311.2.1.28"
#SPC_SIGINFO_OBJID = "1.3.6.1.4.1.311.2.1.30"
#SPC_PE_IMAGE_PAGE_HASHES_V1_OBJID = "1.3.6.1.4.1.311.2.3.1"
#SPC_PE_IMAGE_PAGE_HASHES_V2_OBJID = "1.3.6.1.4.1.311.2.3.2"
#CAT_NAMEVALUE_OBJID = "1.3.6.1.4.1.311.12.2.1"
#CAT_MEMBERINFO_OBJID = "1.3.6.1.4.1.311.12.2.2"
#SPC_SP_AGENCY_INFO_STRUCT =(2000)
#SPC_MINIMAL_CRITERIA_STRUCT =(2001)
#SPC_FINANCIAL_CRITERIA_STRUCT =(2002)
#SPC_INDIRECT_DATA_CONTENT_STRUCT =(2003)
#SPC_PE_IMAGE_DATA_STRUCT =(2004)
#SPC_LINK_STRUCT =(2005)
#SPC_STATEMENT_TYPE_STRUCT =(2006)
#SPC_SP_OPUS_INFO_STRUCT =(2007)
#SPC_CAB_DATA_STRUCT =(2008)
#SPC_JAVA_CLASS_DATA_STRUCT =(2009)
#SPC_SIGINFO_STRUCT =(2130)
#CAT_NAMEVALUE_STRUCT =(2221)
#CAT_MEMBERINFO_STRUCT =(2222)
#SPC_UUID_LENGTH = 16
#WIN_CERT_REVISION_1_0 =($0100)
#WIN_CERT_REVISION_2_0 =($0200)
#WIN_CERT_TYPE_X509 =($0001)
#WIN_CERT_TYPE_PKCS_SIGNED_DATA =($0002)
#WIN_CERT_TYPE_RESERVED_1 =($0003)
#WIN_CERT_TYPE_TS_STACK_SIGNED =($0004)
#WT_TRUSTDBDIALOG_NO_UI_FLAG = $00000001
#WT_TRUSTDBDIALOG_ONLY_PUB_TAB_FLAG = $00000002
#WT_TRUSTDBDIALOG_WRITE_LEGACY_REG_FLAG = $00000100
#WT_TRUSTDBDIALOG_WRITE_IEAK_STORE_FLAG = $00000200

Structure WINTRUST_DATA
  cbStruct.l
  *pPolicyCallbackData
  *pSIPClientData
  dwUIChoice.l
  fdwRevocationChecks.l
  dwUnionChoice.l
  *pPointer
  dwStateAction.l
  hWVTStateData.l
  *pwszURLReference
  dwProvFlags.l
  dwUIContext.l
EndStructure

Structure WINTRUST_FILE_INFO
  cbStruct.l
  *pcwszFilePath
  hFile.l
  *pgKnownSubject
EndStructure

Structure WINTRUST_CATALOG_INFO
  cbStruct.l
  dwCatalogVersion.l
  *pcwszCatalogFilePath
  *pcwszMemberTag
  *pcwszMemberFilePath
  hMemberFile.l
EndStructure

Structure CATALOG_INFO
  cbStruct.l
  wszCatalogFile.b[520]
EndStructure

#WTD_CHOICE_FILE = 1
#WTD_CHOICE_CATALOG = 2
#WTD_UI_NONE = 2
#WTD_REVOKE_NONE = 0
#WTD_STATEACTION_IGNORE = 0
#WTD_STATEACTION_VERIFY = 1
#WTD_SAFER_FLAG = 256

CLIB=OpenLibrary(#PB_Any,"wintrust.dll")

Prototype     CryptCATAdminAcquireContext( *phCatAdmin, *pgSubsystem, dwFlags.l)
Prototype     CryptCATAdminAcquireContext2(*phCatAdmin, *pgSubsystem, c, d, dwFlags.l)
Prototype     CryptCATAdminReleaseContext(hCatAdmin.l, dwFlags.l)
Prototype     CryptCATAdminCalcHashFromFileHandle2(hCatAdmin.l, hFile.l, *pcbHash, *pbHash, dwFlags.l)  ;; update/fill in arg declaration for this one
Prototype     CryptCATAdminCalcHashFromFileHandle              (hFile.l, *pcbHash, *pbHash, dwFlags.l)
Prototype     CryptCATAdminEnumCatalogFromHash(hCatAdmin.l, *pbHash, cbHash.l, dwFlags.l, *phPrevCatInfo)
Prototype     CryptCATCatalogInfoFromContext(hCatInfo.l, *psCatInfo, dwFlags.l)
Prototype     CryptCATAdminReleaseCatalogContext(hCatAdmin.l, hCatInfo.l, dwFlags.l)
Prototype     WinVerifyTrust(HWND.l, *pgActionID, *pWVTData)

global CryptCATAdminAcquireContext.CryptCATAdminAcquireContext                   = GetFunction(CLIB,"CryptCATAdminAcquireContext")  
global CryptCATAdminReleaseContext.CryptCATAdminReleaseContext                   = GetFunction(CLIB,"CryptCATAdminReleaseContext")  
global CryptCATAdminAcquireContext2.CryptCATAdminAcquireContext2                 = GetFunction(CLIB,"CryptCATAdminAcquireContext2")  
global CryptCATAdminCalcHashFromFileHandle2.CryptCATAdminCalcHashFromFileHandle2 = GetFunction(CLIB,"CryptCATAdminCalcHashFromFileHandle2")  
global CryptCATAdminEnumCatalogFromHash.CryptCATAdminEnumCatalogFromHash         = GetFunction(CLIB,"CryptCATAdminEnumCatalogFromHash")  
global CryptCATCatalogInfoFromContext.CryptCATCatalogInfoFromContext             = GetFunction(CLIB,"CryptCATCatalogInfoFromContext")  
global CryptCATAdminReleaseCatalogContext.CryptCATAdminReleaseCatalogContext     = GetFunction(CLIB,"CryptCATAdminReleaseCatalogContext")  
global WinVerifyTrust.WinVerifyTrust                                             = GetFunction(CLIB,"WinVerifyTrust")

; debug WinVerifyTrust
; debug CryptCATAdminCalcHashFromFileHandle2
; debug CryptCATAdminAcquireContext2

; h  = CryptCATAdminAcquireContext2(@hCatAdmin,0, @"SHA256", 0,0)



Procedure CheckFileTrust(FilePath.s)
  Define bRet.l
  Define wd.WINTRUST_DATA
  Define wfi.WINTRUST_FILE_INFO
  Define wci.WINTRUST_CATALOG_INFO
  Define ci.CATALOG_INFO
  Define hCatAdmin.i
  Define bRet.l, hFile.l
  Define hr.l
  Define pszMemberTag.s
  Define dwCnt.l
  Dim byHash.b(99)
  Define dw.l
  Define hCatInfo.l
  
  ClearStructure(@wd, WINTRUST_DATA)
  ClearStructure(@wfi, WINTRUST_FILE_INFO)
  ClearStructure(@wci, WINTRUST_CATALOG_INFO)
  ClearStructure(@ci, CATALOG_INFO)
  
  bRet = #False
  hCatAdmin = #Null
  
  ;   If(Not(CryptCATAdminAcquireContext(@hCatAdmin, #Null, 0)))
  If Not(CryptCATAdminAcquireContext2(@hCatAdmin,0, @"SHA256", 0,0))
    debug "!!!!"
    ProcedureReturn #False
  EndIf
  
  ;********************
  ;Open file
  ;********************
  hFile = CreateFile_(@FilePath, #GENERIC_READ, #FILE_SHARE_READ, #Null, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, #Null)
  
  If (hFile = #INVALID_HANDLE_VALUE)
    Debug ("CheckFileTrust(): CreateFile FAILED, GetLastError = " + Hex(GetLastError_()))
    CryptCATAdminReleaseContext(hCatAdmin, 0)
    ;     
    ProcedureReturn #False
  EndIf
  
  dwCnt = 100
  ;   CryptCATAdminCalcHashFromFileHandle(hFile, @dwCnt, @byHash(), 0)
  CryptCATAdminCalcHashFromFileHandle2(hCatAdmin, hFile, @dwCnt, @byHash(), 0)
  
  
  ;********************
  ;Close file
  ;********************
  CloseHandle_(hFile)
  
  ;********************
  ;Compute member tag
  ;********************
  For dw = 0 To dwCnt - 1
    pszMemberTag + Right("0" + Hex(byHash(dw)), 2)
  Next
  
  ;   debug len(pszMemberTag)
  ;    pszMemberTag = "421FA7019E91CAA42F3B1FA1B2306B15A219FFAD4766C1DA701B28FF0F3172F9"
  
  Debug ("MemberTag = " + pszMemberTag)
  
  hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, @byHash(), dwCnt, 0, #Null)
  
  If (hCatInfo = #Null)
    Debug ("CheckFileTrust(): No CAT sig found -> verifying using embedded signature.")
    wd\cbStruct = SizeOf(wd)
    
    ; Use default code signing EKU.
    wd\pPolicyCallbackData = #Null
    
    ; No data to pass to SIP.
    wd\pSIPClientData = #Null
    
    ; Disable WVT UI.
    wd\dwUIChoice = #WTD_UI_NONE
    
    ; No revocation checking.
    wd\fdwRevocationChecks = #WTD_REVOKE_NONE
    
    ; Verify an embedded signature on a file.
    wd\dwUnionChoice = #WTD_CHOICE_FILE
    
    ; Default verification.
    wd\dwStateAction = #WTD_STATEACTION_IGNORE
    
    ; Not applicable for default verification of embedded signature.
    wd\hWVTStateData = #Null
    
    ; Not used.
    wd\pwszURLReference = #Null
    
    ; Default.
    wd\dwProvFlags = #WTD_SAFER_FLAG
    
    ; This is not applicable if there is no UI because it changes
    ; the UI to accommodate running applications instead of
    ; installing applications.
    wd\dwUIContext = #Null
    
    ; Set pFile.
    wfi\cbStruct = SizeOf(WINTRUST_FILE_INFO)
    wfi\pcwszFilePath = @FilePath
    wfi\hFile = #Null
    wfi\pgKnownSubject = #Null
    wd\pPointer = @wfi
  Else
    If(Not(CryptCATCatalogInfoFromContext(hCatInfo, @ci, 0)))
      Debug ("CheckFileTrust(): CryptCATCatalogInfoFromContext FAILED, GetLastError = " + Hex(GetLastError_()))
    EndIf
    wci\cbStruct = SizeOf(wci)
    wci\pcwszCatalogFilePath = @ci\wszCatalogFile[0]
    wci\pcwszMemberFilePath = @FilePath
    wci\pcwszMemberTag = @pszMemberTag
    
    wd\cbStruct = SizeOf(wd)
    wd\dwUnionChoice = #WTD_CHOICE_CATALOG
    wd\pPointer = @wci
    wd\dwUIChoice = #WTD_UI_NONE
    wd\fdwRevocationChecks = #WTD_REVOKE_NONE
    wd\dwStateAction = #WTD_STATEACTION_VERIFY
    wd\dwProvFlags = 0
    wd\hWVTStateData = #Null
    wd\pwszURLReference = #Null
  EndIf
  
  Define action.GUID
  
  ;********************
  ; WINTRUST_ACTION_GENERIC_VERIFY_V2 (Authenticode)
  ;********************
  With action
    \Data1 = $AAC56B
    \Data2 = $CD44
    \Data3 = $11D0
    \Data4[0] = $8C
    \Data4[1] = $C2
    \Data4[2] = $00
    \Data4[3] = $C0
    \Data4[4] = $4F
    \Data4[5] = $C2
    \Data4[6] = $95
    \Data4[7] = $EE
  EndWith
  
  hr = WinVerifyTrust(#INVALID_HANDLE_VALUE, @action, @wd)
  debug "hr: 0x" + hex(hr)
  If (hCatInfo <> #Null)
    CryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0)
  EndIf
  
  CryptCATAdminReleaseContext(hCatAdmin, 0)
  
  If (hr = 0)
    wd\dwStateAction = #WTD_STATEACTION_CLOSE
    WinVerifyTrust(#INVALID_HANDLE_VALUE, @action, @wd)
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
  
EndProcedure




Define.s szFile = "C:\Program Files\Internet Explorer\iexplore.exe"

debug ( szFile + " - " + CheckFileTrust(szFile))

Define.s szFile = "c:\windows\notepad.exe"

debug ( szFile + " - " + CheckFileTrust(szFile))

User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Re: Verifying PE Signatures - Revisited

Post by Keya »

as you've found out it's not exactly straightforward, so I found it easier (and quicker and surely more reliable) just to compile the C code from Microsoft's example into a lib and link the lib into my PB app, rather than trying to translate it. You've done a very good job with the translation though.

For the lib, just get rid of the tmain() function from the source code, then from your PB code simply call VerifyEmbeddedSignature(szFilename.s).
https://docs.microsoft.com/en-us/window ... -a-pe-file\

If you've never created a lib in Visual Studio before to use in PB i posted a simple tutorial: viewtopic.php?f=12&t=65549
Being able to compile libs from C code (and/or asm code) to call from your PB code opens up a whole new world of possibilities, it's definitely worth taking a little time to learn.
breeze4me
Enthusiast
Enthusiast
Posts: 527
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Verifying PE Signatures - Revisited

Post by breeze4me »

The following code works fine on Windows 10 x64 2004.

Code: Select all


;************************************************

; EnableExplicit

#WINTRUST_MAX_HEADER_BYTES_TO_MAP_DEFAULT = $00A00000
#WINTRUST_MAX_HASH_BYTES_TO_MAP_DEFAULT = $00100000
#WTD_UI_ALL = 1
#WTD_UI_NONE = 2
#WTD_UI_NOBAD = 3
#WTD_UI_NOGOOD = 4
#WTD_REVOKE_NONE = $00000000
#WTD_REVOKE_WHOLECHAIN = $00000001
#WTD_CHOICE_FILE = 1
#WTD_CHOICE_CATALOG = 2
#WTD_CHOICE_BLOB = 3
#WTD_CHOICE_SIGNER = 4
#WTD_CHOICE_CERT = 5
#WTD_STATEACTION_IGNORE = $00000000
#WTD_STATEACTION_VERIFY = $00000001
#WTD_STATEACTION_CLOSE = $00000002
#WTD_STATEACTION_AUTO_CACHE = $00000003
#WTD_STATEACTION_AUTO_CACHE_FLUSH = $00000004
#WTD_PROV_FLAGS_MASK = $0000FFFF
#WTD_USE_IE4_TRUST_FLAG = $00000001
#WTD_NO_IE4_CHAIN_FLAG = $00000002
#WTD_NO_POLICY_USAGE_FLAG = $00000004
#WTD_REVOCATION_CHECK_NONE = $00000010
#WTD_REVOCATION_CHECK_END_CERT = $00000020
#WTD_REVOCATION_CHECK_CHAIN = $00000040
#WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = $00000080
#WTD_SAFER_FLAG = $00000100
#WTD_HASH_ONLY_FLAG = $00000200
#WTD_USE_DEFAULT_OSVER_CHECK = $00000400
#WTD_LIFETIME_SIGNING_FLAG = $00000800
#WTD_CACHE_ONLY_URL_RETRIEVAL = $00001000
#WTD_UICONTEXT_EXECUTE = 0
#WTD_UICONTEXT_INSTALL = 1
#WTCI_DONT_OPEN_STORES = $00000001
#WTCI_OPEN_ONLY_ROOT = $00000002
#WTCI_USE_LOCAL_MACHINE = $00000004
#WTPF_TRUSTTEST = $00000020
#WTPF_TESTCANBEVALID = $00000080
#WTPF_IGNOREEXPIRATION = $00000100
#WTPF_IGNOREREVOKATION = $00000200
#WTPF_OFFLINEOK_IND = $00000400
#WTPF_OFFLINEOK_COM = $00000800
#WTPF_OFFLINEOKNBU_IND = $00001000
#WTPF_OFFLINEOKNBU_COM = $00002000
#WTPF_VERIFY_V1_OFF = $00010000
#WTPF_IGNOREREVOCATIONONTS = $00020000
#WTPF_ALLOWONLYPERTRUST = $00040000
#TRUSTERROR_STEP_WVTPARAMS = 0
#TRUSTERROR_STEP_FILEIO = 2
#TRUSTERROR_STEP_SIP = 3
#TRUSTERROR_STEP_SIPSUBJINFO = 5
#TRUSTERROR_STEP_CATALOGFILE = 6
#TRUSTERROR_STEP_CERTSTORE = 7
#TRUSTERROR_STEP_MESSAGE = 8
#TRUSTERROR_STEP_MSG_SIGNERCOUNT = 9
#TRUSTERROR_STEP_MSG_INNERCNTTYPE = 10
#TRUSTERROR_STEP_MSG_INNERCNT = 11
#TRUSTERROR_STEP_MSG_STORE = 12
#TRUSTERROR_STEP_MSG_SIGNERINFO = 13
#TRUSTERROR_STEP_MSG_SIGNERCERT = 14
#TRUSTERROR_STEP_MSG_CERTCHAIN = 15
#TRUSTERROR_STEP_MSG_COUNTERSIGINFO = 16
#TRUSTERROR_STEP_MSG_COUNTERSIGCERT = 17
#TRUSTERROR_STEP_VERIFY_MSGHASH = 18
#TRUSTERROR_STEP_VERIFY_MSGINDIRECTDATA = 19
#TRUSTERROR_STEP_FINAL_WVTINIT = 30
#TRUSTERROR_STEP_FINAL_INITPROV = 31
#TRUSTERROR_STEP_FINAL_OBJPROV = 32
#TRUSTERROR_STEP_FINAL_SIGPROV = 33
#TRUSTERROR_STEP_FINAL_CERTPROV = 34
#TRUSTERROR_STEP_FINAL_CERTCHKPROV = 35
#TRUSTERROR_STEP_FINAL_POLICYPROV = 36
#TRUSTERROR_STEP_FINAL_UIPROV = 37
#TRUSTERROR_MAX_STEPS = 38
#CPD_USE_NT5_CHAIN_FLAG = $80000000
#CPD_REVOCATION_CHECK_NONE = $00010000
#CPD_REVOCATION_CHECK_END_CERT = $00020000
#CPD_REVOCATION_CHECK_CHAIN = $00040000
#CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = $00080000
#CPD_UISTATE_MODE_PROMPT = $00000000
#CPD_UISTATE_MODE_BLOCK = $00000001
#CPD_UISTATE_MODE_ALLOW = $00000002
#CPD_UISTATE_MODE_MASK = $00000003
#CERT_CONFIDENCE_SIG = $10000000
#CERT_CONFIDENCE_TIME = $01000000
#CERT_CONFIDENCE_TIMENEST = $00100000
#CERT_CONFIDENCE_AUTHIDEXT = $00010000
#CERT_CONFIDENCE_HYGIENE = $00001000
#CERT_CONFIDENCE_HIGHEST = $11111000
#DWACTION_ALLOCANDFILL = 1
#DWACTION_FREE = 2
#szOID_TRUSTED_CODESIGNING_CA_LIST = "1.3.6.1.4.1.311.2.2.1"
#szOID_TRUSTED_CLIENT_AUTH_CA_LIST = "1.3.6.1.4.1.311.2.2.2"
#szOID_TRUSTED_SERVER_AUTH_CA_LIST = "1.3.6.1.4.1.311.2.2.3"
#SPC_TIME_STAMP_REQUEST_OBJID = "1.3.6.1.4.1.311.3.2.1"
#SPC_INDIRECT_DATA_OBJID = "1.3.6.1.4.1.311.2.1.4"
#SPC_SP_AGENCY_INFO_OBJID = "1.3.6.1.4.1.311.2.1.10"
#SPC_STATEMENT_TYPE_OBJID = "1.3.6.1.4.1.311.2.1.11"
#SPC_SP_OPUS_INFO_OBJID = "1.3.6.1.4.1.311.2.1.12"
#SPC_CERT_EXTENSIONS_OBJID = "1.3.6.1.4.1.311.2.1.14"
#SPC_PE_IMAGE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.15"
#SPC_RAW_FILE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.18"
#SPC_STRUCTURED_STORAGE_DATA_OBJID = "1.3.6.1.4.1.311.2.1.19"
#SPC_JAVA_CLASS_DATA_OBJID = "1.3.6.1.4.1.311.2.1.20"
#SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID = "1.3.6.1.4.1.311.2.1.21"
#SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID = "1.3.6.1.4.1.311.2.1.22"
#SPC_CAB_DATA_OBJID = "1.3.6.1.4.1.311.2.1.25"
#SPC_GLUE_RDN_OBJID = "1.3.6.1.4.1.311.2.1.25"
#SPC_MINIMAL_CRITERIA_OBJID = "1.3.6.1.4.1.311.2.1.26"
#SPC_FINANCIAL_CRITERIA_OBJID = "1.3.6.1.4.1.311.2.1.27"
#SPC_LINK_OBJID = "1.3.6.1.4.1.311.2.1.28"
#SPC_SIGINFO_OBJID = "1.3.6.1.4.1.311.2.1.30"
#SPC_PE_IMAGE_PAGE_HASHES_V1_OBJID = "1.3.6.1.4.1.311.2.3.1"
#SPC_PE_IMAGE_PAGE_HASHES_V2_OBJID = "1.3.6.1.4.1.311.2.3.2"
#CAT_NAMEVALUE_OBJID = "1.3.6.1.4.1.311.12.2.1"
#CAT_MEMBERINFO_OBJID = "1.3.6.1.4.1.311.12.2.2"
#SPC_SP_AGENCY_INFO_STRUCT =(2000)
#SPC_MINIMAL_CRITERIA_STRUCT =(2001)
#SPC_FINANCIAL_CRITERIA_STRUCT =(2002)
#SPC_INDIRECT_DATA_CONTENT_STRUCT =(2003)
#SPC_PE_IMAGE_DATA_STRUCT =(2004)
#SPC_LINK_STRUCT =(2005)
#SPC_STATEMENT_TYPE_STRUCT =(2006)
#SPC_SP_OPUS_INFO_STRUCT =(2007)
#SPC_CAB_DATA_STRUCT =(2008)
#SPC_JAVA_CLASS_DATA_STRUCT =(2009)
#SPC_SIGINFO_STRUCT =(2130)
#CAT_NAMEVALUE_STRUCT =(2221)
#CAT_MEMBERINFO_STRUCT =(2222)
#SPC_UUID_LENGTH = 16
#WIN_CERT_REVISION_1_0 =($0100)
#WIN_CERT_REVISION_2_0 =($0200)
#WIN_CERT_TYPE_X509 =($0001)
#WIN_CERT_TYPE_PKCS_SIGNED_DATA =($0002)
#WIN_CERT_TYPE_RESERVED_1 =($0003)
#WIN_CERT_TYPE_TS_STACK_SIGNED =($0004)
#WT_TRUSTDBDIALOG_NO_UI_FLAG = $00000001
#WT_TRUSTDBDIALOG_ONLY_PUB_TAB_FLAG = $00000002
#WT_TRUSTDBDIALOG_WRITE_LEGACY_REG_FLAG = $00000100
#WT_TRUSTDBDIALOG_WRITE_IEAK_STORE_FLAG = $00000200

Structure WINTRUST_DATA Align #PB_Structure_AlignC
  cbStruct.l
  *pPolicyCallbackData
  *pSIPClientData
  dwUIChoice.l
  fdwRevocationChecks.l
  dwUnionChoice.l
  *pPointer
  dwStateAction.l
  hWVTStateData.i
  *pwszURLReference
  dwProvFlags.l
  dwUIContext.l
  *pSignatureSettings
EndStructure

Structure WINTRUST_FILE_INFO Align #PB_Structure_AlignC
  cbStruct.l
  *pcwszFilePath
  hFile.i
  *pgKnownSubject
EndStructure

Structure WINTRUST_CATALOG_INFO Align #PB_Structure_AlignC
  cbStruct.l
  dwCatalogVersion.l
  *pcwszCatalogFilePath
  *pcwszMemberTag
  *pcwszMemberFilePath
  hMemberFile.i
  *pbCalculatedFileHash
  cbCalculatedFileHash.l
  *pcCatalogContext
  hCatAdmin.i
EndStructure

Structure CATALOG_INFO
  cbStruct.l
  wszCatalogFile.b[520]
EndStructure

#WTD_CHOICE_FILE = 1
#WTD_CHOICE_CATALOG = 2
#WTD_UI_NONE = 2
#WTD_REVOKE_NONE = 0
#WTD_STATEACTION_IGNORE = 0
#WTD_STATEACTION_VERIFY = 1
#WTD_SAFER_FLAG = 256

CLIB=OpenLibrary(#PB_Any,"wintrust.dll")

Prototype     CryptCATAdminAcquireContext( *phCatAdmin, *pgSubsystem, dwFlags.l)
Prototype     CryptCATAdminAcquireContext2(*phCatAdmin, *pgSubsystem, c, d, dwFlags.l)
Prototype     CryptCATAdminReleaseContext(hCatAdmin.l, dwFlags.l)
Prototype     CryptCATAdminCalcHashFromFileHandle2(hCatAdmin.l, hFile.l, *pcbHash, *pbHash, dwFlags.l)  ;; update/fill in arg declaration for this one
Prototype     CryptCATAdminCalcHashFromFileHandle              (hFile.l, *pcbHash, *pbHash, dwFlags.l)
Prototype     CryptCATAdminEnumCatalogFromHash(hCatAdmin.l, *pbHash, cbHash.l, dwFlags.l, *phPrevCatInfo)
Prototype     CryptCATCatalogInfoFromContext(hCatInfo.l, *psCatInfo, dwFlags.l)
Prototype     CryptCATAdminReleaseCatalogContext(hCatAdmin.l, hCatInfo.l, dwFlags.l)
Prototype     WinVerifyTrust(HWND.l, *pgActionID, *pWVTData)

Global CryptCATAdminAcquireContext.CryptCATAdminAcquireContext                   = GetFunction(CLIB,"CryptCATAdminAcquireContext")  
Global CryptCATAdminReleaseContext.CryptCATAdminReleaseContext                   = GetFunction(CLIB,"CryptCATAdminReleaseContext")  
Global CryptCATAdminAcquireContext2.CryptCATAdminAcquireContext2                 = GetFunction(CLIB,"CryptCATAdminAcquireContext2")  
Global CryptCATAdminCalcHashFromFileHandle2.CryptCATAdminCalcHashFromFileHandle2 = GetFunction(CLIB,"CryptCATAdminCalcHashFromFileHandle2")  
Global CryptCATAdminEnumCatalogFromHash.CryptCATAdminEnumCatalogFromHash         = GetFunction(CLIB,"CryptCATAdminEnumCatalogFromHash")  
Global CryptCATCatalogInfoFromContext.CryptCATCatalogInfoFromContext             = GetFunction(CLIB,"CryptCATCatalogInfoFromContext")  
Global CryptCATAdminReleaseCatalogContext.CryptCATAdminReleaseCatalogContext     = GetFunction(CLIB,"CryptCATAdminReleaseCatalogContext")  
Global WinVerifyTrust.WinVerifyTrust                                             = GetFunction(CLIB,"WinVerifyTrust")

; debug WinVerifyTrust
; debug CryptCATAdminCalcHashFromFileHandle2
; debug CryptCATAdminAcquireContext2

; h  = CryptCATAdminAcquireContext2(@hCatAdmin,0, @"SHA256", 0,0)



Procedure CheckFileTrust(FilePath.s)
  Define bRet.l
  Define wd.WINTRUST_DATA
  Define wfi.WINTRUST_FILE_INFO
  Define wci.WINTRUST_CATALOG_INFO
  Define ci.CATALOG_INFO
  Define hCatAdmin.i
  Define bRet.l, hFile.l
  Define hr.l
  Define pszMemberTag.s
  Define dwCnt.l
  Dim byHash.b(99)
  Define dw.l
  Define hCatInfo.l
  
  ClearStructure(@wd, WINTRUST_DATA)
  ClearStructure(@wfi, WINTRUST_FILE_INFO)
  ClearStructure(@wci, WINTRUST_CATALOG_INFO)
  ClearStructure(@ci, CATALOG_INFO)
  
  bRet = #False
  hCatAdmin = #Null
  
  ;   If(Not(CryptCATAdminAcquireContext(@hCatAdmin, #Null, 0)))
  If Not(CryptCATAdminAcquireContext2(@hCatAdmin,0, @"SHA256", 0,0))
    Debug "!!!!"
    ProcedureReturn #False
  EndIf
  
  ;********************
  ;Open file
  ;********************
  hFile = CreateFile_(@FilePath, #GENERIC_READ, #FILE_SHARE_READ, #Null, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, #Null)
  
  If (hFile = #INVALID_HANDLE_VALUE)
    Debug ("CheckFileTrust(): CreateFile FAILED, GetLastError = " + Hex(GetLastError_()))
    CryptCATAdminReleaseContext(hCatAdmin, 0)
    ;     
    ProcedureReturn #False
  EndIf
  
  dwCnt = 100
  ;   CryptCATAdminCalcHashFromFileHandle(hFile, @dwCnt, @byHash(), 0)
  CryptCATAdminCalcHashFromFileHandle2(hCatAdmin, hFile, @dwCnt, @byHash(), 0)
  
  
  ;********************
  ;Close file
  ;********************
  CloseHandle_(hFile)
  
  ;********************
  ;Compute member tag
  ;********************
  For dw = 0 To dwCnt - 1
    pszMemberTag + Right("0" + Hex(byHash(dw)), 2)
  Next
  
  ;   debug len(pszMemberTag)
  ;    pszMemberTag = "421FA7019E91CAA42F3B1FA1B2306B15A219FFAD4766C1DA701B28FF0F3172F9"
  
  Debug ("MemberTag = " + pszMemberTag)
  
  hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, @byHash(), dwCnt, 0, #Null)
  
  If (hCatInfo = #Null)
    Debug ("CheckFileTrust(): No CAT sig found -> verifying using embedded signature.")
    wd\cbStruct = SizeOf(wd)
    
    ; Use default code signing EKU.
    wd\pPolicyCallbackData = #Null
    
    ; No data to pass to SIP.
    wd\pSIPClientData = #Null
    
    ; Disable WVT UI.
    wd\dwUIChoice = #WTD_UI_NONE
    
    ; No revocation checking.
    wd\fdwRevocationChecks = #WTD_REVOKE_NONE
    
    ; Verify an embedded signature on a file.
    wd\dwUnionChoice = #WTD_CHOICE_FILE
    
    ; Default verification.
    wd\dwStateAction = #WTD_STATEACTION_IGNORE
    
    ; Not applicable for default verification of embedded signature.
    wd\hWVTStateData = #Null
    
    ; Not used.
    wd\pwszURLReference = #Null
    
    ; Default.
    wd\dwProvFlags = #WTD_SAFER_FLAG
    
    ; This is not applicable if there is no UI because it changes
    ; the UI to accommodate running applications instead of
    ; installing applications.
    wd\dwUIContext = #Null
    
    ; Set pFile.
    wfi\cbStruct = SizeOf(WINTRUST_FILE_INFO)
    wfi\pcwszFilePath = @FilePath
    wfi\hFile = #Null
    wfi\pgKnownSubject = #Null
    wd\pPointer = @wfi
  Else
    If(Not(CryptCATCatalogInfoFromContext(hCatInfo, @ci, 0)))
      Debug ("CheckFileTrust(): CryptCATCatalogInfoFromContext FAILED, GetLastError = " + Hex(GetLastError_()))
    EndIf
    wci\cbStruct = SizeOf(wci)
    wci\pcwszCatalogFilePath = @ci\wszCatalogFile[0]
    wci\pcwszMemberFilePath = @FilePath
    wci\pcwszMemberTag = @pszMemberTag
    
    wd\cbStruct = SizeOf(wd)
    wd\dwUnionChoice = #WTD_CHOICE_CATALOG
    wd\pPointer = @wci
    wd\dwUIChoice = #WTD_UI_NONE
    wd\fdwRevocationChecks = #WTD_REVOKE_NONE
    wd\dwStateAction = #WTD_STATEACTION_VERIFY
    wd\dwProvFlags = 0
    wd\hWVTStateData = #Null
    wd\pwszURLReference = #Null
  EndIf
  
  Define action.GUID
  
  ;********************
  ; WINTRUST_ACTION_GENERIC_VERIFY_V2 (Authenticode)
  ;********************
  With action
    \Data1 = $AAC56B
    \Data2 = $CD44
    \Data3 = $11D0
    \Data4[0] = $8C
    \Data4[1] = $C2
    \Data4[2] = $00
    \Data4[3] = $C0
    \Data4[4] = $4F
    \Data4[5] = $C2
    \Data4[6] = $95
    \Data4[7] = $EE
  EndWith
  
  hr = WinVerifyTrust(#INVALID_HANDLE_VALUE, @action, @wd)
  Debug "hr: 0x" + Hex(hr)
  If (hCatInfo <> #Null)
    CryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0)
  EndIf
  
  CryptCATAdminReleaseContext(hCatAdmin, 0)
  
  If (hr = 0)
    wd\dwStateAction = #WTD_STATEACTION_CLOSE
    WinVerifyTrust(#INVALID_HANDLE_VALUE, @action, @wd)
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
  
EndProcedure




Define.s szFile = "C:\Program Files\Internet Explorer\iexplore.exe"

Debug ( szFile + " - " + CheckFileTrust(szFile))

Define.s szFile = "c:\windows\notepad.exe"

Debug ( szFile + " - " + CheckFileTrust(szFile))

fluent
User
User
Posts: 68
Joined: Sun Jan 24, 2021 10:57 am

Re: Verifying PE Signatures - Revisited

Post by fluent »

Great, thanks for both replies!
Post Reply