Гайд Anti-debug ( PEB )

  • Автор темы Автор темы n0entry
  • Дата начала Дата начала
Пользователь
Пользователь
Статус
Онлайн
Регистрация
12 Дек 2022
Сообщения
128
Реакции
31
Антиотладка через NtCurrentPeb

Этот метод в одном crackme использовался

C++:
Expand Collapse Copy
if ((NtCurrentPeb()->ProcessHeap & 0x70) != 0)
  v12 = v10 + v11;

if ((NtCurrentPeb()->NtGlobalFlag & 0x70) != 0)
  v12 = v10 + v11;

if (*&NtCurrentPeb()->BeingDebugged)
{
  v10 = -83;
  v11 = 43;
}

все три приведённых условия - это антиотладочные проверки

Уточнение: NtCurrentPeb() — это неофициальная конструкция, используемая для получения указателя на PEB через сегментные регистры (FS:[0x30] в x86, GS:[0x60] в x64). Официально Windows предоставляет NtCurrentTeb(), возвращающую TEB*, а PEB доступна через TEB::ProcessEnvironmentBlock


NtCurrentPeb

Пожалуйста, авторизуйтесь для просмотра ссылки.
:

NtCurrentTeb — это функция, возвращающая указатель на текущий TEB (Thread Environment Block, блок среды потока)

C++:
Expand Collapse Copy
_TEB* NtCurrentTeb();

Возвращаемое значение: указатель на текущий TEB


ProcessHeap

Пожалуйста, авторизуйтесь для просмотра ссылки.


Комментарий:

Функция GetProcessHeaps возвращает дескриптор основного кучи текущего процесса, а также дескрипторы любых других куч, созданных через HeapCreate

Эта функция в основном используется для отладки, так как возвращённые кучи могли быть созданы другими частями кода и могут быть уничтожены после вызова. Уничтожение кучи делает указатель, возвращённый из GetProcessHeap, недействительным и дальнейшее его использование может привести к неопределённому поведению
Чтобы получить дескриптор основной кучи процесса, можно использовать GetProcessHeap

Почему это работает как антиотладка
BeingDebugged

Эта проверка понятна по названию.
Пожалуйста, авторизуйтесь для просмотра ссылки.


BeingDebugged — флаг, указывающий, отлаживается ли текущий процесс. Однако PEB — это внутренняя структура ОС, и Microsoft не гарантирует стабильность её формата между версиями Windows. CheckRemoteDebuggerPresent — более "официальный" способ проверки, но под капотом он также обращается к PEB

ProcessHeap и NtGlobalFlag

Влияет ли отладчик на активную кучу процесса (основную или созданную динамически) — зависит от того, активированы ли в отладочной среде специальные механизмы отладки кучи


1. Механизмы отладки и поведение кучи
(1) Флаги отладки и поведение кучи

  • NtGlobalFlag
    Если процесс запущен под отладчиком (а не аттачнут), система может установить флаги отладки в PEB, такие как:
    • FLG_HEAP_ENABLE_TAIL_CHECK (0x10) — добавляет защитные значения в конец блока памяти (например, 0xABABABAB) для обнаружения переполнений
    • FLG_HEAP_ENABLE_FREE_CHECK (0x20) — заполняет освобождённую память особыми значениями (например, 0xFEEEFEEE) для обнаружения повреждений
    • FLG_HEAP_VALIDATE_PARAMETERS (0x40) — включает строгую проверку параметров при работе с кучей, может вызывать исключения

Эти флаги изменяют поведение менеджера кучи — размеры блоков, структуру и метаинформацию
  • Page Heap (страничная куча)
    Если включена (через gflags или реестр), каждая куча получает защитную страницу (guard page):
    • Full Page Heap — каждый блок размещается на отдельной странице памяти, а за ним следует защищённая страница. При переполнении сразу срабатывает исключение STATUS_ACCESS_VIOLATION

(2) Шаблоны заполнения при отладке

В режиме отладки куча может быть заполнена специальными шаблонами :
  • Неинициализированная память: 0xBAADF00D
  • Освобождённая память: 0xFEEEFEEE
Эти шаблоны могут влиять на логику программы, если она зависит от содержимого памяти

2. Влияние способа запуска отладчика
(1) Отладчик запускает процесс
  • Система устанавливает флаги отладки (например, NtGlobalFlag) при инициализации процесса, что влияет на структуру основной кучи (GetProcessHeap)
  • Пример: при включённой Page Heap основная куча будет сильно отличаться от обычной
(2) Отладчик аттачится к уже запущенному процессу
  • Простой аттач обычно не меняет конфигурацию уже созданных куч
  • Однако можно вручную включить отладку кучи через команды или HeapSetInformation
Исключение — если используется Application Verifier или включена отладка через реестр

3. Практические последствия
(1) Изменение размера и структуры кучи
  • Отладочные кучи выделяют больше памяти: запрос 100 байт может реально привести к выделению 132 байт (с защитными байтами)
  • Разница в адресах: при Page Heap блоки располагаются в изолированных страницах памяти
(2) Исключения и стабильность
  • Переполнение вызывает сбой: отладочная куча перехватывает такие ошибки, а без отладки программа может просто продолжить выполнение
  • Обращение к освобождённой памяти: при чтении/записи отладчик может поймать исключение
(3) Падение производительности
  • Дополнительные проверки замедляют выделение и освобождение памяти, особенно при частом использовании кучи
Итак, чтобы поведение кучи изменилось:
  1. Процесс должен быть запущен под отладчиком (а не аттачнут)
  2. Должны быть включены отладочные флаги или механизмы (например, Page Heap)
NtGlobalFlag устанавливается системой только в момент создания процесса, если он создаётся с флагом отладки (например, через CreateProcess с DEBUG_PROCESS). Если отладчик подключается позже, этот флаг не будет установлен, и проверка NtGlobalFlag не покажет присутствие отладчика

Если отладчик только аттачнут, без включения специальных механизмов, поведение кучи не изменится. Можно проверить это по NtGlobalFlag или по шаблонам в памяти

Вывод: поведение основной кучи процесса может меняться при отладке из-за установки флагов (например, NtGlobalFlag) в момент инициализации процесса. Это не влияет на функцию GetProcessHeap() напрямую, но влияет на то, как эта куча работает (например, добавление проверок и шаблонов памяти)

И всё зависит от того, был ли процесс запущен отладчиком или к нему аттачнулись позже

Пример с IDA
1746101333759.png


Можно сравнить: запуск процесса с нуля и аттач отладчика в IDA (Attach to process), установить точки останова и проанализировать

1746101394538.png

1746101424576.png

Если регистр EAX равен 0, выполнение перейдёт сразу на строку 63

(Инструкция TEST делает побитовую проверку, IDA обычно подсвечивает стрелкой, куда будет переход)

Если же запустить программу напрямую, выполнится строка 62

1746101459917.png



То же самое с ProcessHeap - поведение идентично

1746101473600.png



Однако стоит помнить: этот метод не обходит проверку BeingDebugged

1746101492270.png


Спасибо за внимание!
 
Красавчик, Ахору нужно победить и это первый шаг 👍
 
показал бы как байпасить его. Да и практически все методы есть на одном сайте. А так красавчик.


bypass:
1746106470283.png

1746106494978.png

1746106503444.png
 
Последнее редактирование:
показал бы как байпасить его. Да и практически все методы есть на одном сайте. А так красавчик.
спасибо, в следующих статьях буду показывать метод обхода
 
  • Мне нравится
Реакции: mj12
Антиотладка через NtCurrentPeb

Этот метод в одном crackme использовался

C++:
Expand Collapse Copy
if ((NtCurrentPeb()->ProcessHeap & 0x70) != 0)
  v12 = v10 + v11;

if ((NtCurrentPeb()->NtGlobalFlag & 0x70) != 0)
  v12 = v10 + v11;

if (*&NtCurrentPeb()->BeingDebugged)
{
  v10 = -83;
  v11 = 43;
}

все три приведённых условия - это антиотладочные проверки

Уточнение: NtCurrentPeb() — это неофициальная конструкция, используемая для получения указателя на PEB через сегментные регистры (FS:[0x30] в x86, GS:[0x60] в x64). Официально Windows предоставляет NtCurrentTeb(), возвращающую TEB*, а PEB доступна через TEB::ProcessEnvironmentBlock


NtCurrentPeb

Пожалуйста, авторизуйтесь для просмотра ссылки.
:

NtCurrentTeb — это функция, возвращающая указатель на текущий TEB (Thread Environment Block, блок среды потока)

C++:
Expand Collapse Copy
_TEB* NtCurrentTeb();

Возвращаемое значение: указатель на текущий TEB


ProcessHeap

Пожалуйста, авторизуйтесь для просмотра ссылки.


Комментарий:

Функция GetProcessHeaps возвращает дескриптор основного кучи текущего процесса, а также дескрипторы любых других куч, созданных через HeapCreate

Эта функция в основном используется для отладки, так как возвращённые кучи могли быть созданы другими частями кода и могут быть уничтожены после вызова. Уничтожение кучи делает указатель, возвращённый из GetProcessHeap, недействительным и дальнейшее его использование может привести к неопределённому поведению
Чтобы получить дескриптор основной кучи процесса, можно использовать GetProcessHeap

Почему это работает как антиотладка
BeingDebugged

Эта проверка понятна по названию.
Пожалуйста, авторизуйтесь для просмотра ссылки.


BeingDebugged — флаг, указывающий, отлаживается ли текущий процесс. Однако PEB — это внутренняя структура ОС, и Microsoft не гарантирует стабильность её формата между версиями Windows. CheckRemoteDebuggerPresent — более "официальный" способ проверки, но под капотом он также обращается к PEB

ProcessHeap и NtGlobalFlag

Влияет ли отладчик на активную кучу процесса (основную или созданную динамически) — зависит от того, активированы ли в отладочной среде специальные механизмы отладки кучи


1. Механизмы отладки и поведение кучи
(1) Флаги отладки и поведение кучи

  • NtGlobalFlag
    Если процесс запущен под отладчиком (а не аттачнут), система может установить флаги отладки в PEB, такие как:
    • FLG_HEAP_ENABLE_TAIL_CHECK (0x10) — добавляет защитные значения в конец блока памяти (например, 0xABABABAB) для обнаружения переполнений
    • FLG_HEAP_ENABLE_FREE_CHECK (0x20) — заполняет освобождённую память особыми значениями (например, 0xFEEEFEEE) для обнаружения повреждений
    • FLG_HEAP_VALIDATE_PARAMETERS (0x40) — включает строгую проверку параметров при работе с кучей, может вызывать исключения

Эти флаги изменяют поведение менеджера кучи — размеры блоков, структуру и метаинформацию
  • Page Heap (страничная куча)
    Если включена (через gflags или реестр), каждая куча получает защитную страницу (guard page):
    • Full Page Heap — каждый блок размещается на отдельной странице памяти, а за ним следует защищённая страница. При переполнении сразу срабатывает исключение STATUS_ACCESS_VIOLATION

(2) Шаблоны заполнения при отладке

В режиме отладки куча может быть заполнена специальными шаблонами :
  • Неинициализированная память: 0xBAADF00D
  • Освобождённая память: 0xFEEEFEEE
Эти шаблоны могут влиять на логику программы, если она зависит от содержимого памяти

2. Влияние способа запуска отладчика
(1) Отладчик запускает процесс
  • Система устанавливает флаги отладки (например, NtGlobalFlag) при инициализации процесса, что влияет на структуру основной кучи (GetProcessHeap)
  • Пример: при включённой Page Heap основная куча будет сильно отличаться от обычной
(2) Отладчик аттачится к уже запущенному процессу
  • Простой аттач обычно не меняет конфигурацию уже созданных куч
  • Однако можно вручную включить отладку кучи через команды или HeapSetInformation
Исключение — если используется Application Verifier или включена отладка через реестр

3. Практические последствия
(1) Изменение размера и структуры кучи
  • Отладочные кучи выделяют больше памяти: запрос 100 байт может реально привести к выделению 132 байт (с защитными байтами)
  • Разница в адресах: при Page Heap блоки располагаются в изолированных страницах памяти
(2) Исключения и стабильность
  • Переполнение вызывает сбой: отладочная куча перехватывает такие ошибки, а без отладки программа может просто продолжить выполнение
  • Обращение к освобождённой памяти: при чтении/записи отладчик может поймать исключение
(3) Падение производительности
  • Дополнительные проверки замедляют выделение и освобождение памяти, особенно при частом использовании кучи
Итак, чтобы поведение кучи изменилось:
  1. Процесс должен быть запущен под отладчиком (а не аттачнут)
  2. Должны быть включены отладочные флаги или механизмы (например, Page Heap)
NtGlobalFlag устанавливается системой только в момент создания процесса, если он создаётся с флагом отладки (например, через CreateProcess с DEBUG_PROCESS). Если отладчик подключается позже, этот флаг не будет установлен, и проверка NtGlobalFlag не покажет присутствие отладчика

Если отладчик только аттачнут, без включения специальных механизмов, поведение кучи не изменится. Можно проверить это по NtGlobalFlag или по шаблонам в памяти

Вывод: поведение основной кучи процесса может меняться при отладке из-за установки флагов (например, NtGlobalFlag) в момент инициализации процесса. Это не влияет на функцию GetProcessHeap() напрямую, но влияет на то, как эта куча работает (например, добавление проверок и шаблонов памяти)

И всё зависит от того, был ли процесс запущен отладчиком или к нему аттачнулись позже

Пример с IDA
Посмотреть вложение 305100


Можно сравнить: запуск процесса с нуля и аттач отладчика в IDA (Attach to process), установить точки останова и проанализировать

Посмотреть вложение 305103
Посмотреть вложение 305104
Если регистр EAX равен 0, выполнение перейдёт сразу на строку 63

(Инструкция TEST делает побитовую проверку, IDA обычно подсвечивает стрелкой, куда будет переход)

Если же запустить программу напрямую, выполнится строка 62

Посмотреть вложение 305105


То же самое с ProcessHeap - поведение идентично

Посмотреть вложение 305106


Однако стоит помнить: этот метод не обходит проверку BeingDebugged

Посмотреть вложение 305107

Спасибо за внимание!
Данный метод защиты сегодня не актуален, он обходится 1 патчем, да и нынче в дебаггерах по умолчанию стоит хук на PEB. Статья для начинающих в реверсе очень информативная, продолжай их делать
 
Последнее редактирование:
  • Мне нравится
Реакции: mj12
нам никогда не победить этот байт
 
Спасибо за статью👍
 
Назад
Сверху Снизу