![]() |
Как и всё, что работает под управлением центрального процессора, операционная система – это тоже программа, которая на этапе тестирования требовала отладки. Поскольку системное пространство памяти в Win логически разделено на два региона, инженерам требовались технические люки из юзера в кернел. После того-как всё было (типа)настроено, окончательно избавляться от этих туннелей было уже поздно – пришлось-бы опять переписывать львиную долю кода, что совсем не вдохновляло разработчиков. Поэтому лазейки просто прикрыли фиговым листом в надежде "авось прокатит"..
Это касается таких механизмов как TRAP-бит в регистре флагов Eflags, привелегия Debug в пользовательском режиме, регистры отладки DR0-DR7 и несколько модельно-специфичных регистров MSR. В результате не только админ, но и обычный юзер получил в награду аппаратные рычаги дебага, не воспользоваться которыми было-бы грех – нужно просто отключив шаблонное мышление обратить взор чуть дальше собственного носа. В статье рассматриваются несколько простых фишек, которые помогут нам применить в своих программах довольно могучий защитный приём, с убойным радиусом поражения – это код, который будет трассировать сам-себя, но не будет дебажиться в отладчике. ---------------------------------------- Debug в реальном режиме Начнём с того, что отладка – неотъемлемая часть программирования, и фактически поддерживается на аппаратном уровне через флаг трассировки процессора TRAP-Flag. Манипулируя битами регистра EFLAGS, программист может оперировать флагом TF как в реальном, так и в защищённом режиме работы процессора, и в обоих случаях на единичное его состояние CPU реагирует исключением #DB – Debug Breakpoint. Более того, в независимости от текущего режима, за обработку этого исключения отвечает прерывание INT-1. Обработчик INT-1 в реальном режиме представляет из себя шунт-заглушкуIRET (Interrupt Return), по типу зашёл/вышел без каких-либо действий. По этой причине, без отладчика от взведённого флага TF программам реального режима "не холодно, не жарко". В качестве демонстрации я загрузился под чистым DOS, и в отладчике авера KAV AVPUtil дизассемблировал INT-1 (см.в меню Alt+U): https://forum.antichat.xyz/attachmen...8d2ec9f76f.png Пусть вас не смущает здесь устаревший термин BIOS.. для обратной совместимости он эмулируется всеми современными EFI. Кстати, если запустить виндовый debug, то перед нами предстанет совсем иная картина. Дело в том, что Win32 эмулирует DOS в режиме процессора V86(virtual), и соответственно обработчики у него свои, а не чисто-досовские. Например на 32-битных системах можно запустить debug.com прямо из виндовой консоли и командой Код:
–d 0:0Код:
–u 0070:018bКод: Код:
C:\> debug ;// векторы: INT-1 INT-3Флаг трассировки в защищённом режиме процессора После того как мастдай получает управление от загрузчика (NTLDR в win-xp, или BOOTMGR в win7+) и отправляет на покой реальный режим, картина координально меняется. Теперь уже нету таблицы векторов-прерываний IVT в том смысле, который вкладывает в неё DOS – ей на замену Win выстраивает свою таблицу IDT – Interrupt Dispatch Table (таблица диспетчеризации прерываний) со-своими обработчиками. В защищённом режиме, термин "обработчик" переименовали в ISR – Interrupt Service Routine (подпрограммы сервисов) и делятся они на два типа – "ловушка" (trap)для отлова исключений, и "шлюзы" процедур обработки прерываний. Размер и адрес таблицы IDT хранится в регистреIDTR текущего процессора – с пользовательского уровня этот регистр доступен только для чтения инструкцией SIDT (store IDT). В отличии от остальных регистров, размер его 6-байт, где первые 2-байта определяют размер(лимит) таблицы, а следующие 4-байта – базу таблицы в ядерной памяти. Сама таблица IDT занимает один сегмент виртуальной памяти и состоит из 256 8-байтных дескрипторов – в каждом дескрипторе хранятся флаги доступа и указатель на ISR конкретного прерывания. Код ниже демонстрирует вариант чтения и вывода на консоль значения регистра IDTR: C-подобный: Код:
format pe consoleОтладчик ядерного уровня WinDbg, на команду Код:
!idt –aКод:
INT 0x00..0xFFhttps://forum.antichat.xyz/attachmen...95c9e37fae.png Во-всей этой кухне, важным для нас моментом является то, что отладчики пользовательского уровня вообще не используют аппаратный флаг TF для своей работы, соответственно и прерывание INT-1 остаётся не при делах. По текущему указателю регистра EIP они вставляют только программные бряки INT-3 с однобайтным опкодом Код:
0xCCСамотрассировка – идея фикс.. В общем случае мы пришли к тому, что поведение программы со-взведённым флагом TF напрямую зависит от окружающей обстановки. Отладчики любого цвета и ориентации маскируют TF, перехватывая обращения к нему с любого уровня. Зато в реальной ситуации и без отладчика, при взведённом TF процессор моментально генерит исключение #DB и если оно не обрабатывается пользовательским SEH-фреймом, то диспетчер-исключений тупо прибивает процесс, посчитав его глючным. В 32-битном регистре флагов EFLAGS, бит TF занимает позицию (8), однако мы не можем модифицировать его напрямую и приходиться осуществлять это действие через стек в три этапа – запомнить, чекнуть, восстановить. Вот несколько нехитрых способов установки флага TF в единицу: C-подобный: Код:
;Код:
POPFDhttps://forum.antichat.xyz/attachmen...f855288f50.png Если у кого-то это окно и вызывает отвращение, то нам оно только радует глаз. Самотрассировка - self-Debug - подразумевает установку SEH-обработчика на это исключение, с последующей модификацией флага TF. Внутри обработчика мы можем вытворять со-своим кодом всё-что пожелает наша душа, и это будет абсолютно прозрачно для отладчика! Поскольку он постоянно фиксит флаг TF и обнаружив сразу-же сбрасывает его в нуль, то соответственно и исключения Single-Step под отладчиком не возникает. В результате, пользовательский SEH не получит уже управления, и Оля пойдёт топтать совсем не ту тропинку,. Нужно сказать, что Win32-отладчики поглащают только отладочное исключение #DB, а остальные исправно отлавливают, передавая управление SEH-фрейму юзера. Так-что представленная на суд идея имеет право на жизнь только при взведённом флаге TF с прерыванием INT-1: https://forum.antichat.xyz/attachmen...e0e59151c5.png Оригинальное мнение на счёт взведённого флага TF имеет первая версия отладчика OllyDbg, которая напрочь отказывается трассировать весь последующий код, и позорно капитулирует сообщением типа: "Я не в курсе, как реагировать на команду по этому адресу. Попробуйте установить точку-останова на следующей команде". Если внять совету отладчика и установить по F2 бряк (в данном случае) на адрес Код:
0х0040204Вhttps://forum.antichat.xyz/attachmen...aa6fea4008.png Детали реализации кода Чтобы воплотить идею в жизнь, рассмотрим некоторые её нюансы.. Значит установка пользовательского SEH-обработчика и флага TF в единицу, позволяют перехватить исключение #DB в неотлаживаемом процессе и получить контекст всех регистров CPU. (теме SEH была посвященаотдельная статья). Чтобы лишним стековым SEH-фреймом не привлекать внимание взломщика, хорошей идеей будет не расширять цепочку обработчиков, а модифицировать уже имеющийся системный фрейм с маркером -1, просто подсунув ему указатель на свой обработчик (мы ведь не планируем финализировать свою прожку). В этом случае, в стеке будут маячить уже не два фрейма, а дефолтный один. Пример такой махинации представлен ниже: C-подобный: Код:
;Опытный глаз конечно-же сразу обнаружит подвох с SEH-фреймом, ведь финальный обработчик системы с терминальным Код:
0хFFFFFFFFНа рисунке так-же видно, что вторая версия отладчика OllyDbg категорически не хочет выставлять флаг TF в единицу, и комбинация перезаписи регистра EFLAGS инструкциями Код:
push eax/popfdКод:
0х206Ещё следует обратить внимание на то, что в отличии от реального режима, в защищённом система сбрасывает флаг TF после каждого стэпа, поэтому внутри обработчика его нужно взводить по-новой, чтобы после исполнения очередной инструкции SEH-обработчик опять получил управление. Отметим, что исключение #DB процессор генерит не НА текущей инструкции, а уже ПОСЛЕ её исполнения. Такой алгоритм процессора освобождает нас от постоянной коррекции регистра EIP внутри обработчика – достаточно только взводить TF на каждом шаге, а EIP сам будет скакать по нужным инструкциям. Чтобы убедиться в этом, можно написать тестовый код, который взведёт флаг TF и из регистрового контекста SEH, выведет на экран состояние регистров Код:
EIPКод:
EFLAGSКод:
JMP_SHORThttps://forum.antichat.xyz/attachmen...2d57538eb3.png Практическая часть Приведённый ниже пример демонстрирует эту технику. Я старался сделать его максимально понятным, и убрал из него всё лишнее. Здесь обычная проверка пароля, код которой изначально находится в секции-данных программы, от куда потом копируется в выделенную память SEH-обработчиком. По окончанию, на этот код SEH сразу-же передаёт управление. Алгоритм будет работать только в неотлаживаемом процессе, при взведённом флаге TF. Пароль на валидность проверяется по его хэш-сумме, инклуд "except.inc" предоставляет доступ к структуре CONTEXT процессора, и прикреплён скрепкой в подвале темы(нужно положить его в дир "fasm\include\.."): C-подобный: Код:
format pe consoleОрганизовать это дело совсем не сложно и если кого заинтересует этот приём, мы можем осуществить его вместе. Нужно всего-то добавить в процедуру проверки-пароля "флаг окончания", и внутри SEH-обработчика проверять его на единицу. Если индикатор = нуль, значит взводим TF в регистровом контексте и продолжаем трэйс (менять больше ничего не надо). Соответственно, если "флаг окончания теста" =1, значит оставляем TF сброшенным и заканчиваем трэйс. Заключение (в хорошем смысле слова) Здесь мы рассмотрели только основную идею самотрассировки в надежде, что это послужит генератором идей. В этом направлении, наши возможности ограничивает только фантазия – например, можно озадачить SEH распаковкой или декриптором зашифрованного кода, жонглировать контекстом любых регистров, вплоть до отладочных DR0-DR7 (которые для юзера считаются привилегированными), и многое другое. А всё потому, что в брачном периоде, парнями из Microsoft была заброшена капсула, которая со-временем сыграла злую шутку с отладчиками прикладного уровня – они доверяли флагу TF на все 100%, а он оказался хитрым на все 200. До скорого.. |
Наконец-то) Я уж думал творческий запой у Marylin)
|
Я аж всплакнул, думал не дождусь.
Как же мне нравятся вставки кода в статье) |
Увлекательная статья, автор подскажите а у вас есть такие же идеи по написанию статей по анпакингу
|
@Aleks Binakrilпросьба в комментах оставлять только то, что касается данной темы - остальные вопросы в личку.
|
Marylin,
большое спасибо за статью! |
| Время: 12:27 |