Loading... 1、执行权限检测 在 x86 中,一些指令在获取硬件相关信息而不会产生异常,如 sidt、sgdt、sldt、cpuid 等,因为性能原因并没有 VMware 虚拟这些指令,所以机器意味着指令在虚拟机时和物理物理机中运行时会返回不同的结果。 可能会因为虚拟机的升级,导致结果不一样。 2、LDT(随便表) sgdtsldt 由虚拟机配置依赖于LDT(与LDT 提供技术结果),因为Windows 分配了事务表,由虚拟机分配的事实,但不支持LDT,但不支持LDT 的配置真机中LDT位置为0,而在虚拟机中,不为0。同时对于GTR,虚拟机中应为0xFFXXXXXX,否则为真机。 ```cpp inline bool IsVirtualPC_LDTCheck() { unsigned short ldt_addr = 0; unsigned char ldtr[2]; _asm sldt ldtr ldt_addr = *((unsigned short *)&ldtr); return ldt_addr != 0x00000000; } ``` 3、推荐网址 ``` inline bool IsVirtualPC_GDTCheck() { unsigned int gdt_addr = 0; unsigned char gdtr[6]; ``` 4、GDT检测 ```cpp inline bool IsVirtualPC_GDTCheck() { unsigned int gdt_addr = 0; unsigned char gdtr[6]; _asm sgdt gdtr gdt_addr = *((unsigned int *)&gdtr[2]); return (gdt_addr >> 24) == 0xff; } ``` 5、TSS检测 ```cpp inline bool IsVirtualPC_TSSCheck() { unsigned char mem[4] = { 0 }; __asm str mem; return (mem[0] == 0x00) && (mem[1] == 0x40); } ``` 6、I/O通信端口检测 使用IN指令来获取特定端口的数据进行,由于IN指令具有权限,但在保护模式下的真指令上执行此指令时,授权允许使用权限,否则触发为“EXCEL PRIV_INSTRUCTION” “的异常,而在虚拟机中并不会发生异常,在指定功能号为0xA/10(获取VMware版本)时,会在EBX中返回其版本号“VMXH”;而当功能号为0x14时,可当获取更大的0时分析用于描述虚拟机中的情况。 //查询I/O通信端口 ``` BOOL CheckVMWare1() { BOOL bResult = TRUE; __try { __asm { push edx push ecx push ebx //保存环境 mov eax, 'VMXh' mov ebx, 0 //将ebx清零 mov ecx, 10 //指定功能号,用于获取VMWare版本,为0x14时获取VM内存大小 mov edx, 'VX' //端口号 in eax, dx //从端口edx 读取VMware到eax cmp ebx, 'VMXh' //判断ebx中是否包含VMware版本’VMXh’,若是则在虚拟机中 setz[bResult] //为零 (ZF=1) 时设置字节 pop ebx //恢复环境 pop ecx pop edx } } __except (EXCEPTION_EXECUTE_HANDLER) //如果未处于VMware中,则触发此异常 { bResult = FALSE; } return bResult; } ``` 检查MAC ``` #include <stdio.h> #include <string.h> bool checkMAC(){ char buffer[128]; char result[1024*50] = ""; char MAC[] = "08-00-27"; FILE *pipe = _popen("ipconfig /all","r"); if(!pipe) return 0; while(!feof(pipe)){ if(fgets(buffer,128,pipe)) strcat(result,buffer); } _pclose(pipe); //08-00-27 if(strstr(result,MAC)) return false; else return true; } int main(){ if(checkMAC()) printf("Õý³£ÔËÐÐ\n"); else printf("vboxÐéÄâ»úÔËÐÐ\n"); getchar(); } ``` ## 获取当前可用的虚拟/物理内存 当今大多数pc具有4GB以上的RAM,我们可以检测RAM是否大于4GB来判断是否是真实的运行机器。 内存大小可能会大于4GB的情况下我们需要用GlobalMemoryStatusEx获取内存信息,查看MSDN会发现MEMORYSTATUSEX的成员值所占的字节数比MEMORYSTATUS成员值占用的字节数大,其中的成员ullTotalPhys为物理内存大小。 下图代码使用GlobalMemoryStatusEx()来获得一个DWORDLONG类型的内存大小,然后与4GB比较,小于4GB返回false,大于4GB返回true。 ``` #include <windows.h> #include <stdio.h> bool CheckMemory(){ _MEMORYSTATUSEX mst; DWORDLONG d_size = 4294496257; mst.dwLength = sizeof(mst); GlobalMemoryStatusEx(&mst); //printf("PhyMszie:%llu \n",mst.ullTotalPhys); if(mst.ullTotalPhys < d_size) return false; else return true; } int main(){ if(CheckMemory()) printf("ok\n"); else printf("error!\n"); getchar(); return 0; } ``` ## 进程查看 ``` #include <stdio.h> #include <string.h> #include <windows.h> #include <TlHelp32.h> int check(char* name) { const char* list[2] = { "VBoxService.exe","VBoxTray.exe" }; for (int i = 0;i < 2;++i) { if (strcmp(name, list[i]) == 0) return -1; } return 0; } bool CheckProcess() { PROCESSENTRY32 pe32; pe32.dwSize = sizeof(pe32); HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); BOOL bResult = Process32First(hProcessSnap, &pe32); while (bResult) { char sz_Name[MAX_PATH] = { 0 }; WideCharToMultiByte(CP_ACP, 0, pe32.szExeFile, -1, sz_Name, sizeof(sz_Name), NULL, NULL); //printf("%s\n", sz_Name); if (check(sz_Name) == -1) return false; bResult = Process32Next(hProcessSnap, &pe32); } return true; } int main(){ if (CheckProcess() == false) { printf("存在虚拟机\n"); } else{ printf("检测通过!\n"); } getchar(); return 0; } ``` ## 注册表检测 ``` #include <stdio.h> #include <Windows.h> #include <winreg.h> bool checkReg() { HKEY hkey; if (RegOpenKey(HKEY_CLASSES_ROOT, "\\Applications\\VMwareHostOpen.exe", &hkey) == ERROR_SUCCESS) { return true; } else { return false; } } int main() { if (checkReg()) { printf("检测到虚拟机"); } else { printf("未检测到虚拟机"); } getchar(); return 0; } ``` ## 时间戳检测 许多沙箱检测完毕后会重置系统,我们可以检测开机时间来判断是否为真实的运行状况。 我们使用WINAPI GetTickCount()来获取机器已运行的时间(以秒为单位)。然后判断开机运行时间是否大于1个小时,如果开机时间小于1小时就返回false。 ``` #include <windows.h> #include <stdio.h> bool checkUptime(){ DWORD UpTime = GetTickCount(); printf("uptime:%u\n",UpTime); if(UpTime < 3600000) return false; else return true; } int main(){ if(checkUptime()) printf("ok\n"); else printf("error!"); getchar(); return 0; } ``` ## CPU ID检测 ``` #include <stdio.h> #include <windows.h> bool isVM(){ DWORD dw_ecx; bool bFlag = true; _asm{ pushad; pushfd; mov eax,1; cpuid; mov dw_ecx,ecx; and ecx,0x80000000; test ecx,ecx; setz[bFlag]; popfd; popad; } if(bFlag) //真实机器 return false; else return true; } ``` ## 延迟执行 在各类检测沙箱中,检测运行的时间往往是比较短的,因为其没有过多资源可以供程序长时间运行,所以我们可以延迟等待一会儿后再进行真实的操作。 ```cpp #include <stdio.h> #include <thread> int main(){ std::chrono::seconds t = std::chrono::seconds(60); std::this_thread::sleep_for(t); return 0; } ``` std::sleep_for():线程调用该方法时,同样会让出CPU,并且休眠一段时间,从而让其他线程有机会运行。等到休眠结束时,才参与CPU调度。 我们使用this_thread::sleep_for()来延迟当前线程,此方法比使用Sleep()更不容易被沙箱使用模拟方法绕过。 ## 检测CPU 大多数pc拥有4核心cpu,许多在线检测的虚拟机沙盘是2核心,我们可以通过核心数来判断是否为真实机器或检测用的虚拟沙箱。 使用winapi函数GetSystemInfo()将系统信息写入类型为SYSTEM_INFO的结构体,其中成员dwNumberOfProcessors就是CPU核心数(超线程技术也算入核心),如果其小于4,CheckCPU()将返回false,检测不通过。 ```cpp #include <stdio.h> #include <windows.h> bool CheckCPU(){ SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); int CoreNum = sysinfo.dwNumberOfProcessors; printf("Core:%d\n",CoreNum); if(CoreNum < 4) return false; else return true; } int main(){ if(CheckCPU()) printf("ok"); else printf("error"); return 0; } ``` ## 检测临时文件 在TEMP中如果文件小于30个就返回 ```cpp #include <windows.h> #include <stdio.h> #include <string> bool CheckTemp(){ int file_count = 0; DWORD dwRet; LPSTR pszOldVal; pszOldVal = (LPSTR)malloc(4096 * sizeof(char)); dwRet = GetEnvironmentVariableA("TEMP",pszOldVal, 4096); std::string stdstr = pszOldVal; stdstr += "\\*"; LPSTR s = const_cast<char *>(stdstr.c_str()); WIN32_FIND_DATAA data; HANDLE hFind = FindFirstFileA(s, &data); if (hFind != INVALID_HANDLE_VALUE){ do{ file_count++; } while (FindNextFileA(hFind, &data)); FindClose(hFind); } printf("count:%d\n",file_count); if (file_count < 30) return false; else return true; } int main() { CheckTemp(); return 0; } ``` 最后修改:2022 年 05 月 22 日 © 允许规范转载 赞 1 如果觉得我的文章对你有用,请随意赞赏