描述
通常的主机具有有意义且非标准的用户名/计算机名称。特定的虚拟环境为默认用户分配一些预定义的名称以及计算机名称。主机操作系统和虚拟机之间的其他差异包括 RAM 大小、HDD 大小、监视器数量等。虽然这些可能不是检测虚拟环境的最可靠方法,但它们仍然常用于恶意软件样本。
1.检查用户名
检查用户名是否特定,需要检查的用户名如下:
产品 | 用户名 |
---|---|
常规 | admin andy honey john john doe malnetvm maltest malware roo sandbox snort tequilaboomboom test virus virusclone wilbert |
Nepenthes | nepenthes |
Norman | currentuser |
ThreatExpert | username |
Sandboxie | user |
VMware | vmware |
以GetUserNameA/W函数为例:
#include <windows.h>
#include <Lmcons.h>
// 定义一个恶意代码,例如弹出一个消息框
char code[] = "\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xFF\x15\x00\x00\x00\x00";
int main()
{
// 调用GetUserNameA/W函数,并传递一个指向缓冲区的指针和一个指向缓冲区大小的变量作为参数
char username[UNLEN + 1];
DWORD username_len = UNLEN + 1;
BOOL result = GetUserNameA(username, &username_len);
// 检查返回值是否为非零值,如果是,则表示获取了用户的登录名
if (result)
{
// 检查缓冲区中的字符串是否与特定字符串相同
if (strcmp(username, "Administrator") == 0)
{
// 如果缓冲区中的字符串与特定字符串相同,则不运行恶意代码,而是退出或执行其他操作
return 0;
}
else
{
// 如果缓冲区中的字符串与特定字符串不同,则继续运行恶意代码
// 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
*(DWORD*)(code + 1) = (DWORD)GetModuleHandleA("user32.dll");
*(DWORD*)(code + 6) = (DWORD)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
*(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
*(DWORD*)(code + 21) = (DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
// 执行修改后的恶意代码
((void(*)())(DWORD)code)();
}
}
else
{
// 如果获取用户的登录名失败,则可能表示没有权限或发生错误,也继续运行恶意代码
// 修改恶意代码中的地址,使其指向LoadLibraryA和MessageBoxA函数
*(DWORD*)(code + 1) = (DWORD)GetModuleHandleA("user32.dll");
*(DWORD*)(code + 6) = (DWORD)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
*(DWORD*)(code + 11) = (DWORD)"Hello from Malware!";
*(DWORD*)(code + 21) = (DWORD)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
// 执行修改后的恶意代码
((void(*)())(DWORD)code)();
}
return 0;
}
2.检查主机名和计算机名
恶意软件可以检测环境中的主机名和计算机名是否为特定值,如果是则不继续运行恶意代码,达到规避的目的。
以使用GetComputerNameA/W检查计算机名为例:
以使用GetComputerNameA/W检查计算机名为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个缓冲区和一个长度变量
char buffer[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
// 调用GetComputerNameA函数获取计算机名
BOOL result = GetComputerNameA(buffer, &size);
// 如果成功,将计算机名转换为小写并与特定的名称比较
if (result)
{
// 转换为小写
for (int i = 0; i < size; i++)
{
buffer[i] = tolower(buffer[i]);
}
// 比较计算机名
if (strcmp(buffer, "malware-analysis") == 0)
{
// 如果计算机名是malware-analysis,不运行恶意代码
printf("This is a malware analysis machine, aborting.\n");
return 0;
}
else
{
// 如果计算机名不是malware-analysis,运行恶意代码
printf("This is not a malware analysis machine, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetComputerNameA failed with error %d\n", GetLastError());
return -1;
}
}
以使用GetComputerNameExA/W函数检查主机名为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个缓冲区和一个长度变量
char buffer[256];
DWORD size = 256;
// 调用GetComputerNameExA函数获取完全限定的DNS名称
BOOL result = GetComputerNameExA(ComputerNameDnsFullyQualified, buffer, &size);
// 如果成功,将计算机名转换为小写并与特定的名称比较
if (result)
{
// 转换为小写
for (int i = 0; i < size; i++)
{
buffer[i] = tolower(buffer[i]);
}
// 比较计算机名
if (strcmp(buffer, "malware-analysis.example.com") == 0)
{
// 如果计算机名是malware-analysis.example.com,不运行恶意代码
printf("This is a malware analysis machine, aborting.\n");
return 0;
}
else
{
// 如果计算机名不是malware-analysis.example.com,运行恶意代码
printf("This is not a malware analysis machine, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetComputerNameExA failed with error %d\n", GetLastError());
return -1;
}
}
3.检查内存
恶意软件可以检查当前系统环境所使用物理内存和虚拟内存的信息,如果总内存过低则不继续运行恶意代码来达到规避的目的。
以GetMemoryStatusEx函数为例:
以GetMemoryStatusEx函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个结构体变量
MEMORYSTATUSEX statex;
// 设置结构体大小
statex.dwLength = sizeof(statex);
// 调用GetMemoryStatusEx函数获取内存信息
BOOL result = GlobalMemoryStatusEx(&statex);
// 如果成功,将内存信息打印出来,并判断是否过于低
if (result)
{
// 打印内存信息
printf("There is %ld percent of memory in use.\n", statex.dwMemoryLoad);
printf("There are %lld total KB of physical memory.\n", statex.ullTotalPhys / 1024);
printf("There are %lld free KB of physical memory.\n", statex.ullAvailPhys / 1024);
// 判断是否过于低,这里假设低于10%为过于低
if (statex.dwMemoryLoad > 90)
{
// 如果内存使用率超过90%,不运行恶意代码
printf("The memory is too low, aborting.\n");
return 0;
}
else
{
// 如果内存使用率低于90%,运行恶意代码
printf("The memory is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetMemoryStatusEx failed with error %d\n", GetLastError());
return -1;
}
}
以GlobalMemoryStatusEx函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个结构体变量
MEMORYSTATUSEX statex;
// 设置结构体大小
statex.dwLength = sizeof(statex);
// 调用GlobalMemoryStatusEx函数获取内存信息
BOOL result = GlobalMemoryStatusEx(&statex);
// 如果成功,将内存信息打印出来,并判断是否低
if (result)
{
// 打印内存信息
printf("There is %ld percent of memory in use.\n", statex.dwMemoryLoad);
printf("There are %lld total KB of physical memory.\n", statex.ullTotalPhys / 1024);
printf("There are %lld free KB of physical memory.\n", statex.ullAvailPhys / 1024);
// 判断是否低,这里假设低于1GB为低
if (statex.ullTotalPhys < 1024 * 1024 * 1024)
{
// 如果总RAM低于1GB,不运行恶意代码
printf("The total RAM is too low, aborting.\n");
return 0;
}
else
{
// 如果总RAM高于或等于1GB,运行恶意代码
printf("The total RAM is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("GlobalMemoryStatusEx failed with error %d\n", GetLastError());
return -1;
}
}
4.检查屏幕分辨率
恶意软件可以检查屏幕分辨率是否与主机操作系统不正常,如果不正常则不运行,以避免被虚拟机或沙盒环境检测。
以GetDesktopWindow函数为例:
以GetDesktopWindow函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个变量存储桌面窗口的句柄
HWND hDesktop;
// 调用GetDesktopWindow函数获取桌面窗口的句柄
hDesktop = GetDesktopWindow();
// 定义一个变量存储桌面窗口的矩形区域
RECT rect;
// 调用GetWindowRect函数获取桌面窗口的矩形区域
BOOL result = GetWindowRect(hDesktop, &rect);
// 如果成功,将矩形区域的宽度和高度打印出来,并判断是否不正常
if (result)
{
// 打印矩形区域的宽度和高度
printf("The width of the desktop window is %d.\n", rect.right - rect.left);
printf("The height of the desktop window is %d.\n", rect.bottom - rect.top);
// 判断是否不正常,这里假设低于800x600为不正常
if (rect.right - rect.left < 800 || rect.bottom - rect.top < 600)
{
// 如果分辨率低于800x600,不运行恶意代码
printf("The resolution is too low, aborting.\n");
return 0;
}
else
{
// 如果分辨率高于或等于800x600,运行恶意代码
printf("The resolution is normal, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetWindowRect failed with error %d\n", GetLastError());
return -1;
}
}
以EnumWindowsProc函数检查窗口名称是否是常见恶意软件分析工具存在的名称为例:
#include <windows.h>
#include <stdio.h>
// 定义一个回调函数
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
// 定义一个变量存储窗口标题
TCHAR szTitle[MAX_PATH] = { 0 };
// 调用GetWindowText函数获取窗口标题
GetWindowText(hWnd, szTitle, MAX_PATH);
// 定义一个数组存储常见恶意软件分析工具的名称
TCHAR* szTools[] = { L"Process Explorer", L"Process Monitor", L"Wireshark", L"OllyDbg", L"IDA Pro" };
// 定义一个变量存储数组长度
int nLength = sizeof(szTools) / sizeof(TCHAR*);
// 遍历数组,比较窗口标题和工具名称是否相同
for (int i = 0; i < nLength; i++)
{
if (lstrcmp(szTitle, szTools[i]) == 0)
{
// 如果相同,打印信息并返回FALSE,停止枚举
printf("Found analysis tool: %ws\n", szTitle);
return FALSE;
}
}
// 如果不相同,返回TRUE,继续枚举
return TRUE;
}
int main()
{
// 调用EnumWindows函数枚举所有顶级窗口,并传递回调函数和参数
BOOL result = EnumWindows(EnumWindowsProc, 0);
// 判断返回值
if (result)
{
// 如果返回TRUE,表示没有找到分析工具,运行恶意代码
printf("No analysis tool found, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
else
{
// 如果返回FALSE,表示找到了分析工具,不运行恶意代码
printf("Analysis tool detected, aborting.\n");
return 0;
}
}
以GetSystemMetrics函数检查屏幕分辨率是否与主机操作系统不正常为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义两个变量存储屏幕的宽度和高度
int nWidth, nHeight;
// 调用GetSystemMetrics函数获取屏幕的宽度和高度
nWidth = GetSystemMetrics(SM_CXSCREEN);
nHeight = GetSystemMetrics(SM_CYSCREEN);
// 打印屏幕的宽度和高度
printf("The width of the screen is %d.\n", nWidth);
printf("The height of the screen is %d.\n", nHeight);
// 判断是否不正常,这里假设低于800x600为不正常
if (nWidth < 800 || nHeight < 600)
{
// 如果分辨率低于800x600,不运行恶意代码
printf("The resolution is too low, aborting.\n");
return 0;
}
else
{
// 如果分辨率高于或等于800x600,运行恶意代码
printf("The resolution is normal, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
该函数还可以检查显示器数量是否过于少,如果少则不运行恶意代码的示例代码如下:
#include <windows.h>
#include <stdio.h>
int main()
{
// 调用GetSystemMetrics函数获取桌面上的显示监视器数
int nMonitorCount = GetSystemMetrics(SM_CMONITORS);
// 将显示器数量打印出来,并判断是否少
printf("The number of monitors in the system is %d.\n", nMonitorCount);
// 判断是否少,这里假设低于2为少
if (nMonitorCount < 2)
{
// 如果显示器数量低于2,不运行恶意代码
printf("The monitor number is too low, aborting.\n");
return 0;
}
else
{
// 如果显示器数量高于或等于2,运行恶意代码
printf("The monitor number is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
以SystemParametersInfo函数数检查屏幕分辨率是否与主机操作系统不正常为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义两个变量存储屏幕分辨率
int nWidth, nHeight;
// 调用SystemParametersInfo函数获取屏幕分辨率
nWidth = GetSystemMetrics(SM_CXSCREEN);
nHeight = GetSystemMetrics(SM_CYSCREEN);
// 打印屏幕分辨率
printf("The width of the screen is %d.\n", nWidth);
printf("The height of the screen is %d.\n", nHeight);
// 判断是否不正常,这里假设低于800x600为不正常
if (nWidth < 800 || nHeight < 600)
{
// 如果分辨率低于800x600,不运行恶意代码
printf("The resolution is too low, aborting.\n");
return 0;
}
else
{
// 如果分辨率高于或等于800x600,运行恶意代码
printf("The resolution is normal, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
以GetMonitorInfo函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个变量存储主显示监视器的句柄
HMONITOR hMonitor;
// 调用MonitorFromWindow函数获取主显示监视器的句柄
hMonitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY);
// 定义一个变量存储显示监视器的信息
MONITORINFO mi;
// 设置结构体大小
mi.cbSize = sizeof(mi);
// 调用GetMonitorInfo函数获取显示监视器的信息
BOOL result = GetMonitorInfo(hMonitor, &mi);
// 如果成功,将显示监视器的矩形区域和工作区域打印出来,并判断是否不正常
if (result)
{
// 打印显示监视器的矩形区域和工作区域
printf("The rectangle of the monitor is (%d, %d, %d, %d).\n", mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom);
printf("The work area of the monitor is (%d, %d, %d, %d).\n", mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
// 判断是否不正常,这里假设低于800x600为不正常
if (mi.rcMonitor.right - mi.rcMonitor.left < 800 || mi.rcMonitor.bottom - mi.rcMonitor.top < 600)
{
// 如果分辨率低于800x600,不运行恶意代码
printf("The resolution is too low, aborting.\n");
return 0;
}
else
{
// 如果分辨率高于或等于800x600,运行恶意代码
printf("The resolution is normal, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetMonitorInfo failed with error %d\n", GetLastError());
return -1;
}
}
5.检查处理器
恶意软件可以检查处理器数量是否不足,如果不足则不运行,以避免被虚拟机或沙盒环境检测。
以GetSystemInfo函数为例:
以GetSystemInfo函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个变量存储系统信息
SYSTEM_INFO si;
// 调用GetSystemInfo函数获取系统信息
GetSystemInfo(&si);
// 打印系统的处理器数量
printf("The number of processors in the system is %d.\n", si.dwNumberOfProcessors);
// 判断是否不足,这里假设低于2为不足
if (si.dwNumberOfProcessors < 2)
{
// 如果处理器数量低于2,不运行恶意代码
printf("The processor number is too low, aborting.\n");
return 0;
}
else
{
// 如果处理器数量高于或等于2,运行恶意代码
printf("The processor number is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
6.检查显示器数量
恶意软件可以检查显示器数量是否少,如果少则不运行,以避免被虚拟机或沙盒环境检测。
以EnumDisplayMonitors函数为例:
以EnumDisplayMonitors函数为例:
#include <windows.h>
#include <stdio.h>
// 定义一个全局变量存储显示器数量
int nMonitorCount = 0;
// 定义一个回调函数
BOOL CALLBACK EnumMonitorsProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
// 每次枚举一个显示器,就将显示器数量加一
nMonitorCount++;
// 返回TRUE,继续枚举
return TRUE;
}
int main()
{
// 调用EnumDisplayMonitors函数枚举所有显示监视器,并传递回调函数和参数
BOOL result = EnumDisplayMonitors(NULL, NULL, EnumMonitorsProc, 0);
// 如果成功,将显示器数量打印出来,并判断是否少
if (result)
{
// 打印显示器数量
printf("The number of monitors in the system is %d.\n", nMonitorCount);
// 判断是否少,这里假设低于2为少
if (nMonitorCount < 2)
{
// 如果显示器数量低于2,不运行恶意代码
printf("The monitor number is too low, aborting.\n");
return 0;
}
else
{
// 如果显示器数量高于或等于2,运行恶意代码
printf("The monitor number is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("EnumDisplayMonitors failed with error %d\n", GetLastError());
return -1;
}
}
7.检查硬盘和可用空间
恶意软件可以检查硬盘驱动器大小和可用空间是否较小,如果较小则不运行,以避免被虚拟机或沙盒环境检测。
以DeviceIoControl函数为例:
以DeviceIoControl函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 调用CreateFile函数打开物理驱动器0的句柄
HANDLE hDevice = CreateFileW(L"\\\\.\\PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
// 如果成功,继续执行
if (hDevice != INVALID_HANDLE_VALUE)
{
// 定义一个结构体变量存储磁盘空间信息
DISK_GEOMETRY_EX pDiskGeometry;
// 定义一个变量存储返回的字节数
DWORD bytesReturned;
// 调用DeviceIoControl函数发送IOCTL_DISK_GET_DRIVE_GEOMETRY_EX控制代码,获取磁盘空间信息
BOOL result = DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &pDiskGeometry, sizeof(pDiskGeometry), &bytesReturned, (LPOVERLAPPED)NULL);
// 如果成功,将磁盘空间信息打印出来,并判断是否较小
if (result)
{
// 判断是否较小,这里假设低于10GB为较小
if (pDiskGeometry.DiskSize.QuadPart < 10LL * 1024 * 1024 * 1024)
{
// 如果磁盘大小低于10GB,不运行恶意代码
printf("The disk size is too small, aborting.\n");
return 0;
}
else
{
// 如果磁盘大小高于或等于10GB,运行恶意代码
printf("The disk size is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("DeviceIoControl failed with error %d\n", GetLastError());
return -1;
}
}
else
{
// 如果失败,打印错误信息
printf("CreateFile failed with error %d\n", GetLastError());
return -1;
}
}
以GetDiskFreeSpaceExA/W函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义三个变量存储磁盘空间信息
ULARGE_INTEGER freeBytesAvailableToCaller;
ULARGE_INTEGER totalNumberOfBytes;
ULARGE_INTEGER totalNumberOfFreeBytes;
// 调用GetDiskFreeSpaceExA函数获取磁盘C:上的空间信息
BOOL result = GetDiskFreeSpaceExA("C:\\", &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes);
// 如果成功,将磁盘空间信息打印出来,并判断是否较小
if (result)
{
// 打印磁盘大小和可用空间
printf("The disk size is %lld bytes.\n", totalNumberOfBytes.QuadPart);
printf("The free space is %lld bytes.\n", totalNumberOfFreeBytes.QuadPart);
// 判断是否较小,这里假设低于10GB为较小
if (totalNumberOfBytes.QuadPart < 10LL * 1024 * 1024 * 1024)
{
// 如果磁盘大小低于10GB,不运行恶意代码
printf("The disk size is too small, aborting.\n");
return 0;
}
else
{
// 如果磁盘大小高于或等于10GB,运行恶意代码
printf("The disk size is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetDiskFreeSpaceExA failed with error %d\n", GetLastError());
return -1;
}
}
8.检查系统正常运行时间
恶意软件可以检查系统正常运行时间是否较小,如果较小则不运行,以避免被虚拟机或沙盒环境检测。
以GetTickCount函数为例:
以GetTickCount函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 调用GetTickCount函数获取自系统启动以来已用过的毫秒数
DWORD currentTime = GetTickCount();
// 将毫秒数转换为秒数,并打印出来
DWORD currentSeconds = currentTime / 1000;
printf("The system has been running for %d seconds.\n", currentSeconds);
// 判断是否较小,这里假设低于60秒为较小
if (currentSeconds < 60)
{
// 如果系统运行时间低于60秒,不运行恶意代码
printf("The system running time is too short, aborting.\n");
return 0;
}
else
{
// 如果系统运行时间高于或等于60秒,运行恶意代码
printf("The system running time is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
以GetTickCount64函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 调用GetTickCount64函数获取自系统启动以来已用过的毫秒数
ULONGLONG currentTime = GetTickCount64();
// 将毫秒数转换为秒数,并打印出来
ULONGLONG currentSeconds = currentTime / 1000;
printf("The system has been running for %lld seconds.\n", currentSeconds);
// 判断是否较小,这里假设低于60秒为较小
if (currentSeconds < 60)
{
// 如果系统运行时间低于60秒,不运行恶意代码
printf("The system running time is too short, aborting.\n");
return 0;
}
else
{
// 如果系统运行时间高于或等于60秒,运行恶意代码
printf("The system running time is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
以NtQuerySystemInformation函数为例:
#include <windows.h>
#include <stdio.h>
#include <winternl.h>
// 定义一个枚举类型表示系统信息类别
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45,
SystemPolicyInformation = 134,
SystemCodeIntegrityInformation = 103,
SystemKernelVaShadowInformation = 196,
SystemSpeculationControlInformation = 201,
SystemQueryPerformanceCounterInformation = 204
} SYSTEM_INFORMATION_CLASS;
// 定义一个结构体类型表示系统时间信息
typedef struct _SYSTEM_TIMEOFDAY_INFORMATION {
LARGE_INTEGER BootTime;
LARGE_INTEGER CurrentTime;
LARGE_INTEGER TimeZoneBias;
ULONG CurrentTimeZoneId;
} SYSTEM_TIMEOFDAY_INFORMATION, * PSYSTEM_TIMEOFDAY_INFORMATION;
// 定义一个函数指针类型表示NtQuerySystemInformation函数
typedef NTSTATUS(WINAPI* PFN_NT_QUERY_SYSTEM_INFORMATION)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
int main()
{
// 加载ntdll.dll模块
HMODULE hNtdll = LoadLibrary("ntdll.dll");
// 如果成功,继续执行
if (hNtdll != NULL)
{
// 获取NtQuerySystemInformation函数的地址
PFN_NT_QUERY_SYSTEM_INFORMATION pfnNtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFORMATION)GetProcAddress(hNtdll, "NtQuerySystemInformation");
// 如果成功,继续执行
if (pfnNtQuerySystemInformation != NULL)
{
// 定义一个变量存储系统时间信息
SYSTEM_TIMEOFDAY_INFORMATION systemTimeInfo;
// 定义一个变量存储返回的字节数
ULONG returnLength;
// 调用NtQuerySystemInformation函数获取系统时间信息
NTSTATUS status = pfnNtQuerySystemInformation(SystemTimeOfDayInformation, &systemTimeInfo, sizeof(systemTimeInfo), &returnLength);
// 如果成功,将系统时间信息打印出来,并判断是否较小
if (status == 0)
{
// 将启动时间转换为秒数,并打印出来
ULONGLONG bootSeconds = systemTimeInfo.BootTime.QuadPart / 10000000;
printf("The system has been running for %lld seconds.\n", bootSeconds);
// 判断是否较小,这里假设低于60秒为较小
if (bootSeconds < 60)
{
// 如果系统运行时间低于60秒,不运行恶意代码
printf("The system running time is too short, aborting.\n");
return 0;
}
else
{
// 如果系统运行时间高于或等于60秒,运行恶意代码
printf("The system running time is enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("NtQuerySystemInformation failed with status %d\n", status);
return -1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetProcAddress failed with error %d\n", GetLastError());
return -1;
}
}
else
{
// 如果失败,打印错误信息
printf("LoadLibrary failed with error %d\n", GetLastError());
return -1;
}
}
9.检查操作系统是否从虚拟硬盘启动
恶意软件可以检查操作系统是否从虚拟硬盘启动,如果是则不运行,以避免被虚拟机或沙盒环境检测。
以IsNativeVhdBoot函数为例:
以IsNativeVhdBoot函数为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个变量存储操作系统是否从VHD启动的布尔值
BOOL nativeVhdBoot;
// 调用IsNativeVhdBoot函数获取操作系统是否从VHD启动的信息
BOOL result = IsNativeVhdBoot(&nativeVhdBoot);
// 如果成功,将信息打印出来,并判断是否为真
if (result)
{
// 打印信息
printf("The OS was booted from a VHD container: %s\n", nativeVhdBoot ? "Yes" : "No");
// 判断是否为真
if (nativeVhdBoot)
{
// 如果操作系统从VHD启动,不运行恶意代码
printf("The OS is a native VHD boot, aborting.\n");
return 0;
}
else
{
// 如果操作系统不是从VHD启动,运行恶意代码
printf("The OS is not a native VHD boot, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("IsNativeVhdBoot failed with error %d\n", GetLastError());
return -1;
}
}
10.检索时区和区域
恶意软件可以检索当前主机的时区或区域来决定是否继续运行恶意代码,比如特定时区或特定地区运行。这种方法可以达到一定的规避几率。
以GetDynamicTimeZoneInformation函数检查时区设置,如果是特定时区则不运行为例:
以GetDynamicTimeZoneInformation函数检查时区设置,如果是特定时区则不运行为例:
#include <windows.h>
#include <stdio.h>
int main()
{
// 定义一个变量存储时区和夏令时信息
DYNAMIC_TIME_ZONE_INFORMATION timeZoneInfo;
// 调用GetDynamicTimeZoneInformation函数获取当前时区和夏令时设置
DWORD result = GetDynamicTimeZoneInformation(&timeZoneInfo);
// 如果成功,将时区名称打印出来,并判断是否为特定时区
if (result != TIME_ZONE_ID_INVALID)
{
// 打印时区名称
printf("The current time zone is %S\n", timeZoneInfo.StandardName);
// 判断是否为特定时区,这里假设北京时间为特定时区
if (wcscmp(timeZoneInfo.StandardName, L"China Standard Time") == 0)
{
// 如果当前时区是北京时间,不运行恶意代码
printf("The time zone is China Standard Time, aborting.\n");
return 0;
}
else
{
// 如果当前时区不是北京时间,运行恶意代码
printf("The time zone is not China Standard Time, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetDynamicTimeZoneInformation failed with error %d\n", GetLastError());
return -1;
}
}
以EnumSystemLocalesA函数检查区域设置,如果在特定区域则不运行为例:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
// 定义一个回调函数类型表示EnumSystemLocalesA函数的参数
typedef BOOL(CALLBACK* LOCALE_ENUMPROCA)(LPSTR);
// 定义一个全局变量存储是否在特定区域的标志
BOOL inSpecificLocale = FALSE;
// 定义一个回调函数,用于检查区域设置标识符是否为特定区域
BOOL CALLBACK CheckLocale(LPSTR lpLocaleString)
{
// 将字符串转换为整数
int localeID = atoi(lpLocaleString);
// 判断是否为特定区域,这里假设中国大陆为特定区域
if (localeID == 2052)
{
// 如果是特定区域,设置标志为真,并返回FALSE停止枚举
inSpecificLocale = TRUE;
return FALSE;
}
else
{
// 如果不是特定区域,返回TRUE继续枚举
return TRUE;
}
}
int main()
{
// 加载kernel32.dll模块
HMODULE hKernel32 = LoadLibrary(L"kernel32.dll");
// 如果成功,继续执行
if (hKernel32 != NULL)
{
// 获取EnumSystemLocalesA函数的地址
LOCALE_ENUMPROCA pfnEnumSystemLocalesA = (LOCALE_ENUMPROCA)GetProcAddress(hKernel32, "EnumSystemLocalesA");
// 如果成功,继续执行
if (pfnEnumSystemLocalesA != NULL)
{
// 调用EnumSystemLocalesA函数枚举所有支持的区域设置,并传递回调函数指针
BOOL result = pfnEnumSystemLocalesA((LPSTR)CheckLocale);
// 如果成功或者标志为真,判断是否在特定区域
if (result || inSpecificLocale)
{
// 判断是否在特定区域
if (inSpecificLocale)
{
// 如果在特定区域,不运行恶意代码
printf("The locale is in China, aborting.\n");
return 0;
}
else
{
// 如果不在特定区域,运行恶意代码
printf("The locale is not in China, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
}
else
{
// 如果失败,打印错误信息
printf("EnumSystemLocalesA failed with error %d\n", GetLastError());
return -1;
}
}
else
{
// 如果失败,打印错误信息
printf("GetProcAddress failed with error %d\n", GetLastError());
return -1;
}
}
else
{
// 如果失败,打印错误信息
printf("LoadLibrary failed with error %d\n", GetLastError());
return -1;
}
}
11.检索光标
恶意软件可以等待用户将鼠标移动特定距离,如果规定时间内鼠标没有移动则不运行,以避免被虚拟机或沙盒环境检测。
以GetCursorPos函数为例:
以GetCursorPos函数为例:
#include <windows.h>
#include <stdio.h>
#include <math.h>
int main()
{
// 定义一个变量存储初始光标位置
POINT initialCursorPos;
// 调用GetCursorPos函数获取初始光标位置
BOOL result = GetCursorPos(&initialCursorPos);
// 如果成功,继续执行
if (result)
{
// 打印初始光标位置
printf("The initial cursor position is (%d, %d)\n", initialCursorPos.x, initialCursorPos.y);
// 定义一个变量存储当前光标位置
POINT currentCursorPos;
// 定义一个变量存储开始时间
DWORD startTime = GetTickCount();
// 定义一个变量存储结束时间
DWORD endTime;
// 定义一个变量存储是否移动的标志
BOOL moved = FALSE;
// 定义一个常量存储规定时间(毫秒)
const DWORD TIME_LIMIT = 5000;
// 定义一个常量存储特定距离(像素)
const int DISTANCE_LIMIT = 100;
// 循环检查光标位置和时间
do
{
// 调用GetCursorPos函数获取当前光标位置
result = GetCursorPos(¤tCursorPos);
// 如果成功,继续执行
if (result)
{
// 计算光标移动的距离
int distance = sqrt(pow(currentCursorPos.x - initialCursorPos.x, 2) + pow(currentCursorPos.y - initialCursorPos.y, 2));
// 判断是否超过特定距离
if (distance > DISTANCE_LIMIT)
{
// 如果超过特定距离,设置移动标志为真,并退出循环
moved = TRUE;
break;
}
}
// 调用GetTickCount函数获取结束时间
endTime = GetTickCount();
// 判断是否超过规定时间
if (endTime - startTime > TIME_LIMIT)
{
// 如果超过规定时间,退出循环
break;
}
// 等待一段时间,避免占用过多CPU资源
Sleep(100);
} while (TRUE);
// 判断是否移动了光标
if (moved)
{
// 如果移动了光标,运行恶意代码
printf("The cursor has moved enough, executing.\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 1;
}
else
{
// 如果没有移动光标,不运行恶意代码
printf("The cursor has not moved enough, aborting.\n");
return 0;
}
}
else
{
// 如果失败,打印错误信息
printf("GetCursorPos failed with error %d\n", GetLastError());
return -1;
}
}
12.检索壁纸
利用Windows API函数来获取当前系统的桌面壁纸,然后与一些已知的沙箱环境的壁纸进行比较,如果匹配,则认为当前系统是沙箱,从而不执行恶意代码。这种技术可以绕过一些基于行为分析的反病毒技术,例如基于沙盒或虚拟机的检测方法。
#include <windows.h>
#define MAX_PATH 260
int main()
{
// 定义一个字符数组,用于存储桌面壁纸的路径
char wallpaper[MAX_PATH];
// 调用SystemParametersInfo函数,获取当前系统的桌面壁纸
SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaper, 0);
// 定义一个字符串数组,用于存储已知的沙箱环境的壁纸
char *sandbox_wallpapers[] = {
"C:\\windows\\system32\\wallpaper1.bmp",
"C:\\windows\\system32\\wallpaper2.bmp",
"C:\\windows\\system32\\wallpaper3.bmp",
// ...其他已知的沙箱壁纸
};
// 定义一个整数变量,用于存储已知的沙箱环境的壁纸的数量
int sandbox_wallpapers_count = sizeof(sandbox_wallpapers) / sizeof(char *);
// 遍历已知的沙箱环境的壁纸,与当前系统的桌面壁纸进行比较
for (int i = 0; i < sandbox_wallpapers_count; i++)
{
// 如果当前系统的桌面壁纸与某个已知的沙箱环境的壁纸相同,则认为当前系统是沙箱
if (lstrcmpi(wallpaper, sandbox_wallpapers[i]) == 0)
{
// 终止当前进程,并返回一个退出码
ExitProcess(0);
}
}
// 如果当前系统的桌面壁纸与所有已知的沙箱环境的壁纸都不同,则认为当前系统不是沙箱
// 在这里执行恶意代码
return 0;
}
也可以将已知沙箱壁纸计算为MD5,然后读取主机壁纸来进行比对HASH。