沙箱检测
硬件检测
包括:
1.CPU核心数检测
//检查处理器核心数
BOOL CheckNumberOfProcessor()
{
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
if (sysInfo.dwNumberOfProcessors <= 2) {
return FALSE;
}
return TRUE;
}
2.硬盘空间检测
2024年了,主流PC上最小硬盘也在120+,如果系统盘只有40G(部分云服务器可能是40G),或者是更小,显然不正常,所以可以通过检测硬盘的大小来判断是不是沙箱环境。
3.检测Mac地址
用途很少,但也算一个方法,Mac地址一般是按规则分配给各个厂商的,可以通过判断Mac地址来确定程序是否在沙箱或虚拟机环境运行。
4.检测物理内存
//检查内存大小,
//如果小于2G,那么返回FALSE
//否则返回TRUE
BOOL CheckMemorySize()
{
_MEMORYSTATUSEX stMem;
stMem.dwLength = sizeof(stMem);
GlobalMemoryStatusEx(&stMem);
if (stMem.ullTotalPhys < (1024ULL * 1024 * 1024 * 2))
{
return FALSE;
}
return TRUE;
}
环境检测
1.进程数量检测
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
int GetProcessCount() {
int processCount = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_PROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
std::cerr << "无法创建进程快照。" << std::endl;
return -1;
}
PROCESSENTRY32 processEntry;
processEntry.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &processEntry)) {
do {
processCount++;
} while (Process32Next(hSnapshot, &processEntry));
} else {
std::cerr << "无法获取进程信息。" << std::endl;
}
CloseHandle(hSnapshot);
return processCount;
}
int main() {
int processCount = GetProcessCount();
if (processCount >= 0) {
std::cout << "当前系统进程数量: " << processCount << std::endl;
}
return 0;
}
2.特定进程检测
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
bool IsDwmProcessRunning() {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_PROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
std::cerr << "无法创建进程快照。" << std::endl;
return false;
}
PROCESSENTRY32 processEntry;
processEntry.dwSize = sizeof(PROCESSENTRY32);
// 遍历进程
if (Process32First(hSnapshot, &processEntry)) {
do {
if (strcmp(processEntry.szExeFile, "dwm.exe") == 0) {
CloseHandle(hSnapshot);
return true; // 找到 dwm.exe 进程
}
} while (Process32Next(hSnapshot, &processEntry));
}
CloseHandle(hSnapshot);
return false; // 未找到 dwm.exe 进程
}
int main() {
if (IsDwmProcessRunning()) {
std::cout << "dwm.exe 进程正在运行。" << std::endl;
} else {
std::cout << "dwm.exe 进程未运行。" << std::endl;
}
return 0;
}
3.临时目录的文件数量
BOOL CheckCountTempPathFile()
{
int nCount = 0;
WCHAR szTmpPath[MAX_PATH];
GetTempPath(MAX_PATH, szTmpPath);
wcscat(szTmpPath, L"\\*.*");
WIN32_FIND_DATA findData;
HANDLE hFile = FindFirstFile(szTmpPath, &findData);
if (INVALID_HANDLE_VALUE == hFile) {
return FALSE;
}
do {
nCount++;
} while (FindNextFile(hFile, &findData));
if (nCount < 30) {
return FALSE;
}
return TRUE;
}
4.检测开机时间
//检测开机时间
BOOL CheckTickCount()
{
DWORD dwTickCount = GetTickCount();
if (dwTickCount < (10 * 60 * 1000)) {
return FALSE;
}
return TRUE;
}
5.安装的软件数量
一般正常使用的PC不可能只有一两个软件,所以可以通过统计系统中注册的软件数量来判断是不是沙箱环境。
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
bool IsDwmProcessRunning() {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_PROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
std::cerr << "无法创建进程快照。" << std::endl;
return false;
}
PROCESSENTRY32 processEntry;
processEntry.dwSize = sizeof(PROCESSENTRY32);
// 遍历进程
if (Process32First(hSnapshot, &processEntry)) {
do {
if (strcmp(processEntry.szExeFile, "dwm.exe") == 0) {
CloseHandle(hSnapshot);
return true; // 找到 dwm.exe 进程
}
} while (Process32Next(hSnapshot, &processEntry));
}
CloseHandle(hSnapshot);
return false; // 未找到 dwm.exe 进程
}
int main() {
if (IsDwmProcessRunning()) {
std::cout << "dwm.exe 进程正在运行。" << std::endl;
} else {
std::cout << "dwm.exe 进程未运行。" << std::endl;
}
return 0;
}
6.检测特定函数是否被挂钩
沙箱一般会处理特定的函数,例如:时间函数、进程相关函数、内存分配等,可以通过检测这些函数是否被HOOK来判断,但是正常情况存在安全软件等也可能会有这种情况。
//下面的代码可以检测IAT HOOK
#include <windows.h>
#include <iostream>
#include <psapi.h>
void CheckVirtualAllocHook() {
HMODULE hModule = GetModuleHandleA("kernel32.dll");
FARPROC pVirtualAlloc = GetProcAddress(hModule, "VirtualAlloc");
// 获取 VirtualAlloc 的真实地址
// 这里可以使用一些已知的地址来对比
// 例如: 0x7C801D7C 在某些系统上是 VirtualAlloc 的地址
// 检查地址
if (pVirtualAlloc != (FARPROC)0x7C801D7C) { // 这里的地址需要根据实际情况调整
std::cout << "VirtualAlloc may be hooked!" << std::endl;
} else {
std::cout << "VirtualAlloc is not hooked." << std::endl;
}
}
int main() {
CheckVirtualAllocHook();
return 0;
}
7.操作系统语言检测,用在已知目标终端机器操作系统语言的情况下。
#include <windows.h>
#include <iostream>
#include <locale>
void CheckSystemLanguage() {
// 获取当前线程的用户界面语言
LANGID langId = GetUserDefaultUILanguage();
// 获取语言名称
wchar_t langName[LOCALE_NAME_MAX_LENGTH];
if (LCIDToLocaleName(langId, langName, LOCALE_NAME_MAX_LENGTH, 0)) {
std::wcout << L"当前系统语言: " << langName << std::endl;
} else {
std::cerr << "获取语言名称失败。" << std::endl;
}
// 获取区域设置
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
if (GetLocaleInfoEx(nullptr, LOCALE_SISO639LANGNAME, localeName, LOCALE_NAME_MAX_LENGTH) > 0) {
std::wcout << L"区域设置: " << localeName << std::endl;
} else {
std::cerr << "获取区域设置失败。" << std::endl;
}
}
int main() {
CheckSystemLanguage();
return 0;
}
8.用户名、计算机名检测
如果已知特定沙箱的用户名、计算机名等特征,可以通过检测该特征。
9.CPU温度
#include <windows.h>
#include <iostream>
#include <comdef.h>
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
void CheckCpuTemperature() {
HRESULT hres;
// 初始化 COM
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres)) {
std::cerr << "COM 初始化失败。" << std::endl;
return;
}
hres = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
if (FAILED(hres)) {
std::cerr << "安全初始化失败。" << 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 << "WMI Locator 创建失败。" << std::endl;
CoUninitialize();
return;
}
IWbemServices *pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
if (FAILED(hres)) {
std::cerr << "连接 WMI 服务失败。" << std::endl;
pLoc->Release();
CoUninitialize();
return;
}
// 设置安全级别
hres = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
// 查询 CPU 温度
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_PerfFormattedData_Counters_ThermalZone"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator
);
if (FAILED(hres)) {
std::cerr << "查询失败。" << std::endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return;
}
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator) {
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn) {
break;
}
// 获取 CPU 温度
VARIANT vtTemperature;
VariantInit(&vtTemperature);
hr = pclsObj->Get(L"CurrentTemperature", 0, &vtTemperature, 0, 0);
if (SUCCEEDED(hr)) {
// 温度单位为开尔文,转换为摄氏度
double temperatureCelsius = (vtTemperature.dblVal - 273.15);
std::cout << "CPU 温度: " << temperatureCelsius << " °C" << std::endl;
}
VariantClear(&vtTemperature);
pclsObj->Release();
}
// 清理
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
}
int main() {
CheckCpuTemperature();
return 0;
}
10.软件数量检测
软件数量一般要检测注册表,下面的代码只检测了64位的软件数量
#include <windows.h>
#include <iostream>
int GetInstalledSoftwareCount() {
HKEY hKey;
int softwareCount = 0;
// 打开注册表路径以获取已安装软件的信息
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
char softwareName[256];
DWORD nameLength = sizeof(softwareName);
DWORD index = 0;
// 遍历注册表项
while (RegEnumKeyExA(hKey, index, softwareName, &nameLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
softwareCount++;
index++;
nameLength = sizeof(softwareName); // 重置名称长度
}
RegCloseKey(hKey);
} else {
std::cerr << "无法打开注册表项。" << std::endl;
}
return softwareCount;
}
int main() {
int softwareCount = GetInstalledSoftwareCount();
std::cout << "当前系统安装的软件数量: " << softwareCount << std::endl;
return 0;
}
用户操作检测
1.特定窗口检测
2.鼠标移动检测
3.键盘按键检测(慎用)
#include <windows.h>
#include <iostream>
bool IsKeyboardInputDetected() {
// 检查当前线程的消息队列
MSG msg;
while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) {
if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) {
return true; // 检测到键盘输入
}
}
return false; // 未检测到键盘输入
}
bool IsMouseMoved(POINT& lastPosition) {
POINT currentPosition;
GetCursorPos(¤tPosition); // 获取当前鼠标位置
// 检查当前鼠标位置是否与上次记录的位置不同
if (currentPosition.x != lastPosition.x || currentPosition.y != lastPosition.y) {
lastPosition = currentPosition; // 更新最后的位置
return true; // 鼠标已移动
}
return false; // 鼠标未移动
}
int main() {
POINT lastMousePosition;
GetCursorPos(&lastMousePosition); // 初始化上次鼠标位置
while (true) {
// 检测键盘输入
if (IsKeyboardInputDetected()) {
std::cout << "检测到键盘输入。" << std::endl;
}
// 检测鼠标移动
if (IsMouseMoved(lastMousePosition)) {
std::cout << "鼠标已移动。" << std::endl;
}
Sleep(100); // 暂停一段时间以避免过于频繁的检测
}
return 0;
}
时间检测
1.通过GetTickCount和Time函数的结果对比
2.Sleep和GetTickCount的结果去对比
3.判断特定时间范围
沙箱绕过
延时运行
1.通过长时间计算任务(计算pi、遍历特定的目录等)
2.通过时间判断(这种不太准,可能存在被沙箱将API HOOK导致函数失效的问题)
环境检测绕过
1.临时目录中文件数量检测,如果不符合条件退出或者延长程序的功能执行时间
#include <windows.h>
#include <iostream>
#include <string>
#include <dirent.h>
int CountFilesInTempDirectory() {
// 获取临时目录路径
char tempPath[MAX_PATH];
GetTempPathA(MAX_PATH, tempPath);
// 确保路径结尾有反斜杠
std::string path(tempPath);
if (path.back() != '\\') {
path += '\\';
}
// 计数文件数量
int fileCount = 0;
WIN32_FIND_DATAA findFileData;
HANDLE hFind = FindFirstFileA((path + "*").c_str(), &findFileData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
// 忽略目录
if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
fileCount++;
}
} while (FindNextFileA(hFind, &findFileData) != 0);
FindClose(hFind);
} else {
std::cerr << "无法访问临时目录。" << std::endl;
}
return fileCount;
}
int main() {
int fileCount = CountFilesInTempDirectory();
std::cout << "临时目录中的文件数量: " << fileCount << std::endl;
return 0;
}
2.特定进程检测、进程数量检测
正常系统Windows 10一般情况下会有50+以上个进程,而沙箱中为了性能,不会有太多进程,所以可以通过检测系统进程数量来判断进程是否处于沙箱中。同理,软件、服务等等都可以作为特征。
虚拟机检测
文件检测
VMware
C:\windows\System32\Drivers\Vmmouse.sys C:\windows\System32\Drivers\vmtray.dll C:\windows\System32\Drivers\VMToolsHook.dll C:\windows\System32\Drivers\vmmousever.dll C:\windows\System32\Drivers\vmhgfs.dll C:\windows\System32\Drivers\vmGuestLib.dll
VirtualBox
C:\windows\System32\Drivers\VBoxMouse.sys C:\windows\System32\Drivers\VBoxGuest.sys C:\windows\System32\Drivers\VBoxSF.sys C:\windows\System32\Drivers\VBoxVideo.sys C:\windows\System32\vboxdisp.dll C:\windows\System32\vboxhook.dll C:\windows\System32\vboxoglerrorspu.dll C:\windows\System32\vboxoglpassthroughspu.dll C:\windows\System32\vboxservice.exe C:\windows\System32\vboxtray.exe C:\windows\System32\VBoxControl.exe
Mac地址检测
虚拟机Mac地址特点
00:05:69 (Vmware) 00:0C:29 (Vmware) 00:1C:14 (Vmware) 00:50:56 (Vmware) 08:00:27 (VirtualBox)
服务检测
VMTools Vmrawdsk Vmusbmouse Vmvss Vmscsi Vmxnet vmx_svga Vmware Tools
使用CPUID
#include <iostream>
#include <intrin.h>
bool IsRunningInVM() {
int cpuInfo[4];
__cpuid(cpuInfo, 1); // 获取处理器信息
// 检查虚拟化标志
bool isVM = (cpuInfo[2] & (1 << 31)) != 0; // 检查 Bit 31
// 进一步检查 VMWare 和 VirtualBox 等虚拟化平台的特征
__cpuid(cpuInfo, 0x40000000); // 获取制造商信息
if (cpuInfo[0] >= 0x40000000) {
// 获取虚拟化厂商的字符串
char vendor[13];
memcpy(vendor, &cpuInfo[1], 4);
memcpy(vendor + 4, &cpuInfo[2], 4);
memcpy(vendor + 8, &cpuInfo[3], 4);
vendor[12] = '\0';
if (strcmp(vendor, "VMware") == 0 || strcmp(vendor, "VirtualBox") == 0) {
isVM = true;
}
}
return isVM;
}
int main() {
if (IsRunningInVM()) {
std::cout << "程序正在虚拟机中运行。" << std::endl;
} else {
std::cout << "程序不在虚拟机中运行。" << std::endl;
}
return 0;
}
进程名
Vmware:
Vmtoolsd.exe Vmwaretrat.exe Vmwareuser.exe Vmacthlp.exe
VirtualBox:
vboxservice.exe vboxtray.exe
注册表检测
以下是vbox和vmware存在的一些注册表:
HKLM\SOFTWARE\Vmware Inc\Vmware Tools HKLM\HARDWARE\DEVICEMAP\Scsi\Scsi Port 2\Scsi Bus 0\Target Id 0\Logical Unit Id 0\Identifier HKEY_CLASSES_ROOT\Applications\VMwareHostOpen.exe HKEY_LOCAL_MACHINE\SOFTWARE\Oracle\VirtualBox Guest Additions
参考文档:
https://www.freebuf.com/articles/system/202717.html
部分代码使用Chatgpt4生成,未验证是否可正常通过编译,如果报错,请依据实际情况修改。