SignReport, a Tool for Batch Verification of PE Signatures

Code signing is one of the most popular ways of confirming the integrity of software packages. This is made possible by the author of the PE (such as *exe, *.dll and so on) using a Sign tool to add their signature (a certificate) to the PE file. Checking the signature of PE files on the other hand can be done by using WinVerifyTrust function. This example demonstrates how WinVerifyTrust can be used. In this post I’ll share the slight changes needed to make WinVerifyTrust work with Qt Framework, along with a tool built with Qt Framework, that can be used to verify the signature of all PE files within a chosen folder.



Here is the modified version of the Microsoft Example that can be used with Qt Framework in order to check the signature of an executable, library and so on. This function takes a filename and provides a message (with an appropriate color) that describes the signature status of that file:

void verifySignature(const QString& sourceFile, QString& message)
{
    auto sourceFileStr = sourceFile.toStdWString();

    LONG lStatus;
    DWORD dwLastError;

    WINTRUST_FILE_INFO FileData;
    memset(&FileData, 0, sizeof(FileData));
    FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
    FileData.pcwszFilePath = sourceFileStr.c_str();
    FileData.hFile = Q_NULLPTR;
    FileData.pgKnownSubject = Q_NULLPTR;

    GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
    WINTRUST_DATA WinTrustData;

    memset(&WinTrustData, 0, sizeof(WinTrustData));

    WinTrustData.cbStruct = sizeof(WinTrustData);

    WinTrustData.pPolicyCallbackData = Q_NULLPTR;

    WinTrustData.pSIPClientData = Q_NULLPTR;

    WinTrustData.dwUIChoice = WTD_UI_NONE;

    WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;

    WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;

    WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY;

    WinTrustData.hWVTStateData = Q_NULLPTR;

    WinTrustData.pwszURLReference = Q_NULLPTR;

    WinTrustData.dwUIContext = 0;

    WinTrustData.pFile = &FileData;

    lStatus = WinVerifyTrust(
                Q_NULLPTR,
                &WVTPolicyGUID,
                &WinTrustData);

    switch (lStatus)
    {
    case ERROR_SUCCESS:
        message = "The file is signed and the signature was verified.";
        break;

    case TRUST_E_NOSIGNATURE:
        dwLastError = GetLastError();
        if (TRUST_E_NOSIGNATURE == dwLastError ||
                TRUST_E_SUBJECT_FORM_UNKNOWN == dwLastError ||
                TRUST_E_PROVIDER_UNKNOWN == dwLastError)
        {
            message = R"(<span style="color:#ff0000;">The file is not signed.</span>)";
        }
        else
        {
            message = R"(<span style="color:#ff5500;">An unknown error occurred trying to verify the signature of the file.</span>)";
        }

        break;

    case TRUST_E_EXPLICIT_DISTRUST:
        message = R"(<span style="color:#ff5500;">The signature is present, but specifically disallowed.</span>)";
        break;

    case TRUST_E_SUBJECT_NOT_TRUSTED:
        message = R"(<span style="color:#ff5500;">The signature is present, but not trusted.</span>)";
        break;

    case CRYPT_E_SECURITY_SETTINGS:
        message = R"(<span style="color:#ff5500;">CRYPT_E_SECURITY_SETTINGS - The hash representing the subject or the publisher wasn't explicitly trusted by the admin and admin policy has disabled user trust. No signature, publisher or timestamp errors.</span>)";
        break;

    default:
        message = QString(R"(Error is: 0x%1.)").arg(QString::number(lStatus, 16));
        break;
    }

    WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;

    lStatus = WinVerifyTrust(
                Q_NULLPTR,
                &WVTPolicyGUID,
                &WinTrustData);
}

In order for the preceding code to work, you must add the following into your project’s *.pro file:

LIBS += -lwintrust


You can use the following link to download a fully functional reporting tool, called SignReport that can be used to batch verify the signatures of PE files. This tool is built by using the function shared in this post.

SignReport 1.0.0 Setup.exe


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.