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

Как насчет антиотладки?

h0peIess

RAM
Пользователь
Регистрация
04.12.2018
Сообщения
109
Реакции
117
Скрытый контент для зарегистрированных пользователей.
Хэй, рад снова видеть тебя. Жаль, что я так редко пишу статьи...
Слишком много времени отнимает, годный материал сложно найти.
Ладно, долой слезы, ближе к делу.
1587245080300.png

Вместо вступления
Частенько авторы malware для защиты от реверса прибегают к методам противодействия виртуальным машинам (анти-вм). С их помощью вредоносы пытаются определить, выполняются ли они внутри виртуальной машины (далее просто ВМ), и в случае положительного ответа могут поменять свое поведение. Методики анти-вм чаще всего встречаются во вредоносном ПО, которое распространяется в больших масштабах: боты, майнеры, стиллеры и т.д. Существует не мало ВМ, против каждой из них есть собственные методы обхода, чтобы нам с тобой было проще, давай сосредоточимся на VMware(т.к. это самый популярный программный продукт).

Процессы, слишком просто
Среда VMware оставляет множество следов в системе, особенно после установки VMware Tools. Эти следы присутствуют много где, например, в процессах.
Вот список процессов на ВМ:
Untitled.png

Процесс vm3dservice.exe необходим для 3D графики. Так почему бы нам его не отследить? (vmtoolsd.exe тоже пойдет)
Вот что у меня получилось на C++:
C++:
BOOLEAN ProcessDetection() {
    HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 Process;
    Process.dwSize = sizeof(PROCESSENTRY32);

    if (Process32First(Snapshot, &Process)) {
        while (Process32Next(Snapshot, &Process))
        {
            if (!lstrcmp(Process.szExeFile, L"vm3dservice.exe")) {
                wprintf(L"Process -> %s\n", Process.szExeFile);
                return TRUE;
            }
        }
    }

    CloseHandle(Snapshot);
    return FALSE;
}
Если кратко, мы здесь делаем снапшот всех процессов, проходимся по каждому из них, сравниваем с нашим "запретным" процессом. Просто же, верно? Что там дальше?

Реестр, что же ты скрываешь?
А что у нас в реестре? На самом деле, в системе достаточно много ключей, которые можно просмотреть. Давай я тебе покажу некоторые них:

1) HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0 (сведения о виртуальном жестком диске, интересующий параметр: Identifier)
ПК:
1587246392500.png

ВМ:
Untitled.png

2) HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e96f-e325-11ce-bfc1-08002be10318}\0000 (сведения о мыши, интересные параметры: InfSection, ProviderName)
ПК:
1587241650500.png

ВМ:
Untitled.png

Что же там по коду? А вот что:
C++:
BOOLEAN RegistryDetection() {
    HKEY hKey;
    DWORD dwBufLen = MAX_PATH;
    LONG lret;
    HRESULT hr = E_FAIL;

    WCHAR Identifier[MAX_PATH + 1] = { 0 };
    WCHAR Mouse[MAX_PATH + 1] = { 0 };
    WCHAR ProviderName[MAX_PATH + 1] = { 0 };

    lret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 0\\Scsi Bus 0\\Target Id 0\\Logical Unit Id 0", 0, KEY_READ, &hKey);
    if (lret == ERROR_SUCCESS) {
        RegQueryValueEx(hKey, L"Identifier", NULL, NULL, (BYTE*)Identifier, &dwBufLen);
        RegCloseKey(hKey);
    }

    lret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\ControlSet001\\Control\\Class\\{4d36e96f-e325-11ce-bfc1-08002be10318}\\0000", 0, KEY_READ, &hKey);
    if (lret == ERROR_SUCCESS) {
        RegQueryValueEx(hKey, L"ProviderName", NULL, NULL, (BYTE*)ProviderName, &dwBufLen);
        RegQueryValueEx(hKey, L"InfSection", NULL, NULL, (BYTE*)Mouse, &dwBufLen);
        RegCloseKey(hKey);
    }

    if (wcsstr(ProviderName, L"VMware")) {
        wprintf(L"ProviderName -> %s\n", ProviderName);
        return TRUE;
    }
    else if (wcsstr(Identifier, L"VMware")) {
        wprintf(L"Identifier-> %s\n", Identifier);
        return TRUE;
    }
    else if (wcsstr(Mouse, L"VM")) {
        wprintf(L"InfSection -> %s\n", Mouse);
        return TRUE;
    }

    return FALSE;
}
Долго мусолить не буду, читаем необходимые нам значения, ищем в них "запретные" подстроки.
P.S. Если у тебя есть вопрос по коду, то не надо стесняться, я не кусаюсь ^_^
Следующим на очереди у нас идет пункт под названием...

Обращение к порту ввода/вывода
Вот здесь нужно остановиться поподробнее. Для взаимодействия между виртуальной машиной и основной системой VMware использует виртуальные порты ввода/вывода. Это позволяет поддерживать такие возможности, как буфер обмена между двумя системами. Успех этого подхода зависит от инструкции in на платформе x86. VMware отслеживает использование инструкции in и перехватывает ввод/вывод, проходящий через канал VX. Таким образом, чтобы проверить наличие VMware, второй операнд должен содержать VX, что происходит только в случае, когда в регистре EAX находится магическое число VMXh. Регистр ECX должен иметь значение, соответствующее действию, которое вы хотите выполнить с портом. Байт 0xA означает "получить тип версии VMware", а 0x14 — "получить размер памяти". Для обнаружения виртуальной машины можно использовать оба этих значения.
Да, неплохо бы еще знать ASM :D
Вот что получилось:
C++:
BOOLEAN VMwareVersionDetection() {
    unsigned int Temp1, Temp2;
    __try {
        __asm {
            push eax
            push ebx
            push ecx
            push edx

            mov eax, 'VMXh'   
            mov ecx, 0Ah       
            mov dx, 'VX'   

            in eax, dx           

            mov Temp1, ebx           
            mov Temp2, ecx           

            pop edx
            pop ecx
            pop ebx
            pop eax
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {}

    if (Temp1 == 'VMXh') {       
        return TRUE;
    }
    else {
        return FALSE;
    }
}

BOOLEAN MemoryDetection() {
    unsigned int Temp1 = 0;

    __try {
        __asm {
            push eax
            push ebx
            push ecx
            push edx

            mov eax, 'VMXh'       
            mov ecx, 14h       
            mov dx, 'VX'       

            in eax, dx           

            mov Temp1, eax             

            pop edx
            pop ecx
            pop ebx
            pop eax
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {}

    if (Temp1 > 0) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
Вроде все, думаю, что код пояснять не нужно, все подробно расписал. Следующий гость нашей программы...

CPUID, с тобой все хорошо?
Инструкция CPUID позволяет нам определить ВМ 2 способами!

I способ
Если мы вызовем CPUID с входным значением, равным 1 (EAX), то мы получим некоторую информацию о процессоре. 31 бит регистра ECX на ПК будет равен нулю, а на ВМ единице. Код в студию (в прямом смысле :D)!
C++:
BOOLEAN CPUIDDetection() {
    BOOLEAN Result = FALSE;
    __asm {
        xor eax, eax
        inc    eax
        cpuid
        bt ecx, 0x1f
        jc VM
        NotVM:
            jmp NopInstr
        VM:
            mov Result, 0x1
        NopInstr:
            nop
    }
    return Result;
}

II способ
Второй метод в народе называется HyperVisor, он один из самых популярных (к примеру, он используется в Predator'e). Суть в чем, вызывая CPUID с входным значением, равным 40000000, мы получим "Vendor String" в регистры EAX, ECX, EDX. Причем в VMware это значение является константным ("VMwareVMware", ПК: "Microsoft HV"). Реализуем? Это был риторический вопрос ^^
Код:
C++:
BOOLEAN HypervisorDetection() {
    BOOLEAN Result = FALSE;
    __asm {
        xor eax, eax
        mov eax, 0x40000000
        cpuid
        cmp ecx, 0x4D566572
        jne NopInstr
        cmp edx, 0x65726177
        jne NopInstr
        mov Result, 0x1
        NopInstr:
        nop
    }
    return Result;
}
Тадам!
Конец?
Я надеюсь, что ты не разочарован. В этой статье я не упомянул достаточно много других техник обхода ВМ, в этом просто нет смысла, так как их бесчисленное множество. Прошу не стесняться, задавать различные вопросы, кидать еще какие-нибудь методы и т.д.
Особую благодарность от меня получат те люди, которые предоставят рабочие примеры таких методов, как "Red Pill", "No Pill" (советую ознакомиться). До связи!
P.S. Исходник: https://pastebin.com/2WHPTMrs
 
Последнее редактирование:
Скрытый контент для зарегистрированных пользователей.
*ПО ПРОСЬБЕ KNOWNAME*
Дополню свою статью самым скучным методом. Суть в том, что ВМ также меняет данные о видеокарте, вот небольшой семпл, который это иллюстрирует:
C++:
int main() {
    DISPLAY_DEVICE Device;
    Device.cb = sizeof(DISPLAY_DEVICE);
    DWORD Enum = 0;
    while (EnumDisplayDevices(NULL, Enum, &Device, 0)) {
        wprintf(L"%s\n", Device.DeviceString);
        Enum++;
    }
    Sleep(100000);
    return 0;
}
ПК (пример):
Untitled1.png

ВМ (пример):
Untitled.png
 
Последнее редактирование:
Есть ещё один способ, получение температуры CPU.
Без обид, но это бесполезно, так как это способ будет не каждый ПК поддерживать. Температура - это штука, которая сильно зависит от типа и модели процессора. Также нужно учитывать факт, что процессоры Intel и AMD отличаются. Для получения температуры нужен драйвер режима ядра. Если же я не прав, то заткните мне рот своим рабочим кодом ^_^
 
Последнее редактирование:
Без обид, но это бесполезно, так как это способ будет не каждый ПК поддерживать. Температура - это штука, которая сильно зависит от типа и модели процессора. Также нужно учитывать факт, что процессоры Intel и AMD отличаются. Для получения температуры нужен драйвер режима ядра. Если же я не прав, то заткните мне рот своим рабочим кодом ^_^
 
Во-первых, я не просто так попросил рабочий код, у меня данные вытянуть оттуда не получилось. Во-вторых, эта штука не поддерживается на Windows XP.
 
А как же MAC адрес? VMware в нем отлично находится
+ можно чекать версию и вендора ос, биос (там тоже вмварь есть)

Из экзотики - подключенные девайсы (клава, мышь), свободное место на диске, доступ в интернет и т.д.

Кому интересны исходники полного проекта (реестр, цпу, vxи много другое там тоже есть) - в лс)
 


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