• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Детектим работу ПО в VMWare

AngelStar

RAM
Пользователь
Регистрация
04.02.2022
Сообщения
112
Реакции
94
Детектим работу ПО в VMWare

Введение
Уже несколько лет тема использования виртуальных машин является одной из актуальных в мире ИБ комьюнити. А с началом пандемии коронавируса и перехода большого количества компаний на удаленку – можно сказать ВМ вышли на 1-й план (после денег конечно).

При проведении тестирования на проникновение важно понимать, где именно сейчас ты находишься: в гостевой или хостовой операционной системе. Как минимум это даст возможность спланировать дальнейшие вектора развития пентеста, а как максимум – защитить свой пейлоад от возможного исследования. Ведь ни для кого не секрет, что ни один вирусный аналитик не будет запускать образец на хостовой ОС, все используют виртуальные машины и эмуляторы.

В данной скромной статье показано как можно, обладая не очень крутыми навыками в программировании на C++, определить работу своего ПО в гостевой ОС на VMWare. Принципы, рассмотренные, универсальны (в большинстве своём), поэтому замена некоторых строк и условий с VMWare на, например, Virtual Box или QEMU приведет к аналогичному результату по отношению к уже другим средствам виртуализации.

Исходя из приоритета конкурса по поводу практической значимости и собственного нежелания разводить демагогию по поводу теоретических аспектов – в статье минимум теории и максимум кода. Думаю, что по коду и так будет понятно, как и что работает)


Поехали!
Итак, пойдем «снизу вверх» и первым делом давайте рассмотрим такие (многим наверняка непонятные вещи), как idtr, ldtr, gdtr, tr, SMSW, VX.

НИЗ

idtr - Interrupt Descriptor Table Register – регистр таблицы векторов прерываний, которая используется для обработки исключений и прерываний (ТОЛЬКО В архитектуре x86!)
ldtr - Local Descriptor Table Register - регистр локальной дескрипторной таблицы, которая содержит дускрипторы, используемые конкретным процессом.
gdtr - Global Descriptor Table Register – регистр глобальной дескрипторной таблицы, которая содержит дескрипторы, доступ к которым имеют все процессы.
tr – Table Rigister – регистр дескрипторной таблицы, которая содержит указатели на IDT, LDT и GDT.
К чему всё это? Среда виртуализации держит эти регистры в ежовых рукавицах и хранит там свои значения, а в случает с ldtr – не дает его изменить. (РАБОТАЕТ НА VMWare версии 14 и ниже)
Ниже представил примеры функций, с помощью которых можно, используя вышеописанную особенность ВМ, задетектить виртуалочку (return true – детект! return false – всё в норме)
C++:
bool idtr()
{
    unsigned char idtr[6];
    _asm sidt idtr
    unsigned int idt_base = 0;

    idt_base = *((unsigned long*)&idtr[2]);

    if ((idt_base >> 24) == 0xff) {
        return true;
    }
    return false;
}

bool ldtr()
{
    unsigned char   ldtr[5] = "\xef\xbe\xad\xde";
    unsigned long   ldt = 0;

    _asm sldt ldtr
    ldt = *((unsigned long*)&ldtr[0]);

    if (ldt != 0xdead0000)
    {
        return true;
    }
    return false;
}

bool gdtr()
{
    unsigned char   gdtr[6];
    unsigned long   gdt = 0;

    _asm sgdt gdtr
    gdt = *((unsigned long*)&gdtr[2]);

    if ((gdt >> 24) == 0xff)
    {
        return true;
    }
    return false;
}

bool tr()
{
    unsigned char mem[4] = { 0, 0, 0, 0 };

    __asm str mem;

    if ((mem[0] == 0x00) && (mem[1] == 0x40))
    {
        return true;
    }
    return false;
}

Теперь рассмотрим SMSW: Store Machine Status Word (дословно – Хранить слово (2 байта) состояния машины). Не вдаваясь в подробности скажу, что виртуалка его также подменяет. Код ниже, пользуемся)
C++:
bool smsw()
{
    unsigned int reax = 0;

    __asm
    {
        mov eax, 0xCCCCCCCC;
        smsw eax;
        mov DWORD PTR[reax], eax;
    }

    if ((((reax >> 24) & 0xFF) == 0xcc) && (((reax >> 16) & 0xFF) == 0xcc))
    {
        return true;
    }
    return false;
}

Перейдем к VX. Это, так называемый, «порт виртуализации». Если верить интернетам – через него происходит низкоуровневое общение общение хостовой и гостевой ОС. Скажу сразу: сам не проверял как там и что происходит, но точно знаю, что если записать в него 0x564d5868 (в символах - VMXh) и исключения не возникнет – то добро пожаловать в виртуальную машину)

C++:
bool VX_check() {
    __try {
        __asm {
            mov eax, 0x564d5868
            mov ecx, 0x0A
            mov edx, 0x5658
            in eax, dx  }
        return true;
    } __except (EXCEPTION_EXECUTE_HANDLER) {
        return false;
    }
}

НЕМНОГО ВЫШЕ

Современные процессоры указывают на использование виртуализации. При этом, о виртуальном процессоре, также, как и о реальном, хранится большой объем информации, включая его производителя. В связи с этим – проверяем и делаем выводы)
C++:
bool cpu_check() {
    int* cpuinfo = new int[4];
    int f_id = 0x40000000;
    __cpuid(cpuinfo, f_id);
    char hyper_vendor_id[13];
    memcpy(hyper_vendor_id + 0, (const void*)&(cpuinfo[1]), 4);
    memcpy(hyper_vendor_id + 4, (const void*)&(cpuinfo[2]), 4);
    memcpy(hyper_vendor_id + 8, (const void*)&(cpuinfo[3]), 4);
    hyper_vendor_id[12] = '\0';
    cout << "hyper_vendor_id: " << hyper_vendor_id << endl;
    if (strstr(hyper_vendor_id, "VMware"))
        return true;
    return false;
}

По аналогии с процессором – mac адрес, первые 3 байта которого – производитель.
C++:
bool MAC_check() {
    DWORD OutBufLen = 8192;
    PIP_ADAPTER_INFO AdapterInfo = (PIP_ADAPTER_INFO) new(char[OutBufLen]);
    ULONG err = GetAdaptersInfo(AdapterInfo, &OutBufLen);
    while (AdapterInfo) {
        printf("MAC[%s: %s] = %X:%X:%X:%X:%X:%X\n", AdapterInfo->AdapterName, AdapterInfo->Description, (BYTE)AdapterInfo->Address[0], (BYTE)AdapterInfo->Address[1], (BYTE)AdapterInfo->Address[2],
            (BYTE)AdapterInfo->Address[3], (BYTE)AdapterInfo->Address[4], (BYTE)AdapterInfo->Address[5]);
        if ((((BYTE)AdapterInfo->Address[0] == 0x00) && ((BYTE)AdapterInfo->Address[1] == 0x05) && ((BYTE)AdapterInfo->Address[2] == 0x69)) ||
            (((BYTE)AdapterInfo->Address[0] == 0x00) && ((BYTE)AdapterInfo->Address[1] == 0x0c) && ((BYTE)AdapterInfo->Address[2] == 0x29)) ||
            (((BYTE)AdapterInfo->Address[0] == 0x00) && ((BYTE)AdapterInfo->Address[1] == 0x1c) && ((BYTE)AdapterInfo->Address[2] == 0x14)) ||
            (((BYTE)AdapterInfo->Address[0] == 0x00) && ((BYTE)AdapterInfo->Address[1] == 0x50) && ((BYTE)AdapterInfo->Address[2] == 0x56))) {
            delete(AdapterInfo);
            return true;
        }
        AdapterInfo = AdapterInfo->Next;
    }
    delete(AdapterInfo);
    return false;
}

Также производителя хранит ОС и BIOS. Используя wmic (может можно и по другому, но я сделал так), получаем вендора, сравниваем и делаем выводы.
C++:
bool BIOS_check()
{
    bool flag = false;
    const char* cmd = "wmic bios get serialnumber";
    shared_ptr<FILE> pipe(_popen(cmd, "r"), _pclose);
    cout << "DMI_check:" << endl;
    if (pipe)
    {
        char buffer[1024];
        double diskSpace = 0;
        while (!feof(pipe.get())) {
            if (fgets(buffer, 128, pipe.get()) != NULL)
            {
                cout << buffer << endl;
                if (strstr(buffer, "VMware") || strstr(buffer, "WMW"))
                    return true;
            }
        }
    }
    return false;
}
C++:
bool Win_check()
{
bool flag = false;
    const char* cmd = "wmic csproduct get vendor, version";
    shared_ptr<FILE> pipe(_popen(cmd, "r"), _pclose);
    if (pipe)
    {
        char buffer[128];
        string result = "";
        while (!feof(pipe.get()))
            if (fgets(buffer, 128, pipe.get()) != NULL)
                result += buffer;
        cout << "Vendor_Version: " << result << endl;
        if (strstr(result.c_str(), "VMware"))
            return true;
    }
    return false;
}

ВВЕРХ!

Среды виртуализации размещают на гостевых операционных системах свои сервисы, а как следствие – появляются ключи в реестре, процессы и файлы.

Детект через реестр Windows
C++:
bool vmRegVal()
{
    bool res = false;
    std::string stringVmRegVals[25][4] =
    {
        { "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", "VMware User Process", "", "" },
        { "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\SharedDlls", "C:\\WINDOWS\\system32\\VMUpgradeAtShutdownWXP.dll", "", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "DriverDesc", "vmware svga ii", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "DriverDesc", "vmware svga 3d", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96F-E325-11CE-BFC1-08002BE10318}\\0000",
        "InfSection", "vmmouse", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "DriverDesc", "vmware vmscsi controller", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Video\\{4BEF3D64-1F2B-4026-9EE4-B6D8CD9FEA1B}\\0000",
        "Device Description", "vmware svga ii", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Video\\{3A8088C5-4419-4572-801C-A10BA858952F}\\0000",
        "Device Description", "vmware svga 3d", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96F-E325-11CE-BFC1-08002BE10318}\\0000",
        "DriverDesc", "VMware Pointing Device", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96F-E325-11CE-BFC1-08002BE10318}\\0000",
        "ProviderName", "VMware, Inc.", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96F-E325-11CE-BFC1-08002BE10318}\\0001",
        "DriverDesc", "VMware USB Pointing Device", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96F-E325-11CE-BFC1-08002BE10318}\\0001",
        "InfSection", "VMUsbMouse", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96F-E325-11CE-BFC1-08002BE10318}\\0001",
        "ProviderName", "VMware, Inc.", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "HardwareInformation.AdapterString", "VMware SVGA 3D", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "HardwareInformation.ChipType", "VMware Virtual SVGA 3D Graphics Adapter", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "InfSection", "VM3D_AMD64", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "InstalledDisplayDrivers", "vm3dum64", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "InstalledDisplayDrivers", "vm3dum", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "InstalledDisplayDrivers", "vm3dgl64", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "InstalledDisplayDrivers", "vm3dgl", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "OpenGLDriverName", "vm3dgl64.dll", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "OpenGLDriverNameWow", "vm3dgl.dll", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "ProviderName", "VMware, Inc.", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "UserModeDriverName", "vm3dum64.dll", "" },
        { "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000",
        "UserModeDriverNameWow", "vm3dum.dll", "" }
    };

    string val1[] = { "Scsi Port 0", "Scsi Port 1", "Scsi Port 2", "Scsi Port 3", "Scsi Port 4" };
    string val2[] = { "Scsi Bus 0", "Scsi Bus 1", "Scsi Bus 2", "Scsi Bus 3", "Scsi Bus 4", "Scsi Bus 5", "Scsi Bus 6" };

    for (size_t i = 0; i < sizeof(val1) / sizeof(val1[0]); i++)
    {
        for (size_t j = 0; j < sizeof(val2) / sizeof(val2[0]); j++)
        {
            string str;
            str = "HARDWARE\\DEVICEMAP\\Scsi\\" + val1[i] + "\\" + val2[j] +
                "\\Target Id 0\\Logical Unit Id 0";
            if (CheckReg(str, "Identifier", "vmware", ""))
            {
                cout << " detected " << str << endl;
                res = true;
            }
        }
    }
    for (size_t i = 0; i < sizeof(stringVmRegVals) / sizeof(stringVmRegVals[0]); i++)
    {
        if (CheckReg(stringVmRegVals[i][0], stringVmRegVals[i][1], stringVmRegVals[i][2],
            stringVmRegVals[i][3]))
        {
            return true;
        }
    }
    return res;
}

bool CheckReg(string value, string valueName, string key, string key2)
{
    HKEY HK = 0;
    bool flag = false;
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, value.c_str(), 0, KEY_READ, &HK) == ERROR_SUCCESS)
    {
        unsigned long type = 0;
        unsigned long size = 0x100;
        char* reg_value = (char*)LocalAlloc(LMEM_ZEROINIT, size + 10);
        if (ERROR_SUCCESS == RegQueryValueExA(HK, valueName.c_str(), 0, &type, (unsigned char*)reg_value, &size))
        {
            if (key != "")
            {
                if (key2 != "")
                {
                    if (type == REG_MULTI_SZ)
                    {
                        char* video = reg_value;
                        while (*(unsigned char*)video)
                        {
                            string res = resultKey(video);
                            if (res.find(key) != std::string::npos || res.find(key2) != std::string::npos)
                                flag = true;
                            video = &video[strlen(video) + 1];
                        }
                    }
                } else
                {
                    string res = resultKey(reg_value);
                    if (type == REG_SZ || type == REG_EXPAND_SZ)
                    {
                        if (res.find(key) != std::string::npos)
                            flag = true;
                    }
                    if (type == REG_MULTI_SZ)
                    {
                        char* video = reg_value;
                        while (*(unsigned char*)video)
                        {
                            string res = resultKey(video);
                            if (res.find(key) != std::string::npos)
                                flag = true;
                            video = &video[strlen(video) + 1];
                        }
                    }
                }
            } else
                flag = true;
        }
        LocalFree(reg_value);
        RegCloseKey(HK);
    }
    return flag;
}

Теперь файлы
C++:
bool vmFile()
{
    bool res = false;
    string stringVmFiles[20] =
    {
        "C:\\WINDOWS\\system32\\vm3dgl64.dll",
        "C:\\WINDOWS\\system32\\vm3dgl.dll",
        "C:\\WINDOWS\\system32\\vm3dum64.dll",
        "C:\\WINDOWS\\system32\\vm3dum.dll",
        "C:\\WINDOWS\\system32\\VmbuxCoinstaller.dll",
        "C:\\WINDOWS\\system32\\vmGuestLib.dll",
        "C:\\WINDOWS\\system32\\vmGuestLibJava.dll",
        "C:\\WINDOWS\\system32\\vmhgfs.dll",
        "C:\\WINDOWS\\system32\\vmwogl32.dll",
        "C:\\WINDOWS\\system32\\vmmreg32.dll",
        "C:\\WINDOWS\\system32\\vmx_fb.dll",
        "C:\\WINDOWS\\system32\\vmx_mode.dll",
        "C:\\WINDOWS\\system32\\VMUpgradeAtShutdownWXP.dll"
    };

    for (size_t i = 0; i < sizeof(stringVmFiles) / sizeof(stringVmFiles[0]); i++)
    {
        if (fileExist((char*)stringVmFiles[i].c_str()) != INVALID_FILE_ATTRIBUTES)
        {
            cout << " detected " << stringVmFiles[i] << endl;
            res = true;
        }
    }
    return res;
}

DWORD fileExist(char* filename)
{
    return GetFileAttributesA(filename);
}

Ну и процессы напоследок
C++:
bool Process_check()
{
    bool res = false;
    DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i;
    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
    {
        return 1;
    }
    cProcesses = cbNeeded / sizeof(DWORD);
    for (i = 0; i < cProcesses; i++)
    {
        if (aProcesses[i] != 0)
        {
            CHAR szProcessName[MAX_PATH] = "null";

            HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
                PROCESS_VM_READ,
                FALSE, aProcesses[i]);
            if (NULL != hProcess)
            {
                HMODULE hMod;
                DWORD cbNeeded;
                if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),
                    &cbNeeded))
                {
                    GetModuleBaseNameA(hProcess, hMod, szProcessName,
                        sizeof(szProcessName) / sizeof(CHAR));
                }
                CloseHandle(hProcess);
                if (strstr(szProcessName, "vmtool") ||
                    strstr(szProcessName, "vm3dservice") ||
                    strstr(szProcessName, "vmhgfs") ||
                    strstr(szProcessName, "VMMEMCTL") ||
                    strstr(szProcessName, "vmmouse") ||
                    strstr(szProcessName, "vmrawdsk") ||
                    strstr(szProcessName, "VMTools") ||
                    strstr(szProcessName, "vmusbmouse") ||
                    strstr(szProcessName, "vmvss") ||
                    strstr(szProcessName, "vmscsi") ||
                    strstr(szProcessName, "vmxnet") ||
                    strstr(szProcessName, "vmx_svga") ||
                    strstr(szProcessName, "VMware Physical Disk Helper Service") ||
                    strstr(szProcessName, "vmtoolsd") ||
                    strstr(szProcessName, "vmacthlp")) {
                    cout << " detected " << szProcessName << endl;
                    res = true;
                }
            }
        }
    }
    return res;
}

ЭКЗОТИКА

Теперь немного порассуждаем. Каждый из нас, создавая виртуалку, зачастую не выделяет ей такое же количество ресурсов, как у реальной машины. Более того, не всегда виртуалка подключена к сети «Интернет». Исходя из этого ниже приведены методы, которые можно использовать в качестве дополнительных по детекту. Все они основаны на сугубо моих предположениях о том, как пользователи используют ВМ.

Проверка количества ядер процессора. Я не думаю, что в 2022 году еще можно встретить машину с 2-х ядерным процессором, а вот виртуалку – вполне.
C++:
void checkCoreNumber()
{
    const char* cmd = "wmic cpu get NumberOfCores";
    FILE* fp;
    char line[1000];
    string result[100][101];
    int count = 0;
    bool flag = false, flag2 = false, result_flag = false;
    fp = _popen(cmd, "r");
    while (fgets(line, sizeof line, fp) && count < 100)
    {
        count = count + 1;
        if (count == 2)
        {
            if (strstr(line, "2"))
            {
                printf("Core number is 2\n");
            } else {
                printf("Core number is more than 2\n");
            }
        }
    }
    _pclose(fp);
}

Тоже самое касается и жесткого диска. У кого диск на реальном ПК меньше или равен по размеру 60 Гб? Думаю, таких не много.
C++:
void DiskSpace()
{
    bool flag = false;
    const char* cmd = "wmic logicaldisk get size";
    shared_ptr<FILE> pipe(_popen(cmd, "r"), _pclose);
    if (pipe)
    {
        char buffer[128];
        string result = "";
        double diskSpace = 0;
        while (!feof(pipe.get())) {
            if (fgets(buffer, 128, pipe.get()) != NULL)
            {
                result = buffer;
                result = eraseString(result, ' ');
                result = eraseString(result, '\r');
                result = eraseString(result, '\n');
                if (result != "Size" && result != "" && result != " ")
                {
                    diskSpace = stod(result) / (1024 * 1024 * 1024);
                    printf("Disk space is %f\n", diskSpace);
                    break;
                }
            }
        }
    }
}

Проверяем подключение к интернету
C++:
void checkInternet()
{
    bool bConnect = InternetCheckConnectionA("https://www.google.com.tr/", FLAG_ICC_FORCE_CONNECTION, 0);

    int a = GetLastError();
    if (!bConnect)
    {
        printf("No internet\n");
    } else {
        printf("Internet is connected\n");
    }
}

Ну и можно еще чекнуть имя машины, вдруг кто назовет её «VM-1» или как-то так)
C++:
string getComputerName()
{
    CHAR nameBuf[MAX_COMPUTERNAME_LENGTH + 2];
    DWORD nameBufSize = (sizeof nameBuf) - 1;

    GetComputerNameA(nameBuf, &nameBufSize);

    string arr_s(nameBuf);

    return arr_s;
}

Можно еще проверить подключенные устройства (мышь, клавиатура и т.д.). Часто к ПК подключено больше 2-х периферийных устройств)
C++:
void InitDIAndEnumAllDevices(HWND hWnd)
{
    if (DirectInput8Create(GetModuleHandle(0), DIRECTINPUT_VERSION,
        IID_IDirectInput8W, (void**)&g_pDI, NULL) == S_OK)
        g_pDI->EnumDevices(DI8DEVCLASS_ALL, EnumDevices,
            (LPVOID)hWnd, DIEDFL_ALLDEVICES);
}

BOOL CALLBACK EnumDevices(LPCDIDEVICEINSTANCE pdInst,
    LPVOID pvRef)
{
    LPOLESTR guidChar = NULL;
    guidChar = (LPOLESTR)malloc(128);
    if (StringFromGUID2(pdInst->guidProduct, guidChar, 64)) {
        USES_CONVERSION;
        string guid = OLE2CA(guidChar);
        char name[256];
        WideCharToMultiByte(CP_OEMCP, 0, pdInst->tszProductName, -1, name, 260, NULL, NULL);
        cout << name << ": " << guid << endl;
    }
    return DIENUM_CONTINUE;
}
Еще раз отмечу, что экзотические методы не стабильны. Использовать их советую как дополнительные)

В заключении
В данной статье постарался изложить всё, что знаю по теме детекта виртуалок (в частности VMWare). Конечно наверняка есть еще много много различных способов, которые знают другие или которые еще неизвестны человечеству. Если вдруг знаете что-то еще – напишите обязательно в комментариях, будет интересно попробовать и проверить.

На счет кода – его вариаций можно сделать бесконечное множество. Я изложил то, что когда-то писал. Если кто-то хочет написать код по-другому – пожалуйста, пишите в комментариях, тоже интересно глянуть)

Это мой первый опыт в написании такой большой статьи на форуме и уж тем более участии в конкурсе. Надеюсь, кому-то данная статья пригодится)

Всем спасибо за внимание)
 
для каких целей полезно узнать, кто с виртуалки сидит? Либо это хакерам не надо, а только безопасникам?
Ну смотри: пишешь ты софт и хочешь подгадить реверсерам, которые будут работать с ним на виртуалке. Например реализовать самоудаление и поиск своих копий (через инжект и поиск по хешу среди файлов, например)

Конечно, это не спасет от исследования, но замедлит его

+ если уж говорить о "хакерстве" - получать доступы и проверять вирт или нет; можно через детект вирта пытаться побег реализовать, чтобы на хост ос попасть
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Отсюда https://xss.pro/threads/59635/

C:
// Tested on Vmware 16.2.3
bool redpill64()
{
    char idtr[10];
    __stosb(idtr, 0x00, 0xA);
    __sidt(&idtr);
    if (idtr[6] != 0x00) { return true; }
    else { return false; }
    //DumpHex(idtr, 0xA);
}

Отсюда https://xss.pro/threads/67784/ на основе одной из таблиц ACPI, не эмулируемой гипервизором от слова совсем.

C++:
// It's just a  PoC
#include <Windows.h>
#include <stdio.h>
#include <iostream>

using NtQuerySystemInformation = NTSTATUS(NTAPI*)(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID                    SystemInformation,
    ULONG                    SystemInformationLength,
    PULONG                   ReturnLength
    );

NtQuerySystemInformation    pfn_NtQuerySystemInformation = nullptr;

void DumpHex(const void* data, size_t size);
FARPROC GetProcAddrWrapper(LPCSTR FuncName, LPCWSTR Library);

/*
Based on https ://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html

The Firmware Basic Boot Performance Table resides outside of the FPDT.
It includes a header, defined in Table 5.93, and one or more Performance Records.
*/
typedef struct _FIRMWARE_BASIC_BOOT_PERFORMANCE_TABLE_HEADER
{
    DWORD    Signature;                        // ‘FBPT’ is the signature to use.
    BYTE    Length;                            // Length of the Firmware Basic Boot Performance Table.
                                            // This includes the header and allocated size of the subsequent records.
} FIRMWARE_BASIC_BOOT_PERFORMANCE_TABLE_HEADER;

typedef struct _FIRMWARE_BASIC_BOOT_PERFORMANCE_DATA_RECORD
{
    USHORT    PerformanceRecordType;            // 2 - Firmware Basic Boot Performance Data Record. Only one of these records will be produced.
    BYTE    RecordLength;                    // 48 - This value depicts the length of the performance record, in bytes.
    BYTE    Revision;                        // 2 - Revision of this Performance Record
    DWORD    Reserved;                        // Reserved
    DWORD64 ResetEnd;                        // Timer value logged at the beginning of firmware image execution. This may not always be zero or near zero.
    DWORD64 OSLoaderImageStart;                // Timer value logged just prior to loading the OS boot loader into memory.
                                            // For non-UEFI compatible boots, this field must be zero.
    DWORD64 OsLoaderStartImageStart;        // Timer value logged just prior to launching the currently loaded OS boot loader image.
                                            // For non-UEFI compatible boots, the timer value logged will be just prior to the INT 19h handler invocation
    DWORD64 ExitBootServicesEntry;            // Timer value logged at the point when the OS loader calls the ExitBootServices function for UEFI compatible firmware.
                                            // For non-UEFI compatible boots, this field must be zero.
    DWORD64 ExitBootServicesExit;            // Timer value logged at the point just prior to the OS loader gaining control back from the ExitBootServices
                                            // function for UEFI compatible firmware. For non-UEFI compatible boots, this field must be zero.
} FIRMWARE_BASIC_BOOT_PERFORMANCE_DATA_RECORD;

typedef struct _FIRMWARE_BASIC_BOOT_PERFORMANCE_TABLE
{
    FIRMWARE_BASIC_BOOT_PERFORMANCE_TABLE_HEADER Header;
    FIRMWARE_BASIC_BOOT_PERFORMANCE_DATA_RECORD PerfRecord;
} FIRMWARE_BASIC_BOOT_PERFORMANCE_TABLE;

int main()
{
    NTSTATUS Status;
    FIRMWARE_BASIC_BOOT_PERFORMANCE_TABLE fbpt = {0};
    constexpr auto size = sizeof(fbpt);
    pfn_NtQuerySystemInformation = reinterpret_cast<NtQuerySystemInformation>((GetProcAddrWrapper("NtQuerySystemInformation", L"ntdll.dll")));

    Status = pfn_NtQuerySystemInformation(SystemFirmwareBootPerformanceInformation, &fbpt, size, NULL);

    //DumpHex(&fbpt, size);
    /*
    46 42 50 54 38 00 00 00  02 00 30 02 00 00 00 00  |  FBPT8.....0.....
    DE C8 AC E8 A1 D0 68 80  23 58 42 07 01 00 00 00  |  ......h.#XB.....
    5B 03 13 09 01 00 00 00  A8 CA 9A 55 01 00 00 00  |  [..........U....
    2D 23 AC 55 01 00 00 00                           |  -#.U....
    */
    printf(" _FIRMWARE_BASIC_BOOT_PERFORMANCE_TABLE_HEADER\n\n");
    printf("FBPT Signature:\t\t%x\nFBPT Length:\t\t%x\n\n", fbpt.Header.Signature, fbpt.Header.Length);
    printf("_FIRMWARE_BASIC_BOOT_PERFORMANCE_DATA_RECORD\n\n");
    printf("PerformanceRecordType:\t%x\n"
            "RecordLength:\t\t%x\n"
            "Revision:\t\t%x\n"
            "Reserved:\t\t%x\n"
            "ResetEnd:\t\t%llx\n"
            "OSLoaderImageStart:\t%llx\n"
            "OsLoaderStartImageStart:%llx\n"
            "ExitBootServicesEntry:\t%llx\n"
            "ExitBootServicesExit\t%llx\n",
            fbpt.PerfRecord.PerformanceRecordType,
            fbpt.PerfRecord.RecordLength,
            fbpt.PerfRecord.Revision,
            fbpt.PerfRecord.Reserved,
            fbpt.PerfRecord.ResetEnd,
            fbpt.PerfRecord.OSLoaderImageStart,
            fbpt.PerfRecord.OsLoaderStartImageStart,
            fbpt.PerfRecord.ExitBootServicesEntry,
            fbpt.PerfRecord.ExitBootServicesExit);
}

FARPROC GetProcAddrWrapper(LPCSTR FuncName, LPCWSTR Library)
{
    auto hLib = LoadLibrary(Library);
    if (hLib)
    {
        auto addr = GetProcAddress(hLib, FuncName);
        if (addr)
        {
            FreeLibrary(hLib);
            return addr;
        }
        else
        {
            FreeLibrary(hLib);
            return NULL;
        }
    }
    else
    {
        return NULL;
    }
}

Ну и вдогонку https://evasions[.]checkpoint.com/, https://anti-debug[.]checkpoint.com/
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Я пытался понять, как можно внедрить код на C++ в память компьютера в режиме реального времени, но ничего не получилось. есть предложения?
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх