Логотип
Главная | Статьи | Шеллкод для Windows 11: Как обойти Control Flow Guard и писать Position-Independent Code (PIC) на ассемблере
Шеллкод для Windows 11: Как обойти Control Flow Guard и писать Position-Independent Code (PIC) на ассемблере

Шеллкод для Windows 11: Как обойти Control Flow Guard и писать Position-Independent Code (PIC) на ассемблере

29 мая, 2025

72

Эй, привет, кодеры! Сегодня мы погружаемся в мрачный и крутой мир шеллкодов для Windows 11. Мы разберем, как обойти защиту Control Flow Guard (CFG), встроенную в современные системы Microsoft, и напишем Position-Independent Code (PIC) на чистом ассемблере. Это не просто теория — я дам тебе рабочие примеры, лайфхаки и пошаговый разбор. Готов? Погнали!

Что такое Control Flow Guard (CFG) и почему он нам мешает?

Control Flow Guard — это защита, встроенная в Windows начиная с версии 8.1 и усиленная в Windows 11. Ее цель — предотвратить атаки, основанные на перехвате потока управления, такие как ROP (Return-Oriented Programming). CFG проверяет, чтобы вызовы функций и возвраты адресов соответствовали заранее определенным “допустимым” точкам входа. Если шеллкод пытается сделать что-то “не по правилам” — бум, программа падает.

Проблема для нас: классические шеллкоды часто используют прямые вызовы функций (call) или прямые ссылки на адреса в памяти. С CFG это не работает, потому что адреса не проходят проверку.

Решение: писать код, который не зависит от абсолютных адресов, то есть Position-Independent Code (PIC), и обходить CFG, аккуратно манипулируя стеком вызовов или используя обходные пути для вызова функций.

Position-Independent Code (PIC): Почему он крут и как его писать?

PIC — это код, который может исполняться из любого места в памяти. Он не использует абсолютных адресов, а работает относительно текущей позиции (например, через регистр RIP в x64). Это идеально для шеллкодов, потому что мы не знаем заранее, где в памяти окажется наш код после инъекции.

Основные принципы PIC:

  1. Не используй абсолютные адреса для данных или функций.
  2. Работай через относительные смещения (например, jmp short или call rel).
  3. Для доступа к API Windows ищи адреса динамически через PEB (Process Environment Block) или обходи таблицы импорта.

Пошаговый план: Пишем шеллкод на ассемблере для Windows 11

Давай создадим простой шеллкод, который вызывает MessageBoxA (для демонстрации), обходя CFG. Мы будем использовать x64-ассемблер, так как Windows 11 в основном работает на 64-битных системах.

Шаг 1: Получаем базовый адрес через PEB (без абсолютных адресов)

Чтобы найти адреса нужных функций (например, GetProcAddress или LoadLibrary), мы начнем с PEB. Это структура, которая доступна через регистр GS в x64.

Шаг 2: Ищем функции динамически

Теперь, когда у нас есть базовый адрес ntdll.dll, мы можем парсить его экспорты, чтобы найти GetProcAddress и далее загрузить нужные функции. Это долго, но CFG нас не остановит, потому что мы не делаем прямых вызовов.

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

Шаг 3: Обход CFG через прямой вызов системных функций

CFG проверяет только непрямые вызовы через указатели. Если у нас есть прямой адрес системной функции (например, из ntdll.dll), мы можем вызвать ее напрямую через syscall. Это работает, потому что системные вызовы не проходят через CFG.

Пример вызова системной функции:

Шаг 4: Вызов MessageBoxA для теста

После получения адреса MessageBoxA через GetProcAddress мы вызываем его, но аккуратно, чтобы не сломать стек и не триггерить CFG.

Лайфхаки для работы с Windows 11 и CFG

  1. Используй системные вызовы напрямую: Вместо вызова высокоуровневых API, таких как VirtualAlloc, ищи их низкоуровневые аналоги в ntdll.dll (например, NtAllocateVirtualMemory) и вызывай через syscall.
  2. Минимизируй отпечаток: Не оставляй лишних данных в памяти. Если нужно хранить строки или адреса, шифруй их и расшифровывай на лету.
  3. Тестируй на отладчиках: Используй x64dbg или IDA Pro для отладки шеллкода. Это спасет кучу времени, когда CFG будет рушить твои планы.

Типичные ловушки и как их избежать

  • Ошибка стека: Windows 11 строго проверяет выравнивание стека (должно быть кратно 16). Перед вызовом функций всегда проверяй RSP и корректируй его инструкцией and rsp, -16.
  • Антивирусы и EDR: Даже если ты обошел CFG, современные EDR-системы (Endpoint Detection and Response) могут засечь подозрительные системные вызовы. Маскируй свое поведение, например, используя легитимные API для маскировки.
  • Обновления Windows: Microsoft регулярно усиливает защиты. То, что работало вчера, может не работать завтра. Следи за патчами и обновляй свои подходы.

Итоговый шеллкод: Сборка и тестирование

Теперь соберем наш шеллкод. Используй NASM для компиляции:

Для тестирования можешь инъецировать его в тестовый процесс через простую программу на C/C++ с помощью VirtualAlloc и CreateThread. Но помни: делай это только в безопасной среде (виртуалка типа VirtualBox) и с разрешения владельца системы.

Пример инъектора на C:

Заключение: Ты на шаг впереди

Поздравляю, теперь ты знаешь, как писать шеллкоды для Windows 11, обходя Control Flow Guard, и создавать Position-Independent Code на ассемблере. Это только начало — дальше можно углубиться в техники обхода других защит, таких как ASLR или DEP, или оптимизировать код для еще большей скрытности.

Если хочешь копнуть глубже, изучай структуру PE-файлов, системные вызовы и механики работы PEB. И помни: с великой силой приходит великая ответственность. Используй эти знания только для исследований или в рамках легальных penetration-тестов.