网络

描述

该类别中会使用网络相关的函数,通过检测网络相关的功能和网络参数来判断是否在虚拟环境中,从而达到规避的目的。

1.检查MAC地址是否特定

需要检查的MAC地址是否为以下特定值:
产品MAC地址开头字符串
Parallels00:1C:42\x00\x1C\x42
VirtualBox08:00:27\x08\x00\x27
VMware00:05:69
00:0C:29
00:1C:14
00:50:56
\x00\x05\x69
\x00\x0C\x29
\x00\x1C\x14
\x00\x50\x56
Xen00: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 已关闭,以便不生成其他网络请求。关闭此选项将取消本地网络中的查找请求。
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) 的连接,如果存在则不运行即可规避。