Anti VM专题
5、通过服务信息检测虚拟机
一、课程目标
本节课主要学习如何通过检查Windows服务信息来检测虚拟机环境。虚拟机软件在安装和运行时会安装特定的系统服务,通过识别这些服务可以判断程序是否运行在虚拟机中。通过本课的学习,你将能够:
- 理解Windows服务机制和虚拟机相关服务特征
- 掌握枚举和查询系统服务的技术
- 学会识别虚拟机软件特有的服务名称和描述
- 实现基于服务信息的虚拟机检测代码
- 了解该技术的局限性和绕过方法
二、名词解释表
| 名词 | 解释 |
|---|---|
| 服务 | Windows操作系统中的后台运行程序 |
| SCM | Service Control Manager,服务控制管理器 |
| EnumServicesStatus | Windows API函数,用于枚举系统服务状态 |
| OpenSCManager | Windows API函数,用于打开服务控制管理器 |
| OpenService | Windows API函数,用于打开特定服务 |
| QueryServiceConfig | Windows API函数,用于查询服务配置信息 |
| 虚拟机服务 | 虚拟机软件安装时创建的系统服务 |
三、技术原理
3.1 服务检测概述
服务检测是通过枚举系统中运行的服务,检查其中是否包含虚拟机软件特有的服务来判断是否处于虚拟化环境。
3.2 常见虚拟机服务特征
不同虚拟机软件在安装时会创建特定的系统服务:
-
VMware相关服务:
- VMTools - VMware Tools服务
- VMware Physical Disk Helper Service
- VMware Alias Manager and Ticket Service
- VMware Workstation Server
-
VirtualBox相关服务:
- VBoxService - VirtualBox Guest Additions Service
- VBoxDrv - VirtualBox Service
-
Hyper-V相关服务:
- vmms - Hyper-V Virtual Machine Management
- vmcompute - Hyper-V Host Compute Service
- vmicguestinterface - Hyper-V Guest Service Interface
-
其他虚拟化软件:
- parallels - Parallels服务
- qemu - QEMU服务
3.3 检测原理
通过打开服务控制管理器,枚举系统中的所有服务,检查服务名称和描述是否匹配已知的虚拟机软件特征。
四、代码实现
4.1 基础服务检测
#include <windows.h>
#include <stdio.h>
// 虚拟机服务列表
struct VMService {
const char* serviceName;
const char* vendor;
};
VMService g_vmServices[] = {
{"VMTools", "VMware"},
{"VMware Physical Disk Helper Service", "VMware"},
{"VMware Alias Manager and Ticket Service", "VMware"},
{"VBoxService", "VirtualBox"},
{"VBoxDrv", "VirtualBox"},
{"vmms", "Hyper-V"},
{"vmcompute", "Hyper-V"},
{"vmicguestinterface", "Hyper-V"},
{"prl_svc", "Parallels"},
{"qemu-ga", "QEMU"}
};
// 检查服务是否存在
BOOL ServiceExists(const char* serviceName) {
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, GENERIC_READ);
if (hSCM == NULL) {
printf("无法打开服务控制管理器。\n");
return FALSE;
}
SC_HANDLE hService = OpenServiceA(hSCM, serviceName, SERVICE_QUERY_STATUS);
if (hService != NULL) {
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return TRUE;
}
CloseServiceHandle(hSCM);
return FALSE;
}
// 基础服务检测
BOOL DetectVMViaServices() {
printf("=== 基础服务检测 ===\n");
BOOL vmDetected = FALSE;
// 检查已知的虚拟机服务
for (int i = 0; i < sizeof(g_vmServices) / sizeof(g_vmServices[0]); i++) {
if (ServiceExists(g_vmServices[i].serviceName)) {
printf("检测到虚拟机服务: %s (%s)\n", g_vmServices[i].serviceName, g_vmServices[i].vendor);
vmDetected = TRUE;
}
}
return vmDetected;
}
4.2 改进的服务检测
// 获取服务显示名称
BOOL GetServiceDisplayName(SC_HANDLE hSCM, const char* serviceName, char* displayName, DWORD bufferSize) {
DWORD displayNameSize = bufferSize;
DWORD serviceType = SERVICE_WIN32;
if (GetServiceDisplayNameA(hSCM, serviceName, displayName, &displayNameSize)) {
return TRUE;
}
return FALSE;
}
// 获取服务配置信息
BOOL GetServiceConfigInfo(SC_HANDLE hSCM, const char* serviceName) {
SC_HANDLE hService = OpenServiceA(hSCM, serviceName, SERVICE_QUERY_CONFIG);
if (hService == NULL) {
return FALSE;
}
LPQUERY_SERVICE_CONFIGA lpServiceConfig = NULL;
DWORD dwBytesNeeded = 0;
// 第一次调用获取所需缓冲区大小
if (!QueryServiceConfigA(hService, NULL, 0, &dwBytesNeeded) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)LocalAlloc(LPTR, dwBytesNeeded);
if (lpServiceConfig != NULL) {
if (QueryServiceConfigA(hService, lpServiceConfig, dwBytesNeeded, &dwBytesNeeded)) {
printf(" 二进制路径: %s\n", lpServiceConfig->lpBinaryPathName);
printf(" 显示名称: %s\n", lpServiceConfig->lpDisplayName);
printf(" 启动类型: %lu\n", lpServiceConfig->dwStartType);
printf(" 服务类型: %lu\n", lpServiceConfig->dwServiceType);
// 检查二进制路径中是否包含虚拟机相关关键词
char lowerPath[MAX_PATH];
strcpy_s(lowerPath, lpServiceConfig->lpBinaryPathName);
for (int i = 0; lowerPath[i]; i++) {
lowerPath[i] = tolower(lowerPath[i]);
}
const char* vmKeywords[] = {
"vmware", "virtualbox", "vbox", "hyper-v", "hyperv",
"parallels", "qemu", "virtual"
};
for (int i = 0; i < sizeof(vmKeywords) / sizeof(vmKeywords[0]); i++) {
if (strstr(lowerPath, vmKeywords[i]) != NULL) {
printf(" 检测到虚拟机相关路径关键词: %s\n", vmKeywords[i]);
LocalFree(lpServiceConfig);
CloseServiceHandle(hService);
return TRUE;
}
}
}
LocalFree(lpServiceConfig);
}
}
CloseServiceHandle(hService);
return FALSE;
}
// 改进的服务检测
BOOL ImprovedVMServiceDetection() {
printf("=== 改进版服务检测 ===\n");
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | GENERIC_READ);
if (hSCM == NULL) {
printf("无法打开服务控制管理器。\n");
return FALSE;
}
DWORD bytesNeeded = 0;
DWORD servicesReturned = 0;
DWORD resumeHandle = 0;
// 第一次调用获取所需缓冲区大小
EnumServicesStatusA(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &bytesNeeded, &servicesReturned, &resumeHandle);
if (GetLastError() != ERROR_MORE_DATA) {
CloseServiceHandle(hSCM);
return FALSE;
}
// 分配内存
LPENUM_SERVICE_STATUSA lpServices = (LPENUM_SERVICE_STATUSA)LocalAlloc(LPTR, bytesNeeded);
if (lpServices == NULL) {
CloseServiceHandle(hSCM);
return FALSE;
}
// 第二次调用获取服务信息
if (!EnumServicesStatusA(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, lpServices, bytesNeeded, &bytesNeeded, &servicesReturned, &resumeHandle)) {
LocalFree(lpServices);
CloseServiceHandle(hSCM);
return FALSE;
}
BOOL vmDetected = FALSE;
// 遍历所有服务
for (DWORD i = 0; i < servicesReturned; i++) {
printf("服务名称: %s\n", lpServices[i].lpServiceName);
printf("显示名称: %s\n", lpServices[i].lpDisplayName);
// 检查服务名称是否匹配已知的虚拟机服务
for (int j = 0; j < sizeof(g_vmServices) / sizeof(g_vmServices[0]); j++) {
if (_stricmp(lpServices[i].lpServiceName, g_vmServices[j].serviceName) == 0) {
printf("检测到虚拟机服务: %s (%s)\n", g_vmServices[j].serviceName, g_vmServices[j].vendor);
vmDetected = TRUE;
}
}
// 检查服务显示名称中是否包含虚拟机相关关键词
char lowerDisplayName[MAX_PATH];
strcpy_s(lowerDisplayName, lpServices[i].lpDisplayName);
for (int j = 0; lowerDisplayName[j]; j++) {
lowerDisplayName[j] = tolower(lowerDisplayName[j]);
}
const char* vmKeywords[] = {
"vmware", "virtualbox", "vbox", "hyper-v", "hyperv",
"parallels", "qemu", "virtual", "guest"
};
for (int j = 0; j < sizeof(vmKeywords) / sizeof(vmKeywords[0]); j++) {
if (strstr(lowerDisplayName, vmKeywords[j]) != NULL) {
printf("检测到虚拟机相关显示名称关键词: %s\n", vmKeywords[j]);
vmDetected = TRUE;
}
}
// 获取服务详细配置信息
if (GetServiceConfigInfo(hSCM, lpServices[i].lpServiceName)) {
vmDetected = TRUE;
}
printf("\n");
}
LocalFree(lpServices);
CloseServiceHandle(hSCM);
return vmDetected;
}
4.3 高级服务检测技术
// 检查服务状态
BOOL CheckServiceStatus(const char* serviceName) {
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, GENERIC_READ);
if (hSCM == NULL) {
return FALSE;
}
SC_HANDLE hService = OpenServiceA(hSCM, serviceName, SERVICE_QUERY_STATUS);
if (hService != NULL) {
SERVICE_STATUS serviceStatus;
if (QueryServiceStatus(hService, &serviceStatus)) {
printf("服务 %s 状态: ", serviceName);
switch (serviceStatus.dwCurrentState) {
case SERVICE_RUNNING:
printf("运行中\n");
break;
case SERVICE_STOPPED:
printf("已停止\n");
break;
case SERVICE_START_PENDING:
printf("启动中\n");
break;
case SERVICE_STOP_PENDING:
printf("停止中\n");
break;
default:
printf("其他状态 (%lu)\n", serviceStatus.dwCurrentState);
break;
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return TRUE;
}
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCM);
return FALSE;
}
// 检查服务特征
BOOL CheckServiceCharacteristics() {
printf("=== 服务特征检查 ===\n");
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | GENERIC_READ);
if (hSCM == NULL) {
return FALSE;
}
DWORD bytesNeeded = 0;
DWORD servicesReturned = 0;
DWORD resumeHandle = 0;
// 获取服务信息
EnumServicesStatusA(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &bytesNeeded, &servicesReturned, &resumeHandle);
if (GetLastError() != ERROR_MORE_DATA) {
CloseServiceHandle(hSCM);
return FALSE;
}
LPENUM_SERVICE_STATUSA lpServices = (LPENUM_SERVICE_STATUSA)LocalAlloc(LPTR, bytesNeeded);
if (lpServices == NULL) {
CloseServiceHandle(hSCM);
return FALSE;
}
if (!EnumServicesStatusA(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, lpServices, bytesNeeded, &bytesNeeded, &servicesReturned, &resumeHandle)) {
LocalFree(lpServices);
CloseServiceHandle(hSCM);
return FALSE;
}
BOOL vmDetected = FALSE;
// 统计服务数量
printf("系统中共有 %lu 个服务。\n", servicesReturned);
// 在虚拟机环境中,服务数量通常较少
if (servicesReturned < 50) {
printf("服务数量异常少,可能是虚拟机环境。\n");
vmDetected = TRUE;
}
// 检查服务名称模式
int vmServiceCount = 0;
for (DWORD i = 0; i < servicesReturned; i++) {
// 检查服务名称是否以vm开头
if (_strnicmp(lpServices[i].lpServiceName, "vm", 2) == 0) {
printf("发现vm开头服务: %s\n", lpServices[i].lpServiceName);
vmServiceCount++;
}
// 检查服务名称是否包含virtual
char lowerServiceName[MAX_PATH];
strcpy_s(lowerServiceName, lpServices[i].lpServiceName);
for (int j = 0; lowerServiceName[j]; j++) {
lowerServiceName[j] = tolower(lowerServiceName[j]);
}
if (strstr(lowerServiceName, "virtual") != NULL) {
printf("发现virtual相关服务: %s\n", lpServices[i].lpServiceName);
vmServiceCount++;
}
}
if (vmServiceCount > 0) {
printf("发现 %d 个虚拟化相关服务。\n", vmServiceCount);
vmDetected = TRUE;
}
LocalFree(lpServices);
CloseServiceHandle(hSCM);
return vmDetected;
}
// 检查驱动服务
BOOL CheckDriverServices() {
printf("=== 驱动服务检查 ===\n");
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | GENERIC_READ);
if (hSCM == NULL) {
return FALSE;
}
DWORD bytesNeeded = 0;
DWORD servicesReturned = 0;
DWORD resumeHandle = 0;
// 枚举驱动服务
EnumServicesStatusA(hSCM, SERVICE_DRIVER, SERVICE_STATE_ALL, NULL, 0, &bytesNeeded, &servicesReturned, &resumeHandle);
if (GetLastError() != ERROR_MORE_DATA) {
CloseServiceHandle(hSCM);
return FALSE;
}
LPENUM_SERVICE_STATUSA lpServices = (LPENUM_SERVICE_STATUSA)LocalAlloc(LPTR, bytesNeeded);
if (lpServices == NULL) {
CloseServiceHandle(hSCM);
return FALSE;
}
if (!EnumServicesStatusA(hSCM, SERVICE_DRIVER, SERVICE_STATE_ALL, lpServices, bytesNeeded, &bytesNeeded, &servicesReturned, &resumeHandle)) {
LocalFree(lpServices);
CloseServiceHandle(hSCM);
return FALSE;
}
BOOL vmDetected = FALSE;
// 检查驱动服务名称
for (DWORD i = 0; i < servicesReturned; i++) {
const char* driverKeywords[] = {
"vmware", "vbox", "virtualbox", "hyper-v", "hyperv",
"parallels", "qemu"
};
for (int j = 0; j < sizeof(driverKeywords) / sizeof(driverKeywords[0]); j++) {
if (strstr(lpServices[i].lpServiceName, driverKeywords[j]) != NULL) {
printf("检测到虚拟机驱动服务: %s\n", lpServices[i].lpServiceName);
vmDetected = TRUE;
}
}
}
LocalFree(lpServices);
CloseServiceHandle(hSCM);
return vmDetected;
}
// 综合服务检测
BOOL ComprehensiveServiceDetection() {
printf("=== 综合服务检测 ===\n");
BOOL result1 = DetectVMViaServices();
BOOL result2 = ImprovedVMServiceDetection();
BOOL result3 = CheckServiceCharacteristics();
BOOL result4 = CheckDriverServices();
return result1 || result2 || result3 || result4;
}
4.4 反虚拟机实现
// 简单的服务反虚拟机检测
VOID SimpleServiceAntiVM() {
if (ComprehensiveServiceDetection()) {
printf("通过服务信息检测到虚拟机环境!程序即将退出。\n");
ExitProcess(1);
}
}
// 多层次服务检测
BOOL MultiLayerServiceDetection() {
// 第一层:基础检测
if (DetectVMViaServices()) {
return TRUE;
}
// 第二层:改进检测
if (ImprovedVMServiceDetection()) {
return TRUE;
}
// 第三层:特征检查
if (CheckServiceCharacteristics()) {
return TRUE;
}
// 第四层:驱动服务检查
if (CheckDriverServices()) {
return TRUE;
}
return FALSE;
}
// 增强版反虚拟机检测
VOID EnhancedServiceAntiVM() {
// 多次检测
for (int i = 0; i < 3; i++) {
if (MultiLayerServiceDetection()) {
printf("第%d次服务检测发现虚拟机环境!\n", i + 1);
// 随机化响应
int response = rand() % 4;
switch (response) {
case 0:
ExitProcess(0);
case 1:
printf("发生未知错误。\n");
Sleep(5000);
exit(1);
case 2:
// 执行错误指令
__debugbreak();
case 3:
// 进入无限循环
while (1) {
Sleep(1000);
}
}
}
// 随机延迟
Sleep(rand() % 100 + 50);
}
printf("服务反虚拟机检测通过。\n");
}
4.5 绕过服务检测的方法
// 服务检测绕过技术
class ServiceObfuscator {
public:
// 停止虚拟机相关服务
static BOOL StopVMService(const char* serviceName) {
printf("停止虚拟机服务: %s...\n", serviceName);
// 实际应用中需要管理员权限
// 这里仅作为概念演示
return FALSE;
}
// 重命名虚拟机服务
static BOOL RenameVMService(const char* oldName, const char* newName) {
printf("重命名虚拟机服务: %s -> %s...\n", oldName, newName);
// 需要管理员权限和复杂的服务管理操作
return FALSE;
}
// 创建虚假服务
static BOOL CreateFakeService() {
printf("创建虚假服务...\n");
// 创建看起来像正常系统服务的服务来混淆检测
return FALSE;
}
};
// 综合绕过方法
VOID ComprehensiveServiceBypass() {
// 停止虚拟机相关服务
ServiceObfuscator::StopVMService("VMTools");
// 重命名虚拟机服务
ServiceObfuscator::RenameVMService("VBoxService", "SystemService");
// 创建虚假服务
ServiceObfuscator::CreateFakeService();
printf("服务检测绕过完成。\n");
}
4.6 完整测试程序
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 前面实现的函数声明
BOOL DetectVMViaServices();
BOOL ImprovedVMServiceDetection();
BOOL CheckServiceCharacteristics();
BOOL CheckDriverServices();
BOOL MultiLayerServiceDetection();
// 显示系统服务信息
VOID DisplaySystemServiceInfo() {
printf("=== 系统服务信息 ===\n");
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, GENERIC_READ);
if (hSCM != NULL) {
DWORD bytesNeeded = 0;
DWORD servicesReturned = 0;
DWORD resumeHandle = 0;
// 获取服务数量
EnumServicesStatusA(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &bytesNeeded, &servicesReturned, &resumeHandle);
if (GetLastError() == ERROR_MORE_DATA) {
printf("系统中共有 %lu 个Win32服务。\n", servicesReturned);
}
// 获取驱动服务数量
EnumServicesStatusA(hSCM, SERVICE_DRIVER, SERVICE_STATE_ALL, NULL, 0, &bytesNeeded, &servicesReturned, &resumeHandle);
if (GetLastError() == ERROR_MORE_DATA) {
printf("系统中共有 %lu 个驱动服务。\n", servicesReturned);
}
CloseServiceHandle(hSCM);
}
printf("\n");
}
// 性能测试
VOID PerformanceTest() {
const int iterations = 5;
printf("=== 性能测试 (%d次调用) ===\n", iterations);
// 测试基础服务检测
DWORD start = GetTickCount();
for (int i = 0; i < iterations; i++) {
DetectVMViaServices();
Sleep(100);
}
DWORD basicTime = GetTickCount() - start;
// 测试改进版检测
start = GetTickCount();
for (int i = 0; i < iterations; i++) {
ImprovedVMServiceDetection();
Sleep(100);
}
DWORD improvedTime = GetTickCount() - start;
printf("基础服务检测耗时: %lu ms\n", basicTime);
printf("改进版服务检测耗时: %lu ms\n", improvedTime);
printf("\n");
}
// 主程序
int main() {
srand((unsigned int)time(NULL));
printf("通过服务信息检测虚拟机演示程序\n");
printf("=========================\n\n");
// 显示系统服务信息
DisplaySystemServiceInfo();
// 基础服务检测
DetectVMViaServices();
// 改进版检测
ImprovedVMServiceDetection();
// 特征检查
CheckServiceCharacteristics();
// 驱动服务检查
CheckDriverServices();
// 性能测试
PerformanceTest();
// 实际应用示例
printf("=== 反虚拟机检测 ===\n");
if (MultiLayerServiceDetection()) {
printf("检测到虚拟机环境,执行反虚拟机措施。\n");
// 这里可以执行各种反虚拟机措施
// 为演示目的,我们只是显示信息而不真正退出
printf("(演示模式:不实际退出程序)\n");
} else {
printf("未检测到虚拟机环境,程序正常运行。\n");
MessageBoxW(NULL, L"服务检测通过,程序正常运行", L"提示", MB_OK);
}
// 演示绕过方法
printf("\n=== 绕过演示 ===\n");
printf("执行服务绕过...\n");
// ComprehensiveServiceBypass(); // 注释掉以避免实际修改系统
printf("绕过完成后再次检测:\n");
if (MultiLayerServiceDetection()) {
printf("仍然检测到虚拟机环境。\n");
} else {
printf("检测结果显示未发现服务异常。\n");
}
return 0;
}
4.7 高级技巧和注意事项
// 抗干扰版本(防止简单的Hook)
BOOL AntiTamperServiceDetection() {
// 多次调用并验证
BOOL results[3];
for (int i = 0; i < 3; i++) {
results[i] = MultiLayerServiceDetection();
Sleep(10); // 简短延迟
}
// 检查结果一致性
for (int i = 1; i < 3; i++) {
if (results[i] != results[0]) {
// 结果不一致,可能是被干扰了
return TRUE; // 假设存在虚拟机环境
}
}
return results[0];
}
// 综合检测函数
BOOL ComprehensiveServiceDetectionEnhanced() {
// 抗干扰检测
if (AntiTamperServiceDetection()) {
return TRUE;
}
// 多层检测
if (MultiLayerServiceDetection()) {
return TRUE;
}
return FALSE;
}
// 动态获取服务API地址(避免静态导入)
FARPROC GetDynamicServiceAPIAddress(LPCSTR functionName) {
// 动态加载advapi32.dll
HMODULE hAdvapi32 = GetModuleHandle(L"advapi32.dll");
if (hAdvapi32 == NULL) {
return NULL;
}
// 获取函数地址
FARPROC pfn = GetProcAddress(hAdvapi32, functionName);
return pfn;
}
// 检查服务API调用的完整性
BOOL ValidateServiceAPICall() {
// 可以通过检查相关函数代码的完整性来验证未被修改
// 这需要更高级的技术,如代码校验和检查
return TRUE;
}
// 多线程环境下的服务检测
BOOL MultiThreadServiceDetection() {
printf("=== 多线程服务检测 ===\n");
// 在多线程环境中进行检测可以增加检测的可靠性
return FALSE;
}
五、课后作业
-
基础练习:
- 在不同的虚拟机软件中测试服务检测的准确性
- 研究更多虚拟机软件的服务特征
- 实现对服务信息的完整验证
-
进阶练习:
- 实现一个完整的服务行为监控器
- 研究如何通过API Hook绕过服务检测
- 设计一个多层检测机制,结合服务信息和其他反虚拟机技术
-
思考题:
- 服务检测方法有哪些明显的局限性?
- 如何提高服务检测的准确性和隐蔽性?
- 现代虚拟机采用了哪些技术来对抗服务检测?
-
扩展阅读:
- 研究Windows服务机制
- 了解服务隐藏技术
- 学习现代反虚拟机技术