Библиографическое описание:

Сергеев Р. А. Расширение отладочного интерфейса PyDbg для противодействия антиотладке [Текст] // Технические науки в России и за рубежом: материалы V междунар. науч. конф. (г. Москва, январь 2016 г.). — М.: Буки-Веди, 2016. — С. 10-15.

 

Статья посвящена разработке расширения отладочного интерфейса PyDbg для противодействия антиотладочному приему на основе функции NtQueryInformationProcess. Кратко рассмотрены основные категории антиотладочных техник. Дано описание фреймворка PaiMei и его ключевой части — интерфейса PyDbg. Проанализирована функция NtQueryInformationProcess и возможность ее использования в качестве антиотладочной техники. Приведены описание алгоритма разработанного расширения, а также результаты тестирования расширения.

Ключевые слова: обратная разработка, отладчик, антиотладка, pydgb

 

Вопросы обратной разработки программного обеспечения имеют большое значение на современном этапе развития информационных технологий. Обратная разработка программного обеспечения связана с областью компьютерной безопасности [1, с.5], которой уделяют в последнее время повышенное внимание. Обратной разработке подвергаются, в частности, образцы различных вредоносных программ в целях анализа их функциональности. Для затруднения анализа бинарного кода разработчики часто применяют разные техники, среди которых особое место занимают так называемые антиотладочные приемы. Существование и использование таких приемов явилось причиной появления множества анти-антиотладочных надстроек и плагинов для различных отладчиков. Настоящая работа посвящена разработке анти-антиотладочного расширения для отладочного интерфейса PyDbg фреймворка PaiMei, которое противодействует детектированию отладчика путем вызова функции NtQueryInformationProcess с параметром ProcessInformationClass, равным ProcessDebugPort.

Раскроем понятие антиотладки. Т. Шилдс (ShieldsT.) [2, с. 1] определяет антиотладку следующим образом: «Антиотладка — это реализация одной или более техник в компьютерном коде, которая препятствует попыткам обратной разработки или отладки целевого бинарного файла». Сущность таких техник заключается в детектировании исполнения программы под контролем отладчика. Если детектирование показало наличие отладчика, то программа может, например, изменить свой поток управления таким образом, чтобы скрыть свою вредоносную активность. Приемы антиотладки обычно подразделяют на шесть [2, c. 1] основных категорий: основанная на API антиотладка (вызовы функций IsDebuggerPresent, CheckRemoteDebuggerPresent и др.); антиотладка, основанная на исключениях (используется тот факт, что отладчик отлавливает определенные исключения и может неправильно отправлять их процессу для внутренней обработки); непосредственное детектирование в блоках процесса/треда (например, непосредственная проверка поля BeingDebugged в блоке окружения процесса PEB); детектирование модифицированное кода (расчет CRC определенных блоков кода для удостоверения отсутствия изменений, сделанных из-за отладки); детектирование на основе аппаратного обеспечения и регистров (проверка состояния специальных отладочных регистров процессора и др.); основанная на времени антиотладка (использование того факта, что будучи отлаживаемой программа обычно исполняется намного медленней).

Наличие и применение таких антиотладочных приемов вызвало в свою очередь появление различных анти-антиотладочных надстроек для отладчиков, которые направлены на преодоление тех или иных методов антиотладки. Например, существует коллекция плагинов aadp [3] для различных отладчиков (OllyDbg, ImmunityDebugger), целью которых является сокрытие факта наличия отладчика от большинства известных антиотладочных приемов.

PaiMei — это фреймворк для обратной разработки, включающий в себя множество расширяемых компонентов. Как указывается автором фреймворка П. Амини (AminiP.) в [4]: «PaiMei можно в сущности представлять как швейцарский армейский нож реверс-инженера и он уже доказал эффективность для широкого диапазона статических и динамических задач, таких как: поддержка фаззинга, учет покрытия кода, учет распространения данных и т. д».. PaiMei написан на языке Python и предоставляет отладочный интерфейс PyDbg, библиотеку для представления графов как коллекций вершин, ребер и кластеров pGRAPH, библиотеку на основе pGRAPH для представления бинарных файлов как коллекций функций, базовых блоков и инструкций PIDA. Также в состав фреймворка включены различные утилиты, консоль и скрипты.

PyDbg представляет собой класс, полностью написанный на языке Python и абстрагирующий win32 отладочный интерфейс. В функциональность данного класса входит, в том числе:

                    перечисление процессов, модулей, тредов, работа с ними (enumerate_processes(), enumerate_modules(), suspend_thread() и т. д.);

                    установка аппаратных, программных и основанных на памяти точек останова (bp_set_hw(), bp_set() и т. д.);

                    эффективная работа с памятью (чтение, запись, выделение и интеллектуальное разыменование) (read(), write(), virtual_alloc(), smart_dereference() и т. д.);

                    а также наборы API для получения снимков памяти и их восстановления, раскрутки стека и SEH, обработки исключений и событий, дизассемблирования инструкций и специальные функции-утилиты [5, с.22].

PyDbg является отладочным инструментом, следовательно, этот инструмент подвержен действию антиотладочных приемов.

В классе pydbg присутствует специальный метод hide_debugger(). Данный метод предназначен для сокрытия присутствия отладчика. Для этого данный метод модифицирует поле BeingDebugged структуры блока окружения процесса (PEB) путем записи в него нуля. Таким образом, во-первых, отладчик становится невидимым для тех программ, которые напрямую считывают данный флаг, во-вторых, вызов функции IsDebuggerPresent() не показывает наличие отладчика, так как данная функция зависит от модифицируемого флага. Эксперименты показывают правильную работу данного метода.

Однако, в классе pydbg отсутствует функциональность, которая бы учитывала антиотладочный прием на основе функции NtQueryInformationProcess с параметром ProcessInformationClass, равным ProcessDebugPort.

Функция NtQueryInformationProcess располагается в библиотеке ntdll.dll. Таким образом, строго говоря, данная функция не документирована. Однако, можно найти ее описание и варианты использования в том числе в официальных источниках, предназначенных для разработчиков. С данной функцией нет ассоциированных библиотек импорта, поэтому, если разработчик хочет вызвать данную функцию в своем приложении, он должен использовать функции LoadLibrary и GetProcAddress для динамического связывания с библиотекой Ntdll.dll [6].

Дадим описание данной функции. В соответствии с [6], функция NtQueryInformationProcess извлекает информацию об определенном процессе. Возвращает данная функция значение типа NTSTATUS. Параметры функции следующие: ProcessHandle (тип HANDLE) — описатель процесса, для которого извлекается информация; ProcessInformationClass (тип PROCESSINFOCLASS перечисление) — тип информации о процессе, которая будет извлекаться; ProcessInformation (тип PVOID) — указатель на буфер, предоставляемый вызывающим приложением, в который функция записывает запрашиваемую информацию, размер информации, которая будет записана, зависит от параметра ProcessInformationClass; ProcessInformationLength (тип ULONG) — размер буфера, на который указывает параметр ProcessInformation, в байтах; ReturnLenght (тип PULONG) — указатель на переменную, в которую функция возвращает размер запрошенной информации.

Для целей антиотладки данную функцию можно использовать следующим образом. При указании параметра ProcessInformationClass как ProcessDebugPort (что равно числу 7) функция будет извлекать значение типа DWORD_PTR и помещать его в выходной буфер. Данное значение является номером порта отладчика для процесса. Ненулевое значение показывает, что процесс исполняется под контролем отладчика третьего кольца. Таким образом, в программе может содержаться вызов данной функции с указанными параметрами и последующая проверка выходного буфера. Если буфер содержит ненулевое значение, логика работы программы может изменить поток управления и, например, вредоносная программа завершится, не раскрыв свой основной функционал. Таким образом будет реализована техника антиотладки с использование вызова данной функции. Пример подобного использования функции можно найти, например, в [7].

В экспериментальных целях была разработана тестовая программа, которая вызывает функцию NtQueryInformationProcess с параметром ProcessDebugPort, и, в зависимости от содержимого возвращаемого буфера, выводит два различных сообщения, говорящих либо о присутствии, либо об отсутствии отладчика. Эта программа вначале была протестирована на двух известных отладчиках WinDbg и OllyDbg (без анти-антиотладочных плагинов). Во время работы отладчиков было проинспектировано содержимое буфера в обоих случаях. Оно оказалось одинаково и равно 0xFFFFFFFF(-1), что идентифицирует наличие отладчика и вызывает соответствующую ветвь исполнения программы с соответствующим сообщением. Те же результаты были получены и при работе программы под контролем отладочных средств класса pydbg. Для целей преодоления данной техники антиотладки было реализовано расширение класса pydbg.

Представляемое расширение реализовано в виде добавленного в класс метода, получившего название hide_debug_port(). Данный метод можно вызывать в скриптах на языке Python наряду с другими методами класса pydbg.

Внутренняя работа метода hide_debug_port() заключается в следующем. Во время вызова метода вначале происходит поиск адреса функции NtQueryInformationProcess при помощи метода func_resolve() c указанием библиотеки ntdll.dll. Далее, с помощью метода bp_set() происходит установка точки останова по адресу функции NtQueryInformationProcess, при этом обработчиком данной точки останова указывается специальный разработанный приватный метод __Intercepter(). Далее, с использованием метода iterate_modules() происходит процесс итерации по модулям, загруженным в адресное пространство отлаживаемого процесса. Как только встречается модуль, имя которого заканчивается так: “.exe”, в специально введенные атрибуты класса Size и Base заносятся размер и базовый адрес данного модуля соответственно. Данная информация понадобится в дальнейшем. На этом работа метода hide_debug_port() завершается.

Итак, после вызова метода hide_debug_port() на адресе функции NtQueryInformationProcess установлена точка останова с обработчиком __Intercepter(). Это значит, что всякий раз, когда будет вызываться функция NtQueryInformationProcess (управление будет передаваться по адресу данной функции), будет срабатывать исключение отладки, за которым последует передача управления методу __Intercepter().

Метод __Intercepter() работает по следующему алгоритму. Вначале происходит получение значения указателя стека (регистр esp) из структуры context, которое было на момент срабатывания точки останова, а значит, ровно в начале функции NtQueryInformationProcess. Далее с помощью метода read_process_memory считываются 4 байта по указателю стека. Эти четыре байта представляют собой адрес возврата из функции NtQueryInformationProcess. Далее, подобным образом получается параметр ProcessInformationClass функции NtQueryInformationProcess — считываются 4 байта по адресу esp+8. После выполняются преобразования полученных значений с помощью функции unpack модуля struct, значение ProcessInformationClass дополнительно переводится в тип int. Представляемое анти-антиотладочное расширение направлено на подавление попыток определить наличие отладчика путем вызова функции NtQueryInformationProcess с параметром ProcessDebugPort, исходящих из главного модуля программы. Это обосновывает применение следующей эвристики. Если параметр функции ProcessInformationClass равен числу 7 и адрес возврата попадает в диапазон адресов от Base до Base+Size, то делается вывод, что вызов функции произошел из главного модуля программы, и метод __Intercepter() продолжает работу, иначе происходит выход из данного метода без каких-либо изменений. Отметим, что данная логика может быть быстро и легко удалена из класса pydbg вследствие открытого исходного кода данного класса и удобства языка Python. Это может быть сделано, например, в целях противодействия другим функциям, используемым для антиотладки, которые зависят от результатов функции NtQueryInformationProcess. Эти возможности упоминаются, например, в [8]. Однако, эти случаи не являются предметом настоящей работы.

Итак, пусть вызов функции NtQueryInformationProcess произошел из главного модуля программы. В этом случае с помощью метода bp_set() происходит установка точки останова на адрес возврата. Обработчиком данной точки останова назначается другой специальный разработанный приватный метод __HideIt(). Далее, с помощью метода read_process_memory происходит чтение адреса буфера, который был предоставлен вызывающей стороной и в который запишется информация по результатам работы функции NtQueryInformationProcess. Адрес данного буфера располагается по адресу esp+12. Адрес буфера преобразовывается с помощью функции unpack модуля struct, далее данный адрес сохраняется в специально введенный атрибут addr класса pydbg. После работа метода __Intercepter() заканчивается, происходит возврат значения DBG_CONTINUE.

Теперь, если есть факт установки на адрес возврата точки останова, в работу вступает метод __HideIt(). После завершения функции NtQueryInformationProcess вместо адреса возврата управление передается обработчику точки останова __HideIt(). Внутри данного метода сначала формируется число 0, которое преобразовывается с помощью функции pack модуля struct для последующей записи в адресное пространство отлаживаемого процесса. Далее, при помощи метода write_process_memory происходит запись по адресу в атрибуте addr четырех нулевых байт, что равносильно обнулению возвращаемого функцией NtQueryInformationProcess буфера. Таким образом, последующие проверки вызывающей стороной данного буфера на наличие ненулевых значений (номера порта отладки) для определения присутствия отладчика покажут его отсутствие. Следовательно, антиотладочный прием на основе использования функции NtQueryInformationProcess для определения порта отладки не будет иметь эффекта и будет успешно преодолен. Обобщенная схема работы расширения представлена на рисунке 1.

Рис. 1. Обобщенная схема работы расширения hide_debug_port()

 

Для проверки разработанного расширения был написан тестовый скрипт, использующий метод hide_debug_port(). Данный скрипт запускал упомянутую выше программу (выводящую два разных сообщения в зависимости от результатов работы функции NtQueryInformationProcess) и далее вызывал метод hide_debug_port(). Тестовый исполняемый файл вывел сообщение об отсутствии отладчика, таким образом, эксперимент показал правильную работу разработанного метода hide_debug_port().

Итак, в результате было разработано расширение hide_debug_port() отладочного интерфейса PyDbg, призванное обеспечить сокрытие факта работы отладчика в случаях, когда в качестве антиотладочного приема используется вызов функции NtQueryInformationProcess с параметром ProcessDebugPort. Данное расширение показало свою работоспособность по итогам тестов и может использоваться в практической деятельности специалистов по обратной разработке программного обеспечения.

 

Литература:

 

  1.                Eilam, E. Reversing: Secrets of Reverse Engineering / E. Eilam. — Indianapolis, Indiana: Wiley Publishing, Inc., 2005. — 618 c.
  2.                Shields, T. Anti-Debugging — A Developers View / T. Shields. — URL: http://index-of.es/exploit/Anti-Debugging 8211 A Developers View.pdf (дата обращения: 22.12.2015).
  3.                Anti-Anti-Debugger Plugins. — URL: https://code.google.com/p/aadp/ (дата обращения 22.12.2015).
  4.                Amini, P. Paimei: Overview / P. Amini. — URL: http://pedramamini.com/PaiMei/docs/ (дата обращения: 25.12.2015).
  5.                Amini, P. Paimei — Reverse Engineering framework / P. Amini // RECON2006. — URL: http://www.recon.cx/en/f/pamini-five-finger.pdf (дата обращения: 25.12.2015).
  6.                Microsoft Developer Network: NtQueryInformationProcess function. — URL: https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms684280(v=vs.85).aspx (дата обращения 22.12.2015).
  7.                Tully, J. Introduction Into Windows Anti-Debugging / J. Tully. — URL: http://www.codeproject.com/Articles/29469/Introduction-Into-Windows-Anti-Debugging (дата обращения 14.12.2015).
  8.                Falliere, N. Windows Anti-Debug Reference / N. Falliere. — URL: http://lilxam.free.fr/repo/Cracking/Anti-Debugging/Windows Anti-Debug Reference.pdf (дата обращения 14.12.2015).

Обсуждение

Социальные комментарии Cackle