개발/WIN32-MFC

[ WIN ] 코드사인 (WinTrust API)검증

-=HaeJuK=- 2024. 4. 22. 16:27

ChatGpt 4o AI 가 만든 WinTrust 이미지


WinTrust API는 Windows 운영 체제에서 디지털 서명을 검증하고 파일 및 기타 객체의 신뢰성을 확인하는 데 사용됩니다. 이를 이해하기 쉽게 다이어그램으로 나타내 보겠습니다.
다음은 WinTrust API의 주요 구성 요소와 흐름을 설명하는 다이어그램입니다.

  1. 요청자(Requestor): 신뢰성을 확인하고자 하는 애플리케이션 또는 서비스.
  2. WinTrust API: 요청을 받아 디지털 서명을 검증하고 신뢰성을 평가하는 API.
  3. 정책(Policy): 신뢰성 확인에 사용되는 기준 및 규칙 집합.
  4. 신뢰 공급자(Trust Provider): 인증서와 서명을 검증하는 역할을 하는 엔티티.
  5. 결과(Result): 파일 또는 객체의 신뢰성에 대한 검증 결과.

[ 요청자 ] --> [ WinTrust API ] --> [ 정책 ]
                                |
                                v
                      [ 신뢰 공급자 ]
                                |
                               v
                            [ 결과 ]

  1. 요청자:
    • 애플리케이션이 WinTrust API에 파일 또는 객체의 신뢰성 검증을 요청합니다.
  2. WinTrust API:
    • 요청을 수신하고 검증 프로세스를 시작합니다.
  3. 정책:
    • API는 지정된 정책을 사용하여 파일 또는 객체의 디지털 서명을 검토합니다.
  4. 신뢰 공급자:
    • API는 신뢰 공급자를 호출하여 서명 및 인증서를 검증합니다.
  5. 결과:
    • 검증 결과를 요청자에게 반환합니다(성공, 실패, 경고 등).

 

다음은 Windows OS에서 코드 서명 검증을 하는 CODE(C/C++) 입니다. 

#pragma once

#include <windows.h>
#include <wintrust.h>
#include <softpub.h>
#include <wincrypt.h>
#include <iostream>
#pragma comment(lib,"wintrust")

class cVerifyCodeSign
{
    DECLARE_NO_SELF_CLASS( nxcVerifyCodeSign );

public:
    static bool IsVeirfyCodeSigned( const std::wstring& _ssFilePathName ) 
    {
        WINTRUST_FILE_INFO FileData;
        memset( &FileData, 0, sizeof( FileData ) );
        FileData.cbStruct = sizeof( WINTRUST_FILE_INFO );
        FileData.pcwszFilePath = _ssFilePathName.c_str();

        GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
        WINTRUST_DATA WinTrustData;

        memset( &WinTrustData, 0, sizeof( WinTrustData ) );
        WinTrustData.cbStruct = sizeof( WinTrustData );
        WinTrustData.pPolicyCallbackData = NULL;
        WinTrustData.pSIPClientData = NULL;
        WinTrustData.dwUIChoice = WTD_UI_NONE;
        WinTrustData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;  // 체인 전체의 폐지 상태를 검사합니다.
        WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
        WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
        WinTrustData.hWVTStateData = NULL;
        WinTrustData.pwszURLReference = NULL;
        WinTrustData.dwProvFlags = WTD_SAFER_FLAG | WTD_USE_DEFAULT_OSVER_CHECK; // OS 버전 체크를 기본 설정으로 사용합니다.
        WinTrustData.dwUIContext = WTD_UICONTEXT_EXECUTE;
        WinTrustData.pFile = &FileData;

        LONG status = WinVerifyTrust( NULL, &WVTPolicyGUID, &WinTrustData );
        WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;

        WinVerifyTrust( NULL, &WVTPolicyGUID, &WinTrustData );

        return status == ERROR_SUCCESS;
    }

    static std::wstring GetSignerName( const std::wstring& _ssFilePathName )
    {
        HCERTSTORE hStore = NULL;
        HCRYPTMSG hMsg = NULL;
        PCCERT_CONTEXT pCertContext = NULL;
        std::wstring ssSignerNameW = L"Unknown";

        DWORD dwEncoding= 0x00, dwContentType = 0x00, dwFormatType = 0x00;
        if( !CryptQueryObject( CERT_QUERY_OBJECT_FILE, _ssFilePathName.c_str(), CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0,
            &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, (const void**) & pCertContext) )
        {
            return ssSignerNameW;
        }

        DWORD dwSignerInfo;
        PCMSG_SIGNER_INFO pSignerInfo;
        if( !CryptMsgGetParam( hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo ) ) 
        {
            CryptMsgClose( hMsg );
            CertCloseStore( hStore, 0 );
            return ssSignerNameW;
        }

        pSignerInfo = (PCMSG_SIGNER_INFO)malloc( dwSignerInfo );
        if( !CryptMsgGetParam( hMsg, CMSG_SIGNER_INFO_PARAM, 0, pSignerInfo, &dwSignerInfo ) ) 
        {
            free( pSignerInfo );
            CryptMsgClose( hMsg );
            CertCloseStore( hStore, 0 );
            return ssSignerNameW;
        }

        CERT_INFO CertInfo;
        CertInfo.Issuer = pSignerInfo->Issuer;
        CertInfo.SerialNumber = pSignerInfo->SerialNumber;
        pCertContext = CertFindCertificateInStore( hStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, &CertInfo, NULL );
        if( pCertContext )
        {
            DWORD dwData;
            dwData = CertGetNameStringW( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0 );
            wchar_t* nameBuffer = new wchar_t[dwData];
            if( CertGetNameStringW( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, nameBuffer, dwData ) ) {
                ssSignerNameW = nameBuffer;
            }
            delete[] nameBuffer;
        }

        free( pSignerInfo );
        CryptMsgClose( hMsg );
        CertCloseStore( hStore, 0 );
        if( pCertContext ) 
        {
            CertFreeCertificateContext( pCertContext );
        }

        return ssSignerNameW;
    }
};

 

사용 방법 입니다. 

int Test() 
{
    std::wstring path = L"C:\\Path\\To\\YourSignedFile.exe";
    if( cVerifyCodeSign::IsVeirfyCodeSigned( path ) ) {
        std::wcout << L"The file is digitally signed." << std::endl;
        std::wstring signerName = cVerifyCodeSign::GetSignerName( path );
        std::wcout << L"Signer: " << signerName << std::endl;
    }
    else
    {
        std::wcout << L"The file is not digitally signed or the signature could not be verified." << std::endl;
    }
    return 0;
}​
반응형