描述
该类别中会使用网络相关的函数,通过检测网络相关的功能和网络参数来判断是否在虚拟环境中,从而达到规避的目的。
1.检查MAC地址是否特定
需要检查的MAC地址是否为以下特定值:
产品 | MAC地址开头 | 字符串 |
---|---|---|
Parallels | 00:1C:42 | \x00\x1C\x42 |
VirtualBox | 08:00:27 | \x08\x00\x27 |
VMware | 00:05:69 00:0C:29 00:1C:14 00:50:56 | \x00\x05\x69 \x00\x0C\x29 \x00\x1C\x14 \x00\x50\x56 |
Xen | 00:16:E3 | \x00\x16\xE3 |
以GetAdaptersAddresses函数为例:
#include <windows.h>
#include <stdio.h>
#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")
// 定义要检查的MAC地址
#define MAC_COUNT 2
BYTE MAC_ADDRESSES[MAC_COUNT][6] = { {0x00, 0x0C, 0x29, 0x00, 0x00, 0x00}, // VMware
{0x08, 0x00, 0x27, 0x00, 0x00, 0x00} }; // VirtualBox
// 检查MAC地址是否特定
BOOL CheckMacAddress()
{
// 分配15KB缓冲区
ULONG ulOutBufLen = 15 * 1024;
PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)HeapAlloc(GetProcessHeap(), 0, ulOutBufLen);
// 获取适配器地址
ULONG dwRetVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &ulOutBufLen);
if (dwRetVal != ERROR_SUCCESS)
{
printf("GetAdaptersAddresses failed: %d\n", dwRetVal);
return FALSE;
}
// 遍历适配器地址
PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses;
while (pCurrAddresses)
{
// 获取当前适配器的MAC地址
BYTE MacAddress[6];
memcpy(MacAddress, pCurrAddresses->PhysicalAddress, sizeof(MacAddress));
// 遍历要检查的MAC地址
for (int i = 0; i < MAC_COUNT; i++)
{
// 如果当前适配器的MAC地址与要检查的MAC地址匹配,则返回真
if (memcmp(MacAddress, MAC_ADDRESSES[i], sizeof(MacAddress)) == 0)
{
return TRUE;
}
}
// 获取下一个适配器地址
pCurrAddresses = pCurrAddresses->Next;
}
// 没有找到特定的MAC地址,返回假
return FALSE;
}
int main()
{
// 检查MAC地址是否特定
BOOL bFound = CheckMacAddress();
if (bFound)
{
printf("Found specific MAC address, exit\n");
return 1;
}
printf("No specific MAC address found, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 0;
}
以GetAdaptersInfo函数为例:
#include <windows.h>
#include <stdio.h>
#include <iphlpapi.h>
// 定义要检查的MAC地址
#define MAC_COUNT 2
BYTE MAC_ADDRESSES[MAC_COUNT][6] = { {0x00, 0x0C, 0x29, 0x00, 0x00, 0x00}, // VMware
{0x08, 0x00, 0x27, 0x00, 0x00, 0x00} }; // VirtualBox
// 检查MAC地址是否特定
BOOL CheckMacAddress()
{
// 分配15KB缓冲区
ULONG ulOutBufLen = 15 * 1024;
PIP_ADAPTER_INFO pAdapterInfo = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, ulOutBufLen);
// 获取适配器信息
DWORD dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
if (dwRetVal != ERROR_SUCCESS)
{
printf("GetAdaptersInfo failed: %d\n", dwRetVal);
return FALSE;
}
// 遍历适配器信息
PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
while (pAdapter)
{
// 获取当前适配器的MAC地址
BYTE MacAddress[6];
memcpy(MacAddress, pAdapter->Address, sizeof(MacAddress));
// 遍历要检查的MAC地址
for (int i = 0; i < MAC_COUNT; i++)
{
// 如果当前适配器的MAC地址与要检查的MAC地址匹配,则返回真
if (memcmp(MacAddress, MAC_ADDRESSES[i], sizeof(MacAddress)) == 0)
{
return TRUE;
}
}
// 获取下一个适配器信息
pAdapter = pAdapter->Next;
}
// 没有找到特定的MAC地址,返回假
return FALSE;
}
int main()
{
// 检查MAC地址是否特定
BOOL bFound = CheckMacAddress();
if (bFound)
{
printf("Found specific MAC address, exit\n");
return 1;
}
printf("No specific MAC address found, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 0;
}
2.检查适配器名称是否特定
以GetAdaptersAddresses函数为例:
#include <windows.h>
#include <stdio.h>
#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")
// 定义要检查的适配器名称
#define ADAPTER_COUNT 2
LPCSTR ADAPTER_NAMES[ADAPTER_COUNT] = { "VMware Virtual Ethernet Adapter", "VirtualBox Host-Only Ethernet Adapter" };
// 检查适配器名称是否特定
BOOL CheckAdapterName()
{
// 分配15KB缓冲区
ULONG ulOutBufLen = 15 * 1024;
PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)HeapAlloc(GetProcessHeap(), 0, ulOutBufLen);
// 获取适配器地址
ULONG dwRetVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &ulOutBufLen);
if (dwRetVal != ERROR_SUCCESS)
{
printf("GetAdaptersAddresses failed: %d\n", dwRetVal);
return FALSE;
}
// 遍历适配器地址
PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses;
while (pCurrAddresses)
{
// 获取当前适配器的名称
LPCSTR AdapterName = pCurrAddresses->AdapterName;
// 遍历要检查的适配器名称
for (int i = 0; i < ADAPTER_COUNT; i++)
{
// 如果当前适配器的名称与要检查的适配器名称匹配,则返回真
if (strcmp(AdapterName, ADAPTER_NAMES[i]) == 0)
{
return TRUE;
}
}
// 获取下一个适配器地址
pCurrAddresses = pCurrAddresses->Next;
}
// 没有找到特定的适配器名称,返回假
return FALSE;
}
int main()
{
// 检查适配器名称是否特定
BOOL bFound = CheckAdapterName();
if (bFound)
{
printf("Found specific adapter name, exit\n");
return 1;
}
printf("No specific adapter name found, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 0;
}
以GetAdaptersInfo函数为例:
#include <windows.h>
#include <stdio.h>
#include <iphlpapi.h>
#pragma comment (lib, iphlpapi.lib)
// 定义要检查的适配器名称
#define ADAPTER_COUNT 2
LPCSTR ADAPTER_NAMES[ADAPTER_COUNT] = { "VMware Virtual Ethernet Adapter", "VirtualBox Host-Only Ethernet Adapter" };
// 检查适配器名称是否特定
BOOL CheckAdapterName()
{
// 分配15KB缓冲区
ULONG ulOutBufLen = 15 * 1024;
PIP_ADAPTER_INFO pAdapterInfo = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, ulOutBufLen);
// 获取适配器信息
DWORD dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
if (dwRetVal != ERROR_SUCCESS)
{
printf("GetAdaptersInfo failed: %d\n", dwRetVal);
return FALSE;
}
// 遍历适配器信息
PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
while (pAdapter)
{
// 获取当前适配器的名称
LPCSTR AdapterName = pAdapter->Description;
// 遍历要检查的适配器名称
for (int i = 0; i < ADAPTER_COUNT; i++)
{
// 如果当前适配器的名称与要检查的适配器名称匹配,则返回真
if (strcmp(AdapterName, ADAPTER_NAMES[i]) == 0)
{
return TRUE;
}
}
// 获取下一个适配器信息
pAdapter = pAdapter->Next;
}
// 没有找到特定的适配器名称,返回假
return FALSE;
}
int main()
{
// 检查适配器名称是否特定
BOOL bFound = CheckAdapterName();
if (bFound)
{
printf("Found specific adapter name, exit\n");
return 1;
}
printf("No specific adapter name found, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 0;
}
3.检查网络共享的提供商名称是否特定
以WNetGetProviderName函数为例:
#include <windows.h>
#include <stdio.h>
#include <winnetwk.h>
#pragma comment(lib, "Mpr.lib")
// 定义要检查的提供商名称
#define PROVIDER_COUNT 2
LPCSTR PROVIDER_NAMES[PROVIDER_COUNT] = { "Microsoft Windows Network", "Web Client Network" };
// 检查提供商名称是否特定
BOOL CheckProviderName()
{
// 分配256字节缓冲区
DWORD dwBufSize = 256;
LPSTR lpBuffer = (LPSTR)HeapAlloc(GetProcessHeap(), 0, dwBufSize);
// 分配256字节宽字符缓冲区
LPWSTR lpBufferW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwBufSize * sizeof(wchar_t));
// 获取本地计算机的提供商名称
DWORD dwRetVal = WNetGetProviderName(WNNC_NET_LANMAN, lpBufferW, &dwBufSize); // 使用宽字符缓冲区
if (dwRetVal != NO_ERROR)
{
printf("WNetGetProviderName failed: %d\n", dwRetVal);
return FALSE;
}
// 将宽字符缓冲区转换为多字节缓冲区
int iRet = WideCharToMultiByte(CP_ACP, 0, lpBufferW, -1, lpBuffer, dwBufSize, NULL, NULL);
if (iRet == 0)
{
printf("WideCharToMultiByte failed: %d\n", GetLastError());
return FALSE;
}
// 遍历要检查的提供商名称
for (int i = 0; i < PROVIDER_COUNT; i++)
{
// 如果本地计算机的提供商名称与要检查的提供商名称匹配,则返回真
if (strcmp(lpBuffer, PROVIDER_NAMES[i]) == 0)
{
return TRUE;
}
}
// 没有找到特定的提供商名称,返回假
return FALSE;
}
int main()
{
// 检查提供商名称是否特定
BOOL bFound = CheckProviderName();
if (bFound)
{
printf("Found specific provider name, exit\n");
return 1;
}
printf("No specific provider name found, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 0;
}
4.检查能否联网
以WinHttpOpen函数为例:
#include <windows.h>
#include <winhttp.h>
#include <stdio.h>
#pragma comment(lib, "Winhttp.lib")
// 定义要检查的目标URL
#define TARGET_URL L"www.baidu.com"
// 检查能否访问互联网连接
BOOL CheckInternetConnection()
{
// 初始化一个WinHTTP应用程序,并返回一个会话句柄
HINTERNET hSession = WinHttpOpen(L"User-Agent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession == NULL)
{
printf("WinHttpOpen failed: %d\n", GetLastError());
return FALSE;
}
// 指定要连接的服务器和端口号,并返回一个连接句柄
HINTERNET hConnect = WinHttpConnect(hSession, TARGET_URL, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL)
{
printf("WinHttpConnect failed: %d\n", GetLastError());
return FALSE;
}
// 创建一个HTTP请求句柄,并指定请求方法为GET
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL)
{
printf("WinHttpOpenRequest failed: %d\n", GetLastError());
return FALSE;
}
// 发送HTTP请求,并等待服务器响应
BOOL bResult = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
if (!bResult)
{
printf("WinHttpSendRequest failed: %d\n", GetLastError());
return FALSE;
}
// 接收服务器的响应头部,并获取响应状态码
bResult = WinHttpReceiveResponse(hRequest, NULL);
if (!bResult)
{
printf("WinHttpReceiveResponse failed: %d\n", GetLastError());
return FALSE;
}
DWORD dwStatusCode = 0;
DWORD dwSize = sizeof(dwStatusCode);
// 查询响应状态码
bResult = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwStatusCode, &dwSize, NULL);
if (!bResult)
{
printf("WinHttpQueryHeaders failed: %d\n", GetLastError());
return FALSE;
}
// 关闭所有句柄
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
// 如果响应状态码为200,表示能够访问互联网连接,返回真
if (dwStatusCode == 200)
{
return TRUE;
}
// 否则,表示不能访问互联网连接,返回假
return FALSE;
}
int main()
{
// 检查能否访问互联网连接
BOOL bConnected = CheckInternetConnection();
if (bConnected)
{
printf("Internet connection is available, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
return 0;
}
printf("Internet connection is not available, exit\n");
}
5.基于NetValidateName结果
通过带有无效参数的NetValidateName API 函数调用的结果作为服务器名称(例如“123”)来动态计算跳转地址。这种跳转通常指向某些指令的中间,以绕过反病毒软件。
但这项技术也有副作用,如果在操作系统中设置了默认的 NetBIOS 设置(如启用了 TCP/IP 上的 NetBIOS),则返回代码始终等于ERROR_BAD_NETPATH (0x35)。如果 TCP/IP 上的 NetBIOS 关闭,则返回代码为ERROR_NETWORK_UNREACHABLE (0x4CF)。这样跳转地址就会计算错误,导致样本崩溃。因此,此技术可用于破坏沙箱中的模拟环境,其中 TCP/IP 上的 NetBIOS 已关闭,以防止操作系统生成垃圾流量。
注意:通过 DNS 解析服务器 IP 时,TCP/IP 上的 NetBIOS 已关闭,以便不生成其他网络请求。关闭此选项将取消本地网络中的查找请求。
但这项技术也有副作用,如果在操作系统中设置了默认的 NetBIOS 设置(如启用了 TCP/IP 上的 NetBIOS),则返回代码始终等于ERROR_BAD_NETPATH (0x35)。如果 TCP/IP 上的 NetBIOS 关闭,则返回代码为ERROR_NETWORK_UNREACHABLE (0x4CF)。这样跳转地址就会计算错误,导致样本崩溃。因此,此技术可用于破坏沙箱中的模拟环境,其中 TCP/IP 上的 NetBIOS 已关闭,以防止操作系统生成垃圾流量。
注意:通过 DNS 解析服务器 IP 时,TCP/IP 上的 NetBIOS 已关闭,以便不生成其他网络请求。关闭此选项将取消本地网络中的查找请求。
void EntryPoint(void)
{
HANDLE NetApi32 = LoadLibraryW(L"netapi32.dll");
TD_NetValidateName NetValidateName = (TD_NetValidateName)GetProcAddress(NetApi32, "NetValidateName");
DWORD Result = NetValidateName(L"123", L"", L"", L"", 1);
__asm
{
call dword ptr ds:[GetLastError]
add eax, offset TrueEntryPoint
sub eax, 0xCB // ERROR_ENVVAR_NOT_FOUND
call eax
}
}
6.基于Cuckoo ResultServer连接
该技术可用于检测Cuckoo Sandbox虚拟环境。恶意软件可以枚举所有已建立的传出 TCP 连接,并检查是否存在与 Cuckoo ResultServer 使用的特定 TCP 端口 (2042) 的连接,如果存在则不运行即可规避。