You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows 8/10/11平台下如何在程序启动时校验自身EXE代码签名?

Windows 8/10/11程序自签名证书验证实现(WinAPI示例)

以下是直接用WinAPI实现程序启动时自验证签名证书的代码示例,完全覆盖你要求的四个逻辑步骤:

#include <Windows.h>
#include <Wintrust.h>
#include <Cryptography.h>
#include <iostream>

#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "Wintrust.lib")

// 验证当前程序签名证书的核心函数
BOOL VerifySelfCertificate()
{
    WCHAR szExePath[MAX_PATH] = {0};
    // 1. 获取当前运行EXE的完整路径
    if (!GetModuleFileNameW(NULL, szExePath, MAX_PATH))
    {
        std::wcerr << L"获取程序路径失败,错误码: " << GetLastError() << std::endl;
        return FALSE;
    }

    // 2. 验证签名有效性及证书存在性
    WINTRUST_FILE_INFO fileInfo = {0};
    fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
    fileInfo.pcwszFilePath = szExePath;
    fileInfo.hFile = NULL;
    fileInfo.pgKnownSubject = NULL;

    WINTRUST_DATA trustData = {0};
    trustData.cbStruct = sizeof(WINTRUST_DATA);
    trustData.dwUIChoice = WTD_UI_NONE; // 不显示UI,后台验证
    trustData.fdwRevocationChecks = WTD_REVOKE_NONE; // 根据需求选择是否检查吊销
    trustData.dwUnionChoice = WTD_CHOICE_FILE;
    trustData.pFile = &fileInfo;
    trustData.dwStateAction = WTD_STATEACTION_VERIFY;
    trustData.hWVTStateData = NULL;
    trustData.pwszURLReference = NULL;
    trustData.dwProvFlags = WTD_REVOCATION_CHECK_NONE | WTD_CACHE_ONLY_URL_RETRIEVAL;

    GUID guidAction = WINTRUST_ACTION_GENERIC_VERIFY_V2;
    LONG lStatus = WinVerifyTrust(NULL, &guidAction, &trustData);
    if (lStatus != ERROR_SUCCESS)
    {
        std::wcerr << L"证书无效或未签名,错误码: " << lStatus << std::endl;
        return FALSE;
    }

    // 3. 从EXE中提取证书上下文
    HCRYPTPROV hProv = NULL;
    HCRYPTMSG hMsg = NULL;
    PCCERT_CONTEXT pCertContext = NULL;
    DWORD dwEncoding = 0;
    DWORD dwContentType = 0;
    DWORD dwFormatType = 0;

    if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE, szExePath, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding, &dwContentType, &dwFormatType, &hProv, &hMsg, (const void**)&pCertContext))
    {
        std::wcerr << L"提取证书失败,错误码: " << GetLastError() << std::endl;
        WinVerifyTrust(NULL, &guidAction, &trustData); // 清理验证状态
        return FALSE;
    }

    // 4. 获取证书所有者名称并验证是否为"John Doe"
    WCHAR szSubjectName[256] = {0};
    if (!CertGetNameStringW(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, szSubjectName, ARRAYSIZE(szSubjectName)))
    {
        std::wcerr << L"获取证书所有者名称失败,错误码: " << GetLastError() << std::endl;
        CertFreeCertificateContext(pCertContext);
        CryptMsgClose(hMsg);
        CryptReleaseContext(hProv, 0);
        WinVerifyTrust(NULL, &guidAction, &trustData);
        return FALSE;
    }

    if (_wcsicmp(szSubjectName, L"John Doe") != 0)
    {
        std::wcerr << L"证书所有者不符,当前所有者: " << szSubjectName << std::endl;
        CertFreeCertificateContext(pCertContext);
        CryptMsgClose(hMsg);
        CryptReleaseContext(hProv, 0);
        WinVerifyTrust(NULL, &guidAction, &trustData);
        return FALSE;
    }

    // 资源清理
    CertFreeCertificateContext(pCertContext);
    CryptMsgClose(hMsg);
    CryptReleaseContext(hProv, 0);
    WinVerifyTrust(NULL, &guidAction, &trustData); // 结束验证状态

    return TRUE;
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    if (!VerifySelfCertificate())
    {
        // 验证失败,退出程序
        return 1;
    }

    // 验证通过,执行程序主逻辑
    MessageBoxW(NULL, L"证书验证通过,程序启动成功!", L"提示", MB_OK);
    return 0;
}

关键说明:

  • 证书存在性与有效性验证:通过WinVerifyTrust函数完成,不仅检查是否存在签名,还会验证证书链的有效性、有效期等(可通过dwProvFlags调整验证策略)。
  • 证书提取:使用CryptQueryObject从EXE文件中直接提取嵌入的证书上下文。
  • 所有者名称匹配:通过CertGetNameString获取证书的简易显示名称,使用_wcsicmp进行不区分大小写的对比。
  • 资源清理:所有WinAPI获取的句柄和上下文都需手动释放,避免内存泄漏。
  • 编译依赖:需链接Crypt32.lib和Wintrust.lib,代码中已通过#pragma comment声明。

注意事项:

  • 若需要严格检查证书吊销状态,可将fdwRevocationChecks设为WTD_REVOKE_WHOLECHAIN,但需确保程序能访问网络。
  • 此代码仅适用于Windows 8及以上系统,API兼容性满足需求。

内容的提问来源于stack exchange,提问作者Peter Furz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 12:30:31