Blog. Just Blog

Использование TLS для антиотладки

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Использование TLS для антиотладки
Использование TLS для антиотладки

TLS (Thread Local Storage) - локальная память потока, предназначенная для связки данных с потоком. Эта структура изначально была создана для решения проблемы совместного доступа к данным в многопоточных приложениях. TLS бывают статичными и динамическими. Углубляться в эти дебри сейчас не будем, для этого есть Джеффри Рихтер с его книгой "Windows для профессионалов". Нас интересует только тот факт, что при использовании статичной TLS появляется возможность выполнять произвольный код до передачи управления на EP. Это можно использовать для обнаружения отладчика еще до того, как он получит управление над программой.

Секция TLS представляет собой структуру с фиксированным порядковым номером 9 и строго определенным набором данных. Нарушать их последовательность ни в коем случае нельзя. Вот как это выглядит на FASM:
  1. ;------------------------------------------------
  2. ; Секция TLS
  3. ;------------------------------------------------
  4. data 9
  5.               dd 0             ; Raw Data Start VA
  6.               dd 0             ; Raw Data End VA
  7.               dd tls_index     ; Address of Index
  8.               dd tls_callbacks ; Address of Callbacks
  9.               dd 0             ; Size of Zero Fill
  10.               dd 0             ; Reserved
  11. tls_index     dd 0             ; Index
  12. tls_callbacks dd anti_debug1   ; Callbacks
  13.               dd anti_debug2
  14.               dd 0             ; End
  15. end data
Немного теории. При запуске любого исполняемого файла системный загрузчик придерживается следующей логики. Сперва загружаются данные из секций импорта и экспорта, затем загрузчик поочередно проверяет все остальные секции. Если при этом будет обнаружена секция под номером 9, а это ни что иное, как TLS, то загрузчик поочередно выполнит все callback-функции, которые прописаны в этой секции. И только после этого управление передается на entry point программы, где может поджидать отладчик. Прелесть в том, что к моменту выполнения функций TLS уже загружены все необходимые библиотеки из импорта и у нас есть доступ к их функциям.

Возвращаемся к структуре. В поле Address of Callbacks прописывается указатель на массив адресов функций, которые должны вызываться при загрузке программы. Массив адресов заканчивается нулевым элементом. Последовательность вызова callback-функций, как несложно догадаться, определяется положением адреса в массиве. Более того, при обработке цепочки callback-функции могут динамически менять или добавлять новые записи в массиве, тут единственное условие, чтобы они стояли после выполняемой в данный момент callback-функции. Загрузчик обрабатывает массив в реальном времени, беря следующую запись только в момент, когда предыдущая callback-функция завершила свою работу.

Для обнаружения отладчика воспользуемся парочкой хорошо известных трюков. Это проверка параметра BeingDebugged из PEB и флага из структуры RTL_USER_PROCESS_PARAMETERS.
  1. ;------------------------------------------------
  2. ; Anti-Debug Trick 1
  3. ;------------------------------------------------
  4. proc anti_debug1
  5.         ; Указатель на РЕВ
  6.         mov     eax,[fs:30h]
  7.         ; Флаг отладки из PEB
  8.         cmp     [eax+PEB.BeingDebugged],0
  9.         ; Отладчик не обнаружен
  10.         jz      .loc_ret
  11.         ...
  12.         ; Действия при обнаружении отладчика
  13.         ...
  14. .loc_ret:
  15.         ret
  16. endp
Если с первым все понятно, по сути это аналог вызова функции IsDebuggerPresent, то по следующему коду я немного поясню. Когда приложение запускается через CreateProcess и любой из флагов DEBUG_PROCESS или DEBUG_ONLY_THIS_PROCESS установлен, то 14-й бит в поле Flags структуры RTL_USER_PROCESS_PARAMETERS обнуляется. При нормальном запуске этот бит равен 1. Тут же используется трюк с добавлением нового обработчика в цепочку callback-функций.
  1. ;------------------------------------------------
  2. ; Anti-Debug Trick 2
  3. ;------------------------------------------------
  4. proc anti_debug2
  5.         ; Указатель на РЕВ
  6.         mov     eax,[fs:30h]
  7.         ; Указатель на PEB.ProcessParameters
  8.         mov     eax,[eax+PEB.ProcessParameters]
  9.         ; Проверить 14-й бит в поле флагов
  10.         test    [eax+RTL_USER_PROCESS_PARAMETERS.Flags],0x4000
  11.         ; Отладчик не обнаружен
  12.         jnz     .loc_ret
  13.         ...
  14.         ; Действия при обнаружении отладчика
  15.         ...
  16. .loc_ret:
  17.         ; Добавить новую запись в цепочку вызовов
  18.         mov     dword [tls_callbacks+4*2],dyn_callback
  19.         mov     dword [tls_callbacks+4*3],0
  20.         ret
  21. endp
  22.  
  23. ;------------------------------------------------
  24. ; Обработчик, который не описан в цепочке вызовов
  25. ; и добавляется динамически в предыдущей функции
  26. ;------------------------------------------------
  27. proc dyn_callback
  28.         ret
  29. endp
С помощью этих трюков легко обнаруживаются отладчики OllyDbg и WinDebug. В качестве противодействия можно использовать плагин Olly Advanced с включенной опцией "Break on TLS Callback" или отладчик x64dbg, где такой функционал есть "из коробки". Дизассемблер IDA Pro также определяет и показывает все вызовы из TLS, так что обнаружить по крайней мере сам факт наличия раннего выполнения кода в программе можно без труда. Конечно, если при этом не используется динамическое изменение цепочки вызовов callback-функций.

TLS-callbacks в дизассемблере IDA Pro
TLS-callbacks в дизассемблере IDA Pro

Несмотря на то, что антиотладочные трюки с использованием TLS давно известны, возможность раннего исполнения кода нельзя недооценивать. Ведь совершенно необязательно сразу кричать об отладке, достаточно взвести какой-нибудь флаг, который будет влиять, например, на корректность расчетов в программе. Да и без поиска отладчиков в callback-функциях TLS можно динамически модифицировать код, расшифровывать какие-нибудь данные и выполнять прочие действия, которые могут надолго озадачить начинающего реверсера.

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

В приложении пример программы с исходным текстом, которая использует TLS для обнаружения отладчика.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

TLS.Antidebug.Demo.zip (1,924 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 2071 | Комментариев: 1

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (01.11.2021 в 02:26):
Добавил пример с динамической модификацией цепочки вызовов. Архив обновлен.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.14 сек. / MySQL: 2 (0.0416 сек.) / Память: 4.5 Mb
Наверх