litceysel.ru
добавить свой файл
1 2 ... 18 19

часть 3 противостояние отладке

Введение

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

Френк Херберт "Дети Дюны"


Три основных этапа взлома защитных механизмов это: локализации кода защиты в сотнях килобайт (мегабайт) кода приложения и анализу алгоритма ее работы. Последняя стадия – собственно сам взлом. Все этапы одинаково важны – если, например, не будет пройден второй из них – за взлом нечего и браться.

Можно классифицировать защиты по типу "этапа преткновения". Например, шифры и криптозащиты опираются на третий этап – алгоритм из работы обычно общедоступен, хорошо документирован и в общем случае, известен хакеру, но это не сильно облегчает взлом (разве что упрощает написание лобового переборщика). Механизмы регистрационных номеров, напротив, делают упор на засекречивании алгоритма генерации и затруднении его поиска и анализа в коде программы (еще бы, зная алгоритм можно легко написать кейген).

Однако даже если защита построена с применением криптографических методов, скажем, шифрует тело критически-важный функций криптостойким методом по непомерно-длинному ключу, она может быть "отвязана" от ключа, например, копированием дампа программы после расшифровки. Еще проще – распространять программу вместе с ключом (обычная тактика пиратов). Один из способов воспрепятствовать такому беспределу – заложить в ключ зашифрованную привязку к компьютеру или проверять "чистоту" копии через Интернет (можно даже и втихомолку – скрыто от пользователя, хотя это считается дурным тоном). Но что помешает хакеру, владеющему лицензионной копией программы, расшифровать ее своим ключом и выкусить все-все проверки чего бы там ни было?

Таким образом, любой защите желательно уметь эффективно препятствовать своему обнаружению, анализу, попутно отравляя жизнь дизассемблеру и отладчику – основным инструментам взломщика. Без этого защита – не защита.

В эпоху царствования MS-DOS землей безраздельно владели программы реального режима, монопольно распоряжающиеся процессором, памятью и аппаратурой, беспрепятственно в любой момент переходящиеся в защищенный режим и возвращающиеся обратно. Отладчики в то время (еще хлипкие, немощные, нежизнеспособные) легко обманывались (срубались, завешивались) тривиальными приемами программирования, активно используемыми защитами. Дизассемблеры тогда были очень глупыми и впадали в ступор от одного только вида зашифрованного или самомодифицирующегося кода. Словом, - настоящий рай для разработчиков защит.


Сегодня все изменилось. Прежде всего, прикладной программе под Windows особо выпендриваться никто и не даст. Теперь с защищенным режимом особо не разгонишься – используй прозаические непривилегированные инструкции, а о разных "тигростях" и не помышляй. Та же небольшая часть защитных приемов, что может функционировать в такой "юзеризированной" среде, наталкивается на сильно поумневшие отладчики и дизассемблеры.

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

Существуют и отладчики-эмуляторы, фактически настоящие виртуальные машины, самостоятельно исполняющие код вместо того, чтобы пусть его на "живой" процессор. При этом эмулятор всегда исполняется в режиме супервизора даже по отношению к отлаживаемому коду нулевого кольца. У защиты очень мало шансов обнаружить отладчик или помешать его работе (да и то, если эмулятор реализован с ошибками).

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

Даже если приложение и установит свой vxd (vxd – выполняется в нулевом кольце и может вытворять что угодно), это только облегчит задачу взломщика, т.к. взаимодействовать с vxd защита сможет только через специальный API, что упрощает изучение алгоритма защиты и эмуляцию работу vxd для "отвязки" приложения от электронного ключа или ключевой дискеты.

Но даже на уровне нулевого кольца в Windows очень трудно что-либо скрыть – для обеспечения совместимости со всем парком Windows-подобных операционных систем приходится использовать только документированные возможности. Строить в "окнах" защиту – все равно, что пытаться заблудиться в парке. Будь там хоть миллион деревьев – все они геометрически правильно расположены и обильно увешены табличками "выход – там".


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

обзор способов затруднения анализа программ


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

Строго говоря, сегодня уже не существует действительно хороших и надежных методов противодействия анализу защиты. Мощь современных технологий превзошла самые смелые ожидания прошлых лет. Эта фраза может показаться напыщенной, но в действительности и она не может дать истинного представления о вооружении хакера.

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

Сегодня получили широкое распространение отладчики-эмуляторы. Т.е. интерпретацию микрокода исполняет не процессор, а специально написанная для этой цели программа. При этом интерпретатор всегда исполняется в режиме супервизора по отношению даже к отлаживаемому коду нулевого кольца. У защиты нет ни малейших шансов обнаружить отладчик или помешать его работе.

Интерактивные дизассемблеры тесно взаимодействуют с пользователем, что позволяет обойти любые мыслимые ловушки, расставленные разработчиком защиты по всему коду.

Наконец, популярные операционные системы дают прикладным приложениям не так много привилегий, чтобы их хватило для противодействия отладчикам, даже не ориентированным на взлом. Еще недавно в MS-DOS любая программа могла исполняться в нулевом кольце и работать с аппаратурой исключительно через порты ввода\вывода, минуя операционную систему и BIOS. В Windows же это невозможно. Даже если приложение и установит свой vxd, это только облегчит задачу взломщика, т.к. взаимодействовать с ним защита сможет только через стандартный Win32 API и для хакера не составит труда перехватить и при желании проэмулировать работу vxd, но уже без электронного ключа или ключевой дискеты. Кроме того, сегодня, когда аппаратное обеспечение постоянно меняется прикладная программа никак не может взаимодействовать с ним через порты без риска натолкнуться на несовместимость. К тому же у сетевых рабочих станций весь обмен идет через сеть. Следовательно, любая прикладная программа должна взаимодействовать только с драйвером, но ни в коем случае не с железом, иначе это вызовет отказ от ее использования и переход на продукцию конкурента, что принесет убыток гораздо больший, нежели взлом.


Поэтому прогрессивные разработчики выбирают другие пути. Самый перспективный из них (но вместе с тем и самый сложный) - написание собственного эмулятора процессора, интерпретирующего код защиты. При этом невозможна ни декомпиляция, ни отладка штатными средствами. Взломщик должен проделать трудоемкую и кропотливую работу по изучению архитектуры виртуального процессора, и только потом можно будет написать декомпилятор или отладчик. Только ради чертовски хорошей программы можно потратить столько времени и усилий. Однако если один и тот же виртуальный процессор начнет серийно применяться для защиты программ, то каким бы трудоемким ни был его анализ, он будет рентабельным, ибо с лихвой окупит себя на взломе других приложений.

Можно в шутку сказать: не пытайтесь усложнить хакеру жизнь. Вы только напрасно потеряете силы и время, и ничего хорошего из этого не получится. Если это действительно хакер, то все ваши услия не увенчаются успехом. Однако многие соответствующие приемы любопытны сами по себе; кроме того, полезно знать, как с ними можно справиться. Поэтому ниже этот вопрос будет рассмотрен очень подробно. Возможно, большую часть проблем, относящуюся к MS-DOS, читатель уже неплохо знает. Однако я так же рассматриваю технологии противодействия взломщикам под Windows, которые не были ранее широкоопубликованы и изучены. Замечу, что системный программист под Windows имеет все шансы написать программу, которую трудно взломать даже опытным хакерам. Вскрыть сам защитный механизм не проблема. Куда сложнее найти его во многих мегабайтах кода ломаемого приложения. Сегодня мало кто использует для этой цели автоматическую трассировку – на смену ей пришли аппаратные контрольные точки.

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


Время снятия подобных защит измеряется секундами (!) и обычно такие программы ломаются раньше, чем успевают дойти до легального потребителя. К счастью, этому можно противостоять!

Откуда бы ни бралась ключевая информация – из реестра, файла или клавиатуры, взломщик может практически мгновенно локализовать ее местоположение в памяти и установить на него контрольную точку. Помешать этому нельзя, но не составит труда подложить хакеру неожиданный сюрприз, - путь ключевая информация анализируется не сразу же после получения, а передается в качестве аргумента множеству функций, которые что-то с ней делают и затем передают другим функциям, а те в свою очередь – следующим.

Защитный механизм может быть встроен во что угодно – хоть в процедуру открытия файла или расчета зарплаты. Не стоит делать явных проверок, пусть лучше в случае вызова функции с неверной ключевой информацией она возвратит неправильный результат, но не сигнализирует об ошибке. Взломанная программа на первый взгляд будет исправно работать, и далеко не сразу выяснится, что работает она неправильно (например, выводит на экран одни числа, а на принтер – совсем другие). А чтобы обезопасить легального пользователя от ошибочного ввода пароля, достаточно в одном месте явно проверить его контрольную сумму, которая не дает взломщику никакой информации об истинном значении пароля.

Таким образом, защита как бы "размазывается" по всей программе, буфера с ключевыми данными многократно дублируются и на отслеживание обращений у взломщика не хватит ни контрольных точек, ни терпения для анализа огромного объема манипулирующими с ними кода. Будет еще лучше, если после выполнения проверки ключевой информации, эти же самые буфера использовать для хранения служебных данных, обращение к котором происходит по возможности максимального часто. Это не позволит взломщику быстро отделить защитный механизм от прочего прикладного кода.

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


В такой ситуации взломщику ничего не останется как, затарившись пивом, плотно засесть за кропотливое изучение всего кода программы, прямо или косвенно манипулирующего с ключевой информацией (а это многие мегабайты дизассемблерного листинга!). Если критическая часть кода зашифрована, причем ни в какой момент работы программы не расшифровывается полностью (при выходе в каждую функцию она расшифровывается, а при выходе зашифровывается вновь), хакер не сможет получить готовый к дизассемблированию дамп, и будет вынужден прибегнуть к трассировке. А вот тут его будет жать второй сюрприз!



следующая страница >>