Версия для печати


Как написать программу, которую будет дешевле купить, чем сломать
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=90

Дмитрий Логинов
дата публикации 28-12-1999 00:00

Как написать программу, которую будет дешевле купить, чем сломать

Неизлечимый зуд писания овладевает многими.
И укореняется в их безумных душах.
Ювенал.

Предисловие
Я решил написать небольшую серию статей (2,3 статьи) на тему "Написание защиты от копирования". Если быть честным, то это будет, скорее всего, дележка опытом на тему "Как написать программу, которую будет дешевле купить, чем сломать". Сразу скажу, что я не собираюсь делиться исходными текстами, но не потому, что я жадный. Просто то, о чем я буду говорить – это описание предметной области той задачи, которую я сформулировал выше. Видя дальнейшие споры на это тему, скажу, что это всего лишь мое мнение, т.е. мое видение этой области и буду рад узнать другие мнения. Учится, всегда пригодится!
Почему я решил поведать свое мнение? В различных конференциях и журналах можно легко найти мнения либо программеров, либо взломщиков-кракеров о той или иной защите. Я не кракер, но имею кое-какой опыт в этом деле, как, в общем-то, и в защите от ломки. Возможно, это выглядит неправдоподобно – "Ломает, но не кракер". Тогда уточню, я не профессиональный кракер. А по моему опыту могу сказать, что людей, профессионально совмещающих, и ломку, и написание чего-нибудь стоящего, я не встречал (хотя возможно такие люди есть). И в той и в другой области есть инструментарий и определенные наработки. Но надо держать руку на пульсе, чтобы быть достаточно квалифицированным для работы. Новые инструменты, статьи, примеры программ, алгоритмов, новые шифры и дыры к ним – все это лучше иметь свеженьким. А на это уходит время, очень много времени!
Но, я что-то отвлекся. Итак, что же я предлагаю. Если Вы хоть раз в своей жизни, по честному, с нуля, ломанули какую-нибудь прогу. Если для Вас слова IDA, HIEW, SOFTICE непросто термины, которые Вам известны. Если Вы профессионально занимаетесь ломкой. Если да - не теряйте времени, не читайте мою статью. Здесь для Вас не будет ничего нового. Для остальных, а я думаю такие найдутся, я поведаю о возможностях современных средств взлома, т.е. о возможностях Ваших потенциальных противников. Я буду очень стараться, чтобы это было просто и интересно. Начнем???

Дыра – это просто ничто,
Но вы можете в ней сломать шею.
О.О'Мелли

"Давным-давно, когда в мире не было еще интегральных схем. Когда мыши еще бегали по полу и жили в норах. Когда люди знакомились по телефону или на улице и называли себя настоящими именами. В те стародавние времена жили тараканы. Так вот, именно в те времена группа тараканов во главе с … черт, имя забыл! Так вот, они вознамерились помешать прогрессу человеческой мысли. Прослышали они, что люди построили БОЛЬШИЕ счеты и что питаются эти счеты исключительно тараканами. Что стало с этими доблестными тараканами - история умалчивает. Но доподлинно известно, что некоторые из них, проникнув в первые машинные залы, попадали под беспощадные электромеханические реле. Англичане почему-то называли тараканов BUGS. Только не зря гибли доблестные таракашки. Смертью своей они не позволяли электричеству бежать дальше. Так тараканы победили электричество. И с тех пор их называют БАГАМИ, а процесс их обнаружения ДЕБАГИРОВАНИЕ или отладка.
Уже потом баги стали мельчать и очень хорошо прятаться. Потребовалось создание нескольких поколений процессоров, чтобы научится ловить баги. Ходят слухи, что некоторые самые мелкие баги прокрались в процессоры и порождают более крупные баги. Как баги размножаются науке не известно. Но зато известно, как их поймать." (Записано со слов Chlora, он же Guga)

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

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

В чем их неудобство:
  1. Неверное определение размеров данных. Ну, например, если в программе есть цикл с использованием оператора MOV AL, BYTE PTR DS:[BX]. Тогда дизассемблер поймет, что туда, куда обращается оператор можно представить как единый блок, например строка STR DB '0123'. Если же Вы обращаетесь туда черте как, как это делают языки высокого уровня, то вы получите вот что:
    Byte1 db 30h ;'0'
    Byte2 db 31h ;'1'
    Byte3 db 32h ;'2'
    Byte4 db 33h ;'3'
    Как это может навредить? Например, вы дизассемблировали программу закрытую HASP ключом. Чтобы ее взломать, вам нужно найти точку входа в HASP API. Она находится сразу за строкой HASPDOSDRV. Черта лысого вы найдете ее после дизассемблирования!
  2. Отсутствие динамики. Статичный анализ. Т.е. если данные в программе зашифрованы, то декомпилятор их не расшифрует! Огромное количество незначимых для Вас команд! Невозможность посмотреть регистры, стек и память! Ну и т.д.
В чем преимущество:
  1. Возможность изменения исходного кода программы.
  2. Невозможность обнаружения.
Что я здесь имел ввиду. Редко, но бывает необходимым внесения крупных изменений в код программы. Прямая вставка двоичных кодов не помогает, т.к. нарушается расположения меток перехода и процедур. Понимаете? Программа – это линейка кода, по которой нам надо ходить нелинейно, прыгать с определенным смещением. Если линейка удлиняется из-за добавления чего-то в середине, все наши смещения будут показывать не туда куда надо. Повторная перекомпиляция вписывает новые смещения для джампов и колов. ЭТО ОЧЕНЬ РЕДКИЙ СЛУЧАЙ, но такое в моей практике было.
Однажды мне пришлось ломать клипперную программу. Для тех, кто не в курсе, скажу, что это самоинтерпретатор. Т.е. все команды языка переводятся в псевдокод, и к каждой из них сверху линкуется инициализация параметров в стеке и вызов процедурки __plankton. Даже IF и вся булевская часть языка реализована таким образом. Попробуй, поменяй условие для IF или FOR! На уровне ассемблера – это очень трудно делать. А, взяв деклиппер, любой дурак сможет. Вот я и смог. ;))
Что касается "невозможности обнаружения". Здесь я не имел ввиду то, что защититься от декомпиляции невозможно, нет. Очень даже запросто! Но некоторые старые отладчики могли залететь на очень простом фокусе. Раньше, в ДОСе, сегменты были ограничены длинной 65535, а точнее стековый указатель SP не может скакать через 0 или 0FFFFH. Поэтому если вы в программе сделаете SP=0 – то многие отладчики повиснут. Это было тогда! Кончено, если вы будете использовать старые отладчики сейчас, то это произойдет и сейчас. Почему это происходило? Ответ прост – прерывания. Отладчику нужен стек, чтобы вызвался обработчик одного из отладочных прерываний. Если стека нет, то … Я помню свою детскую защитку. Я прописывал в заголовок ЕХЕ файла значение SP равным 0, а в начале программы ставил защиту от дизассемблирования, после чего вкатывал нужное SP. Блочок занимал несколько байт и элементарно обходился. Но как я сладостно потирал руки, когда зависали отладчики при загрузке программы, а SOURCER выдавал чепуху.
Но разработчики дизассемблеров давно учли сложности использования своих программ. И появились такие программы, как Хакер-VIEW (HIEW) и IDA (Интерактивный Дизассемблер). В чем их прелесть?
HACKERVIEW выпускается как внешний просмотрщик для Нортона. Вы можете просмотреть любой исполняемый файл по любому смещению. Более того, вы можете "выполнить" какую-то часть программы или собственную программу, написанную естественно на ассемблере. Это позволяет расшифровывать программы и обходить защиту от дизассемблирования. Он понимает, как старые форматы исполняемых файлов DOS-COM и DOS-EXE, так и форматы исполняемых файлов Windows и OS/2.
IDA очень мощное средство работы с ассемблерными текстами программ. Обладает такими же возможностями, как и HACKERVIEW, но имеет более удобный интерфейс. Также очень хорошо предусмотрена архитектура работы программ в Windows. Т.е. такие вещи, как DLL, расширенный режим работы с памятью и т.д. В своей практике я ни разу не использовал IDA для ломки, но для анализа вирусов приходилось. Очень хорошее средство.

Вывод: интерактивные декомпиляторы программ занимают свою нишу в инструментарии кракера. В основном это совместное использование с отладчиками, где основную работу делают отладчики. Дело в том, что программирование, благодаря Windows, в основном стало событийным, а не линейным как это было в ДОСе. Поэтому иногда проще в отладчике поставить брейк-точку на нужное нам событие, анализируем, что за гадости готовит нам программа. И уже после, если того требует необходимость, лезем HEIW в нужную часть программы. Но многие задачи не требуют такого совместного использования. Хотя все, конечно, в первую очередь решает привычка, стиль атаки, которую использует обычно кракер. Мне, например, чаще нравится повозится SOFTICE-ом в проге, и лишь при крайней нужде я запускаю Hiew. Поэтому давайте перейдем к самому интересному.

Второе средство: это отладчики. Трудно сказать, что было первым отладчиком или дебаггером. Но для меня все началось с TurboDebugger`a фирмы Borland. Пакет отладочных инструментов этой фирмы поставлялся с такими продуктами, как TurboAssembler, TurboPascal, TurboC, Borland C/C++.
Началось все с того, что нужно было поменять экранные формы одной широко используемой программы. Дело в том, что там стояла проверка контрольной суммы содержимого экрана, и если там находилось что-то не то!!! Это была система "Клиент-банк", написанная местными умельцами. Естественно, тогда не у всех банков были такие умельцы. Ну, вот и решили в другом банке, скопировать программу и поменять экранные формы, чтобы клиенты знали с каким банком они работают!
Весь процесс ломки не занял много времени. Я тогда был глуп и неопытен. А посему стоял за спиной и выдавал новые идеи на гора. Это был мой первый опыт работы с TurboDebugger`ом, опыт "из-за спины". После чего мне пришлось пережить два своих проекта, в которых было много ассемблера. Тогда я и получил богатый опыт отладки с использованием TurboDebuggera.
Многие из понимающих людей будут смеяться, но первую программу я взломал при помощи TurboDebuggera! Было это сделано по просьбе военных, когда я был на сборах. Уж не знаю, зачем им это надо было. Поручение было следующего плана. В штабе стоял комп, чудо ворождебной техники Intel386 c 4-мя метрами памяти. После институтских двоек, просто песня. Так вот, там был приклеен через интерфейсную плату летный тренажер. Господа офицеры, конечно, больше любили F-19. Но вот, в тренажере были обязаны заниматься.
Тренажер был написан одним столичным ВУЗом и, защита была поставлена с умом. Все исполняемые файлы за редким исключением были зашифрованы. Но, что самое главное расшифровка была повешена на отладочные прерывания INT 1 и INT 3. Это был мой первый опыт "борьбы против потных рук", поэтому действовал я немножечко коряво.
Загрузив прогу в TurboDebugger, я проигнорировал переопределение векторов, и передал управление по адресу "обработчика INT 3". Потом я проанализировал, чего там ждет "обработчик INT 1". Так выделился расшифровщик. Система была проста, как коврик мыши. Все исполняемые модули, вызываемые из главной программы, были зашифрованы простой операцией XOR от ключа длинной 512 байт записанного в определенном секторе винта. Т.е. 1-ый байт ключа ксорился с 1-ым байтом блока, 2-ой со 2-ым и т.д. Я не стал заниматься изысками, вычисляющими ключ. Я написал прогу, которая читает ключ в файл или, если скажут, из файла в сектор на диске. Т.к. военные не умели пользоваться DISKEDITORом, именно поэтому я написал прогу в обе стороны, которую они повезли в ближайшую военную часть, где стоял такой же тренажер, но только винт не форматировали в отличии от моих клиентов.
Я привел этот пример для того, чтобы показать, что, во-первых, защита от дебагирования не самоцель и ей не стоит уделять ей много времени благо все возможные люки уже известны и кракерам и программерам. Во-вторых, шифрование прог не панацея от кракеров. Любой кракер, если получает заказ на взлом, имеет доступ до нормальной копии программы. То есть он ее либо может купить, либо попользовать ее на компе покупателя. Но об этом чуть позднее.
Теперь вернемся к нашим отладчикам. В отладочный пакет фирмы Borland входили 4 отладчика. TD, TD286 и TD386, а также гордость фирмы – отладчик с удаленной машины по COM-порту. Для истории хотел бы упомянуть о TD386. Этот отладчик в отличие от других мог использовать встроенные в процессор возможности по отладке. Т.е. в CONFIG.SYS прописывался драйвер, который переводил процессор в расширенный режим работы, а ДОС пускался в виртуальной машине. Поэтому после него нельзя было пустить что-то, делающие нечто схожее. После чего в самом отладчике можно было установить аппаратное прерывание на какие-то действия программы. Ну, там чтение из памяти, чтение из порта и т.д. Но сделано это было коряво.

Поэтому я с удовольствием для себя открыл SOFTICE, WINICE (просто айс). Этот отладчик до сих пор является лучшим из лучших, и его возможности позволяют крошить в щепы многие защиты. Если вы когда-нибудь видели ДОС-ский AFD. Вам будет легко представить интерфейс этой программы. Несколько невзрачных окон и командный режим работы. Т.е. при переходе из TurboDebuggera и иже с ним, хочется бросить это "чудо". Но разработчики этой программы пошли в нужную сторону. Если вы вспомните большинство отладчиков, то там все их возможности "повешены" на какие-нибудь клавиши или пункты меню. Но на самом деле этого мало!!! В айсе очень много возможностей, клавишей не хватит, и все они реализованы в "макроязык". Ну, например, серия команд установки точек-останова (брейков). (Попробую на память) BPX – брейк на выполнение, BPM – на обращение к памяти, BMSG – на сообщение Windows, BPIO – на обращение к ВУ, BPR – на обращение к участку памяти, BPRW – на обращение к модулю, BPINT – на прерывание. Плюс еще условия на каждую из команд.
Например, мне надо поставить брейк на щелчек левой кнопкой мыши на кнопке в окне. Даем команду TASK, выбираем нужную задачу. Даем команду hwnd <имя задачи>, выбираем нужный handle. Поверьте это не сложно, т.к. кнопка – это ресурс и данные о нем и ее имя известно Windows, а значит и айсу. Так вот, выбираете handle кнопки, а т.к. любой видимый компонент в Windows – это окно, то даем команду bmsg <хендл>. Ой, а как же нажатие мышки. В винде так много сообщений, что не все упомнишь. Не беда, набираем wmsg wm_mouse* и видим, что wm_mousefirst=200H. В принципе, если вы помните символьное имя нужного вам события, можете сразу его использовать. Итак, bmsg <хендл> wm_mousefirst. Как мы знаем в виндах параметры сообщений запихиваются в регистры и еще кой-куда. Так вот, если вам нужно можете к любой команде дописать if <регистр>=<выражение> ( bpio 21 r if al=1 – прерваться если с 21-го порта прочитана 1-ка). Для извращенных способов ломки, когда чтений из LPT-порта море, можно после if-а добавить DO и одну из BPCOUNT, BPMISS, BPTOTAL – это все запишется в журнал. После чего – сиди читай. Да, еще забыл. При указывании в условии IF можно указать операцию над регистром. Например, чудесная команда BPX. Набрав bpx GetWindowText, вы можете смело запущать дальше программу. Она прервется, когда вызовется функция виндов GetWindowText. Например, вам нужно поставить брейк на какую-нибудь другую функцию, но с проверкой параметра. Набираем, bpx OtherFuncName if @(esp+смещение_параметра)=<значение>. Это в старых айсах, в других bpx OtherFuncName if esp->смещение_параметра=<значение>. Вот такой наворот!

Кажется хватит. Нет, стоп, совсем забыл. Айс запускается на уровне ядра, т.е. им можно заходить и отлаживать VXD, DRV. Но не это главное. Такие старинные штуки, как перекрытие векторов INT1 и INT 3 теперь не проходит. Конечно, и у айса есть люки, как его можно обнаружить, но их очень легко увидеть и не допустить использование таких штучек для обнаружения отладки. Айс на самом деле очень удобный интерфейс отладки. Я описал только возможности установки брейков и не затронул остальных возможностей айса, т.к. именно брейки нас сейчас интересуют.

Вывод: С появлением Windows отладка программ стала на порядок проще. И намного удобнее дизассемблирования. Принципиально изменился стиль некоторых атак на защиту программ. Теперь не надо шаг за шагом смотреть на ассемблерные леса, продираться сквозь дебри незначащих кодов и защит. Теперь надо отловить нужное событие и понять как на него реагирует программа. Но это не всегда бывает так просто, как выглядит сейчас на словах. Как и ранее, отладка требует знание архитектуры операционки. Чем лучше вы знаете внутренности виндов, тем проще для вас будет взломать программу. Такой отладчик как SOFTICE сильно упрощает подход к анализу программ, он не требует таких навыков, как дизассемблеры. Хотя это спорный вопрос.

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

Продолжение следует.

Дмитрий Логинов,
28 декабря, специально для «Королевства Дельфи»