背景介绍
在近期的工作中,我们偶然发现了一条非常实用且有趣的命令。通过这条命令,我们可以轻松获取计算机支持的最大内存容量以及内存插槽的数量。
wmic memphysical get MaxCapacity, MemoryDevices
这条命令是否可以用来检测沙箱或虚拟机呢?通过分析系统支持的最大内存容量和内存插槽数量,或许能够捕捉到某些异常特征。例如,虚拟机环境中的硬件配置通常与物理机存在差异,可能会出现不合理的内存大小或超出常规范围的插槽数量。基于这些差异,这条命令或许可以成为我们判断虚拟环境的一种巧妙手段。
详细信息
让我们先看一下这条命令在真实物理机上的运行结果。通过输出可以清楚地看到,这台电脑最大支持 16GB 的内存,并且配备了两个内存插槽。这意味着每个内存插槽的最大支持容量为 8GB,非常符合常见的物理机硬件配置。
C:\Users\4SecNet>wmic memphysical get MaxCapacity, MemoryDevices MaxCapacity MemoryDevices 16777216 2
接着,我们来看一下虚拟机运行这条命令后的结果。我的虚拟机实际配置为 4 核 8GB,但查询结果却让人震惊:显示计算机支持的最大内存容量为 129GB,配备了多达 64 个内存插槽。这意味着单个内存插槽的支持容量仅为 2GB,显然这种配置与真实物理机的常规硬件情况相去甚远,极具虚拟环境的特征。
C:\Users\4SecNet>wmic memphysical get MaxCapacity, MemoryDevices MaxCapacity MemoryDevices 135266304 64
同样地,我们再来看一下微步云沙箱的运行结果。查询显示只有 1 个内存插槽,总内存最大容量为 4GB。这样的配置在现代计算机中几乎难以见到,只有在非常古老的系统上才有可能存在。这种异常的硬件信息再次印证了沙箱环境与真实物理机之间的显著差异。
无独有偶,我们再来看一下 AnyRun 沙箱的运行结果。令人惊讶的是,它的结果竟与微步云沙箱如出一辙:仅有 1 个内存插槽,最大只支持 4GB 的内存条。谁的电脑会只有一个内存插槽,而且还仅能支持如此小的容量?这样的配置显然脱离了现代硬件的常规范畴,进一步暴露了沙箱环境的特征。
基于常规计算机的硬件特性,我们总结了一些用于判断沙箱和虚拟机的思路。一般而言,普通计算机的最大内存容量通常是 2GB 的整数倍,单个内存槽的最大容量通常不会低于 8GB,同时内存槽的数量也不会过多。基于这一逻辑,我们将其转化为代码实现,以便更高效地检测异常环境。
if ((maxCapacity % (2 * 1024 * 1024)) != 0 || // 内存总容量不是2GB整数倍 (maxCapacity / memoryDevices) < (8 * 1024 * 1024) || // 单个内存槽支持最大容量小于8GB memoryDevices > 16) { // 内存插槽数量大于16 isVirtualSandbox = true; }
最终效果
我们最终通过代码实现,调用 WMI 接口来模拟执行这条命令的过程,并判断当前是否在沙箱环境。
物理机运行结果
VMware运行结果。
微步运行结果。
完整代码
#include <iostream> #include <comdef.h> #include <Wbemidl.h> #pragma comment(lib, "wbemuuid.lib") void GetMemoryInfo() { HRESULT hres; // 初始化 COM 库 hres = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hres)) { std::cerr << "Failed to initialize COM library. Error code = 0x" << std::hex << hres << std::endl; return; } // 初始化安全性 hres = CoInitializeSecurity( NULL, -1, // COM默认认证服务 NULL, // COM默认授权服务 NULL, // 预留 RPC_C_AUTHN_LEVEL_DEFAULT, // 默认认证级别 RPC_C_IMP_LEVEL_IMPERSONATE, // 默认模拟级别 NULL, // 授权列表 EOAC_NONE, // 其他选项 NULL // 预留 ); if (FAILED(hres)) { std::cerr << "Failed to initialize security. Error code = 0x" << std::hex << hres << std::endl; CoUninitialize(); return; } // 获取 WMI 服务接口 IWbemLocator* pLoc = NULL; hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc ); if (FAILED(hres)) { std::cerr << "Failed to create IWbemLocator object. Error code = 0x" << std::hex << hres << std::endl; CoUninitialize(); return; } IWbemServices* pSvc = NULL; hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), // WMI 命名空间 NULL, // 用户名 NULL, // 密码 0, // 区域设置 NULL, // 安全标志 0, // 权限 0, // 代理 &pSvc // 接口指针 ); if (FAILED(hres)) { std::cerr << "Could not connect to WMI namespace. Error code = 0x" << std::hex << hres << std::endl; pLoc->Release(); CoUninitialize(); return; } // 设置代理安全性 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)) { std::cerr << "Could not set proxy blanket. Error code = 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return; } // 执行 WMI 查询 IEnumWbemClassObject* pEnumerator = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT MaxCapacity, MemoryDevices FROM Win32_PhysicalMemoryArray"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator ); if (FAILED(hres)) { std::cerr << "WMI query failed. Error code = 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return; } // 解析查询结果 IWbemClassObject* pClassObject = NULL; ULONG uReturn = 0; bool isVirtualSandbox = false; while (pEnumerator) { HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObject, &uReturn); if (0 == uReturn) { break; } VARIANT vtProp; UINT32 maxCapacity = 0; UINT32 memoryDevices = 0; // 获取 MaxCapacity hr = pClassObject->Get(L"MaxCapacity", 0, &vtProp, 0, 0); if (SUCCEEDED(hr)) { maxCapacity = vtProp.uintVal; std::wcout << L"MaxCapacity (KB): " << maxCapacity << std::endl; } VariantClear(&vtProp); // 获取 MemoryDevices hr = pClassObject->Get(L"MemoryDevices", 0, &vtProp, 0, 0); if (SUCCEEDED(hr)) { memoryDevices = vtProp.uintVal; std::wcout << L"MemoryDevices: " << memoryDevices << std::endl; } VariantClear(&vtProp); // 条件判断 if ((maxCapacity % (2 * 1024 * 1024)) != 0 || // 内存总容量不是2GB整数倍 (maxCapacity / memoryDevices) < (8 * 1024 * 1024) || // 单个内存槽支持最大容量小于8GB memoryDevices > 16) { // 内存插槽数量大于16 isVirtualSandbox = true; } pClassObject->Release(); } // 打印结果 if (isVirtualSandbox) { std::cout << "Virtual SandBox" << std::endl; } else { std::cout << "Physical environment" << std::endl; } // 清理 pEnumerator->Release(); pSvc->Release(); pLoc->Release(); CoUninitialize(); } int main() { GetMemoryInfo(); getchar(); return0; }
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)