虚拟机运行环境检测

时间:2024-02-20 08:23:31

虚拟机运行环境检测

虚拟机运行环境检测,指的是软件能够判断当前是不是在虚拟机中运行,根据判断结果,做对应的处理。从恶意软件的视角,它可以在虚拟机中改变自身行为,加大分析难度。从软件自身安全出发,用于防止被逆向调试以及某些场景下的非正常使用。

检测思路

要实现这个功能,可有如下几个入手点:

  • 硬件检测
    • 虚拟机会创建具有特定标示符的硬件设备以及驱动。例如vmware会虚拟出两个网卡设备VMnet1(Host Only方式)和VMnet8(NAT方式),vbox会创建VirtualBox Host-Only Network
  • 运行环境检测
    • vmware虚拟机会默认开启几个硬件端口与宿主机通讯。
    • 利用特权指令在虚拟机和真实机器上执行结果不一致来区分。目前在网上找到的方法大部分是用来检测Vmware,不适用于VirtualBox以及VirtuaPC。
  • 应用程序检测
    • 虚拟机会安装一些特定软件以及服务,比如vmtoolsd.exevboxserivce.exe等。
    • 在特定路径下,存在特殊标识,例如注册表、系统驱动文件等。

分享一个网上各虚拟机的硬件区别,原文点此进入

02d06e6691bc2f5087e6a056042c129e.jpg

安装虚拟机以及测试的注意事项

通过VirtualBox安装虚拟机时,有时会出现如下错误:

使用VirtualBox安装系统出错.jpg

通过查阅网上相关资料,发现是因为权限问题,重新以管理员权限打开VirtualBox,就可以继续安装。

本次测试发现Virtaul BoxVirtual PC两款虚拟机会相互冲突,就是说,当Virtaul box启动时,再启动Virtual PCVirtaul box会弹出如下提示:

virtualbox和virtualpc相互冲突.jpg

可能这两种虚拟机不兼容,读者在自行测试时,需要注意这一点。

安装VirtualBox的增强功能时,需要安装多个驱动,有时候安装界面会把驱动安装确认界面给盖住,此时安装界面会出现类似卡死的情况,因此,建议把安装界面移到一边,这样当驱动确认界面出现时,可确认并继续安装。

为了便于在不同虚拟机下测试,选择原版XP系统。在构建测试软件时,注意,要使用兼容XP模式的平台工具集来编译,否则测试软件无法在xp上运行。同时,将程序运行需要的运行库放在同一个共享目录中,各个虚拟机都访问该共享目录。

通过VirtualPC安装虚拟机时,安装集成组件后,无法查看共享目录。网上解答连接在此,需要设置登陆用户名和密码,然后重新启动,在打开VirtualPC虚拟机之前,输入用户名和密码,方可看到共享目录。

实践

以下给出三种实例来检测虚拟机是否存在,分布是基于进程名、基于注册表键以及基于硬盘驱动器检测,更多检测方案,参考文末实例代码链接。

基于进程名检测

通过检测检测指定进程名是否存在,来判断是否运行在虚拟机。


bool IsExist(const wchar_t* pName)
{
	if (nullptr == pName)
		return false;
	
	const wchar_t* list[] = {
		//Vmware
		L"vmtoolsd.exe",
		L"vmacthlp.exe",
		L"vmwaretray.exe",
		L"vmwareuser.exe",
		
		//virtuablBox
		L"vboxserivce.exe",
		L"vboxtray.exe",

		//virtualPC
		L"vmsrvc.exe",
		L"vmusrvc.exe",
		L"vpcmap.exe",
	};

	std::wstring strProcessName(pName);
	std::transform(strProcessName.begin(), strProcessName.end(), strProcessName.begin(), ::tolower);
	for (int i = 0; i < sizeof(list)/sizeof(list[0]); i++)
	{
		if (0 == strProcessName.compare(list[i]))
			return true;
	}

	return false;
}

BOOL CheckVMByProcessName()
{
	HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (INVALID_HANDLE_VALUE == hProcessSnap)
		return false;
	
	PROCESSENTRY32 pe32;
	pe32.dwSize = sizeof(PROCESSENTRY32);
	BOOL bMore = Process32First(hProcessSnap, &pe32);
	while (bMore)
	{
		char szName[MAX_PATH] = { 0 };
		
		if (IsExist(pe32.szExeFile))
		{
			_tprintf(L"进程名: %s 进程PID: %d", pe32.szExeFile, pe32.th32ProcessID);
			break;
		}
			
		bMore = Process32Next(hProcessSnap, &pe32);		
	}

	CloseHandle(hProcessSnap);
	return bMore;
}

基于注册表键检测

利用注册表键值是否存在来检测,具体如下:


LONG registerOpenKey(char *value)
{
	HKEY HK = 0;
	return RegOpenKeyExA(HKEY_LOCAL_MACHINE, value, 0, KEY_READ, &HK);
}

bool CheckVMByReg()
{
	std::string stringVmRegKeys[] =
	{
		//VMWare
		"SOFTWARE\\Clients\\StartMenuInternet\\VMWAREHOSTOPEN.EXE",
		"SOFTWARE\\VMware, Inc.\\VMware Tools",
		"SYSTEM\\CurrentControlSet\\Enum\\SCSI\\Disk&Ven_VMware_&Prod_VMware_Virtual_S",
		
		// Virtual PC or VirtualBox
		"SYSTEM\\CurrentControlSet\\Control\\VirtualDeviceDrivers",
	};
	
	bool bCheckflag = false;
	for (size_t i = 0; i < sizeof(stringVmRegKeys) / sizeof(stringVmRegKeys[0]); i++)
	{
		if (ERROR_SUCCESS == registerOpenKey((char *)stringVmRegKeys[i].c_str()))
		{
			bCheckflag = true;
			printf("Analysis environment detected (%s)\n", stringVmRegKeys[i].c_str());
		}
	}

	return bCheckflag;
}

基于硬盘驱动器名称检测

基于特定硬盘驱动器标题名称来检测。


BOOL CheckVMByDiskName()
{
	std::vector<std::wstring> vtBlockHardDisc({ L"vmware", L"vbox", L"virtual"});

	std::vector<std::wstring> vtDrivers;
	CWmiDataHelper querier;
	if (querier.ExecComQuery(L"select * from Win32_DiskDrive", L"Caption", vtDrivers) && vtDrivers.size())
	{
		std::transform(vtDrivers[0].begin(), vtDrivers[0].end(), vtDrivers[0].begin(), tolower);
		
		for (unsigned int i = 0; i < vtBlockHardDisc.size(); i++)
		{
			if (wcsstr(vtDrivers[0].c_str(), vtBlockHardDisc[i].c_str()))
			{				
				_tprintf(L"local disk name: %s. find key word:%s \n", vtDrivers[0].c_str(), vtBlockHardDisc[i].c_str());
				return TRUE;
			}
		}
	}

	return FALSE;
}

测试结果

测试环境:

  • VMware 10.0.1
  • Virtual Box 6.1.18
  • Virtual PC 6.1.7601

在没有进行任何反检测措施的情况下,下表为检测结果汇总。

检测方法 Vmware Virtual Box Virtual PC 反检测手段
特定进程名检测 可以 可以 可以 删除特定进程
硬盘名称检测 可以 可以 可以 修改驱动或者配置文件vmx
MAC地址检测 可以 可以 可以 修改MAC地址
CPUId检测 可以 不行 可以 未找到
特定服务检测 可以 可以 可以 卸载对应服务程序
特定文件检测 可以 可以 可以 修改特定文件
注册表检测 可以 可以 可以 修改特定注册表选项
IN特权指令 可以 不可以 不可以 未找到
IDT基址 不可以 不可以 不可以 未找到
LDT基址 不可以 不可以 不可以 未找到
GDT基址 不可以 不可以 不可以 未找到
STR 不可以 不可以 不可以 未找到

通过上表可以知道,三种虚拟机环境都可以检测的方法有

  • 特定进程名
  • 硬盘名
  • MAC地址
  • 注册表检测
  • 特定文件
  • 特定服务

特定进程名、硬盘名以及MAC地址这三种很容易反检测,不建议使用。注册表选项也很容易绕过,不建议。

最后剩下特定文件以及特定服务,经过实际测试发现,即使禁用掉特定服务,只要没有卸载掉服务程序,还是可以检测到的。一般来说,虚拟机提供的服务是为了方便与宿主机通讯的,共享文件的,卸载后会很麻烦。

最终结论,优先使用特定文件检测,具体检测文件可根据实际虚拟机环境来设定,其次使用特定服务检测。

上述每一种方法,均不能百分百保证检测正确,各位读者可根据具体情况来使用。

总结

本文搜集网上现有总结,并介绍基于进程、注册表键以及硬盘驱动器名称等多种检测虚拟机运行环境的方法,给出优先使用特定文件检测,其次检测特定后台服务的方案。

参考资料:

本文工程代码链接在此
软件如何判断自己运行在虚拟机中?
反虚拟机和沙箱检测的一些小技巧
sems
修改虚拟机中的硬盘ID等信息
[原创]虚拟机检测技术剖析
VMware | ESXi 等虚拟软件的反虚拟机检测技术方法探讨
VIrtual Machine Detection Techniques