0x2 虚拟机检测

  • 虚拟机检测的针对性很强,时效性也很强,这里只是简单的介绍一个作为例子
  • 虚拟机检测核心无外乎以下几点:

    • 设备
    • 驱动
    • 硬件
    • 虚拟指令
  • TRUE:表示检测到调试

0x2.1 mac检测

  • 虚拟机的mac地址一般都有特殊的标志头
  • 这个标志头是全球mac联盟分配的,一般不会变
  • 这里列举vb的mac检测方式
  • vb的mac地址是以08:00:27开头
//获取并且比对mac地址
BOOL check_mac_addr(const TCHAR* szMac)
{
    BOOL bResult = FALSE;
    PIP_ADAPTER_INFO pAdapterInfo, pAdapterInfoPtr;
    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);

    pAdapterInfo = (PIP_ADAPTER_INFO)MALLOC(sizeof(IP_ADAPTER_INFO));
    if (pAdapterInfo == NULL)
    {
        _tprintf(_T("Error allocating memory needed to call GetAdaptersinfo.\n"));
        return -1;
    }

    DWORD dwResult = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);

    // 获取 ulOutBufLen 需要的长度
    if (dwResult == ERROR_BUFFER_OVERFLOW)
    {
        FREE(pAdapterInfo);
        pAdapterInfo = (PIP_ADAPTER_INFO)MALLOC(ulOutBufLen);
        if (pAdapterInfo == NULL) {
            printf("Error allocating memory needed to call GetAdaptersinfo\n");
            return 1;
        }

        // 获取网卡信息
        dwResult = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
    }

    if (dwResult == ERROR_SUCCESS)
    {
        // 将mac转换成字符串比较
        CHAR szMacMultiBytes[4];
        for (int i = 0; i < 4; i++) {
            szMacMultiBytes[i] = (CHAR)szMac[i];
        }

        pAdapterInfoPtr = pAdapterInfo;

        while (pAdapterInfoPtr)
        {

            if (pAdapterInfoPtr->AddressLength == 6 && !memcmp(szMacMultiBytes, pAdapterInfoPtr->Address, 3))
            {
                bResult = TRUE;
                break;
            }
            pAdapterInfoPtr = pAdapterInfoPtr->Next;
        }
    }

    FREE(pAdapterInfo);

    return bResult;
}


BOOL vbox_check_mac()
{
    // VirtualBox 的mac 地址 由 PCS Systemtechnik CmbH 公司提供
    return check_mac_addr(_T("\x08\x00\x27"));
}

0x2.2 窗口检测

  • 虚拟机内一般会运行固定的软件:

    • 调试器
    • vmtools
    • vbtools
  • 检测这些特殊的窗口也可在以为标志
BOOL vbox_window_class()
{
    //检测特殊的窗口
    HWND hClass = FindWindow(_T("VBoxTrayToolWndClass"), NULL);
    HWND hWindow = FindWindow(NULL, _T("VBoxTrayToolWnd"));
    //只要有一个就算是虚拟机
    if (hClass || hWindow)
        return TRUE;
    else
        return FALSE;
}

0x2.3 硬盘检测

  • 虚拟磁盘需要windows加载专属的驱动才能识别
  • 驱动中内置了硬盘的类别
  • 通过字符串比较 硬盘类别可以判断是否存在虚拟磁盘
  • 本质上检测是否挂载了虚拟磁盘
// 本质上是检测注册表:HKLM\System\CurrentControlSet\Services\Disk\Enum
BOOL registry_services_disk_enum()
{
    HKEY hkResult = NULL;
    const TCHAR* diskEnumKey = _T("System\\CurrentControlSet\\Services\\Disk\\Enum");
    DWORD diskCount = 0;
    DWORD cbData = sizeof(diskCount);
    const TCHAR* szChecks[] = {
        /* 
        关键字 
        * https://research.checkpoint.com/2019-resurgence-of-smokeloader
        */
         _T("qemu"),
         _T("virtio"),
         _T("vmware"),
         _T("vbox"),
         _T("xen"),

         /* 
         关键字 
         https://cofense.com/kutaki-malware-bypasses-gateways-steal-users-credentials/ 
         */
        _T("VMW"),
        _T("Virtual"),

    };
    WORD dwChecksLength = sizeof(szChecks) / sizeof(szChecks[0]);
    BOOL bFound = FALSE;

    //没有记录就退出

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, diskEnumKey, NULL, KEY_READ, &hkResult) == ERROR_SUCCESS)
    {
        if (RegQueryValueEx(hkResult, _T("Count"), NULL, NULL, (LPBYTE)&diskCount, &cbData) != ERROR_SUCCESS)
        {
            RegCloseKey(hkResult);
            return bFound;
        }
        RegCloseKey(hkResult);
    }

    for (unsigned int i = 0; i < diskCount; i++) {
        TCHAR subkey[11];

        _stprintf_s(subkey, sizeof(subkey) / sizeof(subkey[0]), _T("%d"), i);
        //检测是否存在关键字
        for (unsigned int j = 0; j < dwChecksLength; j++) {
            if (Is_RegKeyValueExists(HKEY_LOCAL_MACHINE, diskEnumKey, subkey, szChecks[j])) {
                bFound = TRUE;
                break;
            }
        }
        if (bFound) {
            break;
        }
    }
    return bFound;
}

0x2.4 设备检查

  • 虚拟机一般会虚拟出一些专用的硬件设备用于通信
//vb的一些特殊设备
VOID vbox_devices()
{
    const TCHAR *devices[] = {
        _T("\\\\.\\VBoxMiniRdrDN"),
        _T("\\\\.\\VBoxGuest"),
        _T("\\\\.\\pipe\\VBoxMiniRdDN"),
        _T("\\\\.\\VBoxTrayIPC"),
        _T("\\\\.\\pipe\\VBoxTrayIPC")
    };

    WORD iLength = sizeof(devices) / sizeof(devices[0]);
    for (int i = 0; i < iLength; i++)
    {
        HANDLE hFile = CreateFile(devices[i], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        TCHAR msg[256] = _T("");
        _stprintf_s(msg, sizeof(msg) / sizeof(TCHAR), _T("Checking device %s "), devices[i]);
        if (hFile != INVALID_HANDLE_VALUE) {
            CloseHandle(hFile);
            print_results(TRUE, msg);
        }
        else
            print_results(FALSE, msg);
    }
}


//vmware的设备
VOID vmware_devices()
{
    const TCHAR *devices[] = {
        _T("\\\\.\\HGFS"),
        _T("\\\\.\\vmci"),
    };

    WORD iLength = sizeof(devices) / sizeof(devices[0]);
    for (int i = 0; i < iLength; i++)
    {
        HANDLE hFile = CreateFile(devices[i], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        TCHAR msg[256] = _T("");
        _stprintf_s(msg, sizeof(msg) / sizeof(TCHAR), _T("Checking device %s "), devices[i]);
        
        if (hFile != INVALID_HANDLE_VALUE) {
            CloseHandle(hFile);
            print_results(TRUE, msg);
        }
        else
            print_results(FALSE, msg);
    }
}

0x2.5 进程检测

  • 虚拟机中可能在后台运行一些特殊的驱动程序
//xen检测
VOID xen_process()
{
    //这是一个数组
    const TCHAR *szProcesses[] = {
        _T("xenservice.exe"),
    };

    WORD iLength = sizeof(szProcesses) / sizeof(szProcesses[0]);
    for (int i = 0; i < iLength; i++)
    {
        TCHAR msg[256] = _T("");
        _stprintf_s(msg, sizeof(msg) / sizeof(TCHAR), _T("Checking Citrix Xen process %s"), szProcesses[i]);
        if (GetProcessIdFromName(szProcesses[i]))
            print_results(TRUE, msg);
        else
            print_results(FALSE, msg);
    }
}
Last modification:August 20, 2021
如果觉得我的文章对你有用,请随意赞赏