【Windows】使用 WMI 获取系统版本信息

获取系统版本信息

通过 GetVersionEx 获取系统版本的方法可能不适用于所有情况,而且将要过时(被废弃)。下面介绍一种通过 WMI 查询并根据版本号进行划分的系统版本解析工具,其他方法还有通过注册表和通过文件属性等等。内部版本号表可以通过官方渠道获取,例如:
Windows 10 更新历史记录
Windows 11 更新历史记录

代码

sysinfo.h

#pragma once
#include <string>
#include <iostream>
#include <windows.h>
#include <iphlpapi.h>
#include <comdef.h>
#include <Wbemidl.h>
#include <math.h>

class SysInfo
{
public:
    SysInfo();
    virtual ~SysInfo();

    bool init_wmi();
    void uninit_wmi();


    double get_memory_size();
    std::string get_os_name();
    std::string get_host_name();
    int get_file_flag(std::string file_name);
    std::string get_area(std::string ip);
    std::string wstring_to_string(wchar_t* data);


protected:
private:
    bool m_init_wmi = false;

    IWbemServices* pSvc = NULL;
    IWbemLocator* pLoc = NULL;

    HRESULT hres = NULL;
};

SysInfo.cpp

#include "SysInfo.h"

#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "iphlpapi.lib")

#define  GBYTES  1073741824
#define  MBYTES  1048576
#define  KBYTES  1024
#define  DKBYTES 1024.0

SysInfo::SysInfo()
{
    m_init_wmi = init_wmi();
}

SysInfo::~SysInfo()
{
    uninit_wmi();
}

bool SysInfo::init_wmi()
{

    hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        return false;
    }

    hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    if (FAILED(hres))
    {
        CoUninitialize();
        return false;
    }


    hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
    if (FAILED(hres))
    {
        CoUninitialize();
        return false;
    }


    hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
    if (FAILED(hres))
    {
        pLoc->Release();
        CoUninitialize();
        return false;
    }

    hres = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
    if (FAILED(hres))
    {
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return false;
    }
    return true;
}

void SysInfo::uninit_wmi()
{

    pSvc->Release();
    pLoc->Release();
    CoUninitialize();
}


//Win32_PhysicalMemory

double SysInfo::get_memory_size()
{

    double mem_size = 0;

    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_PhysicalMemory")
        , WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
    if (FAILED(hres))
    {
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return -1;
    }

    IWbemClassObject* pclsObj = NULL;
    ULONG uReturn = 0;
    while (pEnumerator)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
        if (0 == uReturn)
        {
            break;
        }

        VARIANT vtProp = { 0 };
        VariantInit(&vtProp);// 标准初始化
        hr = pclsObj->Get(L"Capacity", 0, &vtProp, 0, 0);



        std::string data = wstring_to_string(vtProp.bstrVal);

        mem_size += ::atof(data.c_str());
        VariantClear(&vtProp);
        pclsObj->Release();
    }
    pEnumerator->Release();

    double mem_total = mem_size / 1024 / 1024 / 1024;

    return floor(mem_total * 100) / 100;
}



std::string SysInfo::get_os_name()
{
    std::string res_data;
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM win32_operatingsystem")
        , WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
    if (FAILED(hres))
    {
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return res_data;
    }

    IWbemClassObject* pclsObj = NULL;
    ULONG uReturn = 0;
    while (pEnumerator)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
        if (0 == uReturn)
        {
            break;
        }

        VARIANT vtProp = { 0 };
        VariantInit(&vtProp);// 标准初始化
        hr = pclsObj->Get(L"name", 0, &vtProp, 0, 0);
        std::string data = wstring_to_string(vtProp.bstrVal);
        data = data.substr(0, data.find('|'));

        hr = pclsObj->Get(L"Version", 0, &vtProp, 0, 0);
        res_data = wstring_to_string(vtProp.bstrVal);
        std::string restp = res_data;
        std::string temp = "[";
        temp += res_data;
        temp += "] ";
        temp += data;
        res_data = temp;

        // 分割string字符串
        int pos1 = 0, pos2 = 0;
        std::string pattern = ".";
        restp += pattern;
        std::string s[3];
        for (int i = 0; i < 3; i++) {
            pos2 = (int)restp.find(pattern, pos1);
            s[i] = restp.substr(pos1, 
                static_cast<std::basic_string<char, std::char_traits<char>, 
                std::allocator<char>>::size_type>(pos2) - pos1);
            pos1 = pos2 + 1;
        }
        //for (int i = 0; i < 3; i++) {
            //std::cout << s[i] << std::endl;
        //}
        /*
        size_t size = s[0].length() + 1;
        char* MajorVer = (char*)malloc(sizeof(char) * size);
        if (MajorVer != NULL) strcpy_s(MajorVer, size, s[0].c_str());

        size = s[1].length() + 1;
        char* MinorVer = (char*)malloc(sizeof(char) * size);
        if (MinorVer != NULL) strcpy_s(MinorVer, size, s[1].c_str());

        size = s[2].length() + 1;
        char* BuildVer = (char*)malloc(sizeof(char) * size);
        if (BuildVer != NULL) strcpy_s(BuildVer, size, s[2].c_str());
        */

        int MajorVer = 0, MinorVer = 0, BuildVer = 0, L;
        L = sscanf_s(s[0].c_str(), "%d", &MajorVer);
        L = sscanf_s(s[1].c_str(), "%d", &MinorVer);
        L = sscanf_s(s[2].c_str(), "%d", &BuildVer);

        printf("大版本号:%d, 小版本号:%d, 内部版本号:%d\n", MajorVer, MinorVer, BuildVer);

        printf("显式版本: ");
        if (BuildVer >= 22621) printf("Windows 11 22H2 Or Greater\n");
        else if (BuildVer >= 22000) printf("Windows 11 21H2\n");
        else if (BuildVer == 20348) printf("Windows Server 2022\n");
        else if (BuildVer >= 19045) printf("Windows 10 22H2\n");
        else if (BuildVer >= 19044) printf("Windows 10 21H2\n");
        else if (BuildVer >= 19043) printf("Windows 10 21H1\n");
        else if (BuildVer >= 19042) printf("Windows 10 20H2\n");
        else if (BuildVer >= 19041) printf("Windows 10 2004\n");
        else if (BuildVer >= 18363) printf("Windows 10 1909\n");
        else if (BuildVer >= 18362) printf("Windows 10 1903\n");
        else if (BuildVer >= 17763) printf("Windows 10 1809\n");
        else if (BuildVer >= 17134) printf("Windows 10 1803\n");
        else if (BuildVer >= 16299) printf("Windows 10 1709\n");
        else if (BuildVer >= 15063) printf("Windows 10 1703\n");
        else if (BuildVer >= 14393) printf("Windows 10 1607\n");
        else if (BuildVer >= 10586) printf("Windows 10 1511\n");
        else if (BuildVer >= 10240) printf("Windows 10 1507\n");
        // 以下数据属于网络收集,不一定准确,数据已经不可考究
        else if (BuildVer >= 9200)
        {// 6.2->win 8; 6.3->win 8.1
            if (MinorVer == 2) printf("Windows 8 Release\n");
            else if (MinorVer == 3) printf("Windows 8.1 Release\n");
        }
        else if (BuildVer >= 7601) printf("Windows 7 Service Pack 1\n");
        else if (BuildVer >= 7600) printf("Windows 7 Release\n");
        else if (BuildVer >= 6002) printf("Windows Vista SP2\n");
        else if (BuildVer >= 6001) printf("Windows Vista SP1\n");
        else if (BuildVer >= 6000) printf("Windows Vista\n");
        else if (BuildVer >= 3790) printf("Windows XP Professional x64 Edition\n");
        else if (BuildVer == 3000) printf("Windows Me");// 版本特殊?
        else if (BuildVer >= 2600) printf("Windows XP\n");// 存在特殊版本
        else if (BuildVer == 2222) printf("Windows 98 Second Edition\n");// 版本特殊?
        else if (BuildVer >= 2195) printf("Windows 2000 Professional\n");
        else if (BuildVer >= 1998) printf("Windows 98\n");
        else if (BuildVer >= 1381) printf("Windows NT Workstation 4.0\n");
        else if (BuildVer >= 1057) printf("Windows NT Workstation 3.51\n");// 版本特殊?
        else if (BuildVer >= 950) printf("Windows 95\n");
        else if (BuildVer >= 807) printf("Windows NT Workstation 3.5\n");
        else if (BuildVer >= 528) printf("Windows NT 3.1\n");
        else printf("版本特殊或者为远古版本!\n");



        // 释放
        //free(MajorVer);
        //free(MinorVer);
        //free(BuildVer);
        VariantClear(&vtProp);
        pclsObj->Release();
    }
    pEnumerator->Release();

    return res_data;

}




std::string SysInfo::get_host_name()
{
    std::string host_name;

    char buf[MAX_PATH] = { 0 };
    DWORD length = MAX_PATH;
    if (::GetComputerNameA(buf, &length)) {
        host_name = buf;
    }
    return host_name;
}


int SysInfo::get_file_flag(std::string file_name)
{
    return 0;
}

std::string SysInfo::get_area(std::string ip)
{
    std::string area;

    return area;
}

std::string SysInfo::wstring_to_string(wchar_t* data)
{
    std::string res_data;
    int iSize;
    // 宽字符串转换
    iSize = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
    char* pCapacity = (char*)malloc(iSize * sizeof(char));
    if (pCapacity == NULL) return res_data;
    pCapacity[0] = 0;
    WideCharToMultiByte(CP_ACP, 0, data, -1, pCapacity, iSize, NULL, NULL);
    res_data = pCapacity;
    free(pCapacity);
    return res_data;
}

mian.cpp

#include "SysInfo.h"

int main()
{

	SysInfo Info;
	Info.init_wmi();
	printf("%s\n", Info.get_os_name().c_str());
	//Info.uninit_wmi();
	system("pause");
	return 0;
}

效果如图所示:
在这里插入图片描述
代码是很早之前写的,用的话需要自己优化一下。

更新版本
参考:https://blog.csdn.net/magictong/article/details/40753519,修复了 PE 开启了兼容模式时 RtlGetVersion 获取到错误的版本号的问题。
下面贴一张作者文章的原图:
兼容模式下各版本号API工作效果对比

#pragma once
#include <Windows.h>

#define _LIBLIANYOU_OSVERSION_INVALID 0xffffffff

typedef LONG NTSTATUS, * PNTSTATUS;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS (0x00000000)
#endif

#ifndef DISPLAY_VERSION_VALUE
#define DISPLAY_VERSION_VALUE     L"DisplayVersion"
#endif

typedef NTSTATUS(WINAPI* __LYRtlGetVersion)(PRTL_OSVERSIONINFOW);

typedef VOID(NTAPI* __LYRtlGetNtVersionNumbers)(
    _Out_opt_ PULONG NtMajorVersion,
    _Out_opt_ PULONG NtMinorVersion,
    _Out_opt_ PULONG NtBuildNumber);

// https://stackoverflow.com/questions/36543301/detecting-windows-10-version/36543774#36543774
// https://blog.csdn.net/magictong/article/details/40753519
inline BOOL LYGetOSVersion(PRTL_OSVERSIONINFOW lpRovi, BOOL bRedirection = false)
{
    HMODULE hMod = GetModuleHandleW(L"ntdll.dll");
    if (hMod != nullptr)
    {
        __LYRtlGetVersion myRtlGetVersion = nullptr;
        __LYRtlGetNtVersionNumbers myRtlGetNtVersionNumbers =
            (__LYRtlGetNtVersionNumbers)GetProcAddress(
                hMod,
                "RtlGetNtVersionNumbers"
            );

        if (bRedirection) {  // 是否遵循兼容模式的 API 重定向
            myRtlGetVersion = (__LYRtlGetVersion)GetProcAddress(
                hMod,
                "RtlGetVersion"
            );

            if (myRtlGetVersion != nullptr)
            {
                lpRovi->dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
                if (STATUS_SUCCESS == myRtlGetVersion(lpRovi))
                {
                    return TRUE;
                }
                else {
                    return FALSE;
                }
            }
        }

        if (myRtlGetNtVersionNumbers != nullptr 
            && (!bRedirection || myRtlGetVersion == nullptr))
        {
            lpRovi->dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
            ULONG NtMajorVersion = 0;
            ULONG NtMinorVersion = 0;
            ULONG NtBuildNumber = 0;
            myRtlGetNtVersionNumbers(&NtMajorVersion, &NtMinorVersion, &NtBuildNumber);

            NtBuildNumber &= 0x0ffff;

            lpRovi->dwMajorVersion = NtMajorVersion;
            lpRovi->dwMinorVersion = NtMinorVersion;
            lpRovi->dwBuildNumber = NtBuildNumber;
            return TRUE;
        }
    }
    return FALSE;
}

// https://stackoverflow.com/questions/47926094/detecting-windows-10-os-build-minor-version
inline BOOL LYGetDisplayVersion(std::wstring& lpszOSDisplayVersion)
{
    HKEY hKey;
    LRESULT lRes = RegOpenKeyExW(
        HKEY_LOCAL_MACHINE,
        wcschr(
            wcschr(
                wcschr(
                    UNIFIEDBUILDREVISION_KEY,
                    '\\'
                ) + 1,
                '\\'
            ) + 1,
            '\\'
        ) + 1,
        0,
        KEY_READ,
        &hKey
    );
    if (lRes == ERROR_SUCCESS)
    {
        DWORD dwType = 0;
        DWORD dwSize = 0;

        // 第一次调用:获取所需缓冲区大小
        LONG lResult = RegQueryValueExW(
            hKey, 
            DISPLAY_VERSION_VALUE, 
            nullptr, 
            &dwType, 
            nullptr, 
            &dwSize);
        if (lResult != ERROR_SUCCESS || 
            (dwType != REG_SZ 
                && dwType != REG_EXPAND_SZ)) {
            return false; // 读取失败或类型不匹配
        }

        // 分配缓冲区(以 WCHAR 为单位),包括空字符
        std::vector<wchar_t> buffer(dwSize / sizeof(wchar_t));

        // 第二次调用:读取实际的字符串值
        lResult = RegQueryValueExW(hKey,
            DISPLAY_VERSION_VALUE, 
            nullptr, 
            nullptr,
            reinterpret_cast<LPBYTE>(buffer.data()),
            &dwSize);
        if (lResult != ERROR_SUCCESS) {
            return false; // 读取失败
        }

        // 将缓冲区转换为 std::wstring,确保字符串以空字符结尾
        lpszOSDisplayVersion.assign(buffer.data());

        return true;
    }
    return false;
}

inline DWORD32 LYGetUBR(void)
{
    DWORD32 ubr = 0, ubr_size = sizeof(DWORD32);
    HKEY hKey;
    LRESULT lRes = RegOpenKeyExW(
        HKEY_LOCAL_MACHINE,
        wcschr(
            wcschr(
                wcschr(
                    UNIFIEDBUILDREVISION_KEY,
                    '\\'
                ) + 1,
                '\\'
            ) + 1,
            '\\'
        ) + 1,
        0,
        KEY_READ,
        &hKey
    );
    if (lRes == ERROR_SUCCESS)
    {
        RegQueryValueExW(
            hKey,
            UNIFIEDBUILDREVISION_VALUE,
            0,
            NULL,
            (LPBYTE)&ubr,
            (LPDWORD)&ubr_size
        );
    }
    return ubr;
}

inline DWORD32 LYGetOSVersionAndUBR(PRTL_OSVERSIONINFOW lpRovi)
{
    if (!LYGetOSVersion(lpRovi))
    {
        return _LIBLIANYOU_OSVERSION_INVALID;
    }
    return LYGetUBR();
}

// 函数:格式化版本号
std::wstring LYFormatVersionString(const RTL_OSVERSIONINFOW& osvi, DWORD32 UBR) {
    std::wstringstream versionStream;
    versionStream << osvi.dwMajorVersion << L"."
        << osvi.dwMinorVersion << L"."
        << osvi.dwBuildNumber << L"."
        << UBR;
    return versionStream.str();
}

std::wstring LYFormatVersionString2(const RTL_OSVERSIONINFOW& osvi, std::wstring szOSDisplayVersion) {
    std::wstringstream versionStream;

    if (osvi.dwBuildNumber < 7600) {  // win7 以前
        versionStream << L"版本过低(Vista 或更早)";
    }
    else if(osvi.dwBuildNumber >= 7600
        && osvi.dwBuildNumber < 9200) {  // win7 
        versionStream << L"Windows 7 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber >= 9200
        && osvi.dwBuildNumber < 10240) {  // win8
        versionStream << L"Windows 8 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber >= 10240
        && osvi.dwBuildNumber < 19042) {  // win10 20H2 之前版本
        versionStream << L"Windows 10 低于 20H2 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber == 19042) {  // win10 20H2
        versionStream << L"Windows 10 20H2 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber == 19043) {  // win10 21H1
        versionStream << L"Windows 10 21H1 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber == 19044) {  // win10 21H2
        versionStream << L"Windows 10 21H2 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber == 19045) {  // win10 22H2
        versionStream << L"Windows 10 22H2 <"
            << szOSDisplayVersion << L">";
    }
    else if(osvi.dwBuildNumber == 22000) {  // win11 21H2
        versionStream << L"Windows 11 21H2 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber == 22621) {  // win11 22H2
        versionStream << L"Windows 11 22H2 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber == 22631) {  // win11 23H2
        versionStream << L"Windows 11 23H2 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber == 26100) {  // win11 24H2
        versionStream << L"Windows 11 24H2 <"
            << szOSDisplayVersion << L">";
    }
    else if (osvi.dwBuildNumber > 26100) {
        versionStream << L"Windows 11 24H2 或者更高版本 <"
            << szOSDisplayVersion << L">";
    }
    else {
        versionStream << L"预览体验计划版本或者其他 <"
            << szOSDisplayVersion << L">";
    }

    return versionStream.str();
}

使用样例:

/**
 *
 * CRunaGUIDlg::OnBnClickedButton6()
 * -- 设置是否使用小任务栏按钮
 * (系统默认不显示)
 *
 */
void CRunaGUIDlg::OnBnClickedButton6()
{
	RTL_OSVERSIONINFOW osvi{};
	DWORD32 UBR = LYGetOSVersionAndUBR(&osvi);
	if (UBR == _LIBLIANYOU_OSVERSION_INVALID)
	{
		if (IDYES != MessageBoxW(
			L"当前系统版本可能不支持此功能,继续执行可能出现未知结果。是否要继续?",
			L"提示", MB_YESNO | MB_ICONWARNING | MB_APPLMODAL))
			return;
	}
	else if (osvi.dwMajorVersion >= 10 && osvi.dwBuildNumber >= 22621 && UBR >= 1413)
	{
		// 格式化版本号
		std::wstring formattedVersion = LYFormatVersionString(osvi, UBR);
		std::wstring szOSDisplayVersion;
		
		if (!LYGetDisplayVersion(szOSDisplayVersion)) {
			szOSDisplayVersion = L"(Unknown)";
		}

		std::wstring formattedVersion2 = 
			LYFormatVersionString2(osvi, szOSDisplayVersion);
		
		// 构建完整的消息框内容
		std::wstring message = 
			L"当前系统版本不支持此功能。\n构建版本: "
			+ formattedVersion
			+ L"\n显式版本: " + formattedVersion2;

		// 显示消息框
		MessageBoxW( message.c_str(),
			L"提示", MB_OK | MB_ICONWARNING | MB_APPLMODAL);
		return;
	}

	//TaskbarSmallIcons
	const char* valueName1 = "TaskbarSmallIcons";
	DWORD value1;
	value1 = RegGetExplorerAdvancedDwordValue(valueName1);

	if (value1 != IsSmallTaskIconsEnabled)
	{
		MessageBoxW(L"当前缓存的设置与系统配置不一致,需要同步后再操作。",
			L"提示",
			MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
		OnInitCheckIsTaskbarSmallIconsEnabled();
		return;
	}


	if (!IsSmallTaskIconsEnabled)
	{
		RegSetExplorerAdvancedDwordValue(valueName1, 1);
		IsSmallTaskIconsEnabled = true;
		smallTaskbarIconsBn.SetWindowTextW(L"禁用小任务栏按钮");
	}
	else
	{
		RegSetExplorerAdvancedDwordValue(valueName1, 0);
		IsSmallTaskIconsEnabled = false;
		smallTaskbarIconsBn.SetWindowTextW(L"启用小任务栏按钮");
	}

	// 小任务栏按钮
	// (目前需要配合修改注册表,不需要注册表的实现还在研究,可能存在)
	// HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
	// TaskbarSmallIcons   值:1 小图标, 值 0 大图标
	SendMessageTimeoutW(
		HWND_BROADCAST,
		WM_SETTINGCHANGE, NULL,
		(LPARAM)L"TraySettings",
		SMTO_NOTIMEOUTIFNOTHUNG,
		3000, NULL);

	MessageBoxW(L"操作成功完成", L"提示",
		MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);

}

效果:
检测版本

[补充]
判断进程是否运行在兼容模式下:

#include <windows.h>
#include <psapi.h>
#include <iostream>
#include <string>
#include <locale>
#include <vector>

struct CompatibilityEntry {
    std::wstring programPath;
    std::wstring compatibilityMode;
};

// Convert a string to lowercase
void ToLower(std::wstring& str) {
    for (size_t i = 0; i < str.length(); ++i) {
        str[i] = towlower(str[i]);
    }
}

// Function to get the current executable path
std::wstring GetCurrentExecutablePath() {
    DWORD bufferSize = MAX_PATH;
    std::vector<wchar_t> buffer(bufferSize);

    while (true) {
        DWORD result = GetModuleFileNameW(
            NULL, 
            buffer.data(), 
            bufferSize);

        if (result == 0) {
            std::wcerr << L"Failed to get the current process path." << std::endl;
            return L"";
        }
        if (result < bufferSize) {
            return std::wstring(buffer.data());
        }
        bufferSize *= 2;
        buffer.resize(bufferSize);
    }
}

// Function to check if AcLayers.dll is loaded in the current process
BOOL IsAcLayersDllLoaded() {
    WCHAR systemDir[MAX_PATH];
    if (GetSystemDirectoryW(systemDir, MAX_PATH) == 0) {
        std::wcerr << L"Failed to get the system directory." << std::endl;
        return FALSE;
    }

    std::wstring aclayersPath = systemDir;
    aclayersPath += L"\\AcLayers.dll";
    ToLower(aclayersPath);

    HMODULE hModules[1024];
    DWORD cbNeeded;

    if (EnumProcessModules(GetCurrentProcess(), hModules, sizeof(hModules), 
        &cbNeeded)) {

        for (size_t i = 0; i < (cbNeeded / sizeof(HMODULE)); ++i) {
            WCHAR moduleName[MAX_PATH];
            if (GetModuleFileNameExW(GetCurrentProcess(), hModules[i],
                moduleName, MAX_PATH)) {
                std::wstring modulePath = moduleName;
                ToLower(modulePath);
                if (modulePath == aclayersPath) {
                    return TRUE;
                }
            }
        }
    }
    return FALSE;
}

// Function to check compatibility mode and merge results
BOOL RegCheckCompatibilityMode(
    HKEY rootKey, 
    const std::wstring& subKey, 
    const std::wstring& currentPath, 
    std::vector<CompatibilityEntry>& results
)
{
    HKEY hKey;
    if (RegOpenKeyEx(rootKey, subKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
        std::wcerr << L"Failed to open registry key: " << subKey << std::endl;
        return FALSE;
    }

    DWORD index = 0;
    WCHAR valueName[256];
    DWORD valueNameSize = sizeof(valueName) / sizeof(valueName[0]);
    BYTE data[256];
    DWORD dataSize = sizeof(data);
    DWORD type;

    std::wcout.imbue(std::locale(""));

    while (RegEnumValue(hKey, 
        index, valueName, &valueNameSize, 
        NULL, &type, data, &dataSize) == ERROR_SUCCESS) {
        if (type == REG_SZ) {
            CompatibilityEntry entry;
            entry.programPath = valueName;
            entry.compatibilityMode = (WCHAR*)data;

            auto it = std::find_if(
                results.begin(), 
                results.end(), 
                [&](const CompatibilityEntry& e)
                {
                    return e.programPath == entry.programPath;
                });

            // Add or overwrite entry
            if (it != results.end()) {
                if (rootKey == HKEY_LOCAL_MACHINE) {
                    *it = entry; // Overwrite if from HKEY_LOCAL_MACHINE
                }
            }
            else {
                results.push_back(entry);
            }

            if (entry.programPath == currentPath) {
                std::wcout << L"[-] Match found!\n\tProgram: "
                    << entry.programPath << L" - Compatibility Mode: "
                    << entry.compatibilityMode << std::endl;
            }
        }
        index++;
        valueNameSize = sizeof(valueName) / sizeof(valueName[0]);
        dataSize = sizeof(data);
    }

    RegCloseKey(hKey);
    return TRUE;
}

// Function that encapsulates all three checks
BOOL PerformCheckCompatibilityMode() {

    // Check if AcLayers.dll is loaded
    if (!IsAcLayersDllLoaded()) {
        std::wcerr << L"[+] AcLayers.dll is not loaded in the current process." << std::endl;
        return FALSE;
    }
    else {
        std::wcout << L"[-] AcLayers.dll is loaded in the current process." << std::endl;
    }

    std::wstring currentPath = GetCurrentExecutablePath();
    if (currentPath.empty()) {
        return FALSE;
    }

    std::wcout << L"[*] Current process path: " << currentPath << std::endl;

    std::vector<CompatibilityEntry> results;

    // Check HKEY_CURRENT_USER registry path
    std::wcout << L"[*] Checking HKEY_CURRENT_USER..." << std::endl;
    RegCheckCompatibilityMode(HKEY_CURRENT_USER, 
        L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 
        currentPath, results);

    // Check HKEY_LOCAL_MACHINE registry path
    std::wcout << L"[*] Checking HKEY_LOCAL_MACHINE..." << std::endl;
    RegCheckCompatibilityMode(HKEY_LOCAL_MACHINE, 
        L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 
        currentPath, results);

    // Final check: Ensure at least one registry entry matches and DLL is loaded
    if (!results.empty()) {
        //std::wcout << L"Compatibility settings detected." << std::endl;
        return TRUE;
    }
    else {
        //std::wcerr << L"No compatibility settings found." << std::endl;
        return FALSE;
    }
}

int main() {
    if (PerformCheckCompatibilityMode()) {
        std::wcout << L"\n[-] The current process is running in compatibility mode." << std::endl;
    }
    else {
        std::wcout << L"\n[+] Not detected." << std::endl;
    }

    return 0;
}

原文出处链接:https://blog.csdn.net/qq_59075481/article/details/142319803
本文发布于:2024.09.17,修改于:2024.09.17, 2024.10.23, 2024.10.31。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涟幽516

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值