Реферат: Примеры реальных взломов

примеры реальных взломов
В качестве подопытных свинок, помогающих продемонстрировать те или иные техники взлома, в настоящей книге используются специальным образом подготовленные программы – так называемые "крякмисы" (от английского "crack.me" – сломай мя, по аналогии с "eat me" – надписью на пирожке, который обнаружила Алиса в Стране Чудес). Автор признает, что многие из "крякмисов" вышли слишком искусственными и далекими от реальных защитных механизмов.

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

Напоминаю, что взлом в той или иной мере конфликтует с российским и международным законодательством, поэтому необходимо помнить, что взлом не освобождает от приобретения лицензионной версии программы и может быть использован только в для удовлетворения собственного любопытства, но не с целью долговременного использования взломанного продукта. Впрочем, на этот счет вам лучше проконсультироваться у квалифицированного юриста, специализирующегося на защите авторских прав.
^ Intel С++ 5.0.1 compiler


Рисунок 1 0х001 Логотип компилятора Intel C++

Прежде, чем приступать к обсуждению аспектов стойкости защиты компилятора Intel C++ 5.0.1, считаю своим долгом заявить, что я глубоко восхищен этим великолепным программным продуктом и ломать его на мой взгляд по меньшей мере кощунственно. Впрочем, сегодня только ленивый не найдет в Сети кряк (один только Google по запросу "Intel C++ crack" выдает свыше 12 тысячи ссылок!), так что никакого вреда от данной публикации не будет.

Немного грустных новостей для начала. Приобрести легальную версию данного компилятора для жителей России оказывается чрезвычайно затруднительно. И вопрос упирается даже не в то "сколько он стоит" (а стоит он, если мне не изменяет память что-то в районе тысячи долларов), – компания Intel просто игнорирует данный сегмент рынка. Обращения в российское представительство компании с просьбой предоставить (за деньги!) данный компилятор для его же описания (читай – рекламы и продвижения) в книге "Техника оптимизации программ" положительных результатов не дали, – даже после того, как к этому вопросу подключились прямо-таки скажем не мелкие отечественные издательства BHV и Солон Р. Ладно, не хотят продавать – ну и не надо! Благо с сервера компании можно свободно утянуть 30-дневный триал. Негусто конечно, но для сравнительного тестирования – вполне достаточно (а для других целей мне этот компилятор и не нужен!).

Впрочем, все оказалось не так просто! С web-сервера компилятор за просто так не отдался, – после заполнения регистрационной формы меня вежливо поблагодарили и сообщили, что сейчас ко мне на мыло упадет письмо с триальной лицензией и инструкцией по ее установке. Это "сейчас" заняло у севера аж несколько дней (такое впечатление, что анкеты просматриваются вручную). ОК! Лицензия получена! Начинаем скачивать файл…. Как это так докачка не поддерживается?! А вот не поддерживается и все! Учитывая, что у меня лишь хлипкий Dial-Up по каналу в 19.200 (да и тот по межгороду) скачать полста мегабайт без единого разрыва просто нереально. К тому же, работа над книгой уже близиться к завершению и вносить в нее еще один компилятор (а, значит, – переписывать кучу текста заново) мне становится просто в лом. Да и Intel C++ это далеко не самый популярный в кругах российских программистов компилятор и книга без него как ни будь уж переживет (хотя, посмотреть как Intel оптимизирует код под свои процессоры очень хотелось, да и документация по компилятору вдохновляла)1.

Разозлившись на весь свет (и на парней из Intel в частности) я отправился на ftp-сервер компании, откуда наскоро, всего за каких-то три дня, слил полнофункциональную (хотя и шибко несвежую) версию компилятора, находящуюся по следующему адресу: ftp://download.intel.com/software/products/downloads/C5.0.1-15.exe. (приятно, что ftp докачку исправно поддерживал и многократные разрывы никаких проблем не вызывали). Польстившись на размер, я скачал именно пятую версию компилятора, которая была в полтора раза легче шестой (под которую у меня имелась неиспользованная триальная лицензия) и аж в два раза компактнее седьмой – новейшей на момент написания этих строк – версии, ломать которую из "политических" соображений я все равно бы не рискнул2, так зачем же ее зря качать?

Теперь, собственно, мы и подходим к известному философскому вопросу: этично ли ломать программный продукт уважаемой тобой компании или без этого можно обойтись? Да если бы без этого было возможно обойтись, я бы – честное слово – без тени сожаления выложил за этот замечательный продукт пачку вечнозеленых, но, увы… компания не проявляет ко мне как покупателю никакого интереса и, кроме как ломать, ничего другого просто не остается!

Итак, инсталлируем Intel C++ и, предварительно скопировав в просроченную лицензию от шестой версии в папку \Intel\Licenses, запускаем головной файл программы:


...\Program Files\Intel\C501\Compiler50\ia32\bin>icl.exe

Intel(R) C++ Compiler for 32-bit applications, Version 5.0.1 Build 010525Z

Copyright (C) 1985-2001 Intel Corporation. All rights reserved.


icl: error: could not checkout FLEXlm license

checkout failed: No such feature exists (-5,357)

^ Листинг 1 ругательное сообщение, выдаваемое компилятором при его запуске

Как и следовало ожидать "could not checkout FLEX lm license" ("не могу проверить FLEX lm лицензию") – компилятор ругается и прекращает свою работу. Ага, стало быть, программа защищена FLEX'ом, – достаточно известным в хакерских кругах менеджером лицензий от компании Globetrotter Inc, представляющим собой достаточно продвинутую защиту интегрированного типа. Разработчик защищаемого приложения получает в свое распоряжение SDK, содержащее как тривиальные функции проверки валидности ключевого файла (лицензии), так и развитые средства динамической шифровки файла. При грамотном подходе к защите запустить защищенную программу без наличия соответствующей ей лицензии доподлинно невозможно. Если часть программы зашифрована, – пытаться расшифровать ее без ключа – дохлое дело. Правда не факт, что парни из Intel действительно использовали шифрование, к тому же, зашифрованные фрагменты иногда удается восстановить по косвенным данным. Это смотря, что еще зашифровано!

Разумеется, при наличии триальной лицензии шифровка снимается без труда, но в том-то все и дело, что триальной лицензии у меня не было! Тем не менее надежда меня не покидала и, перекусив для смелости батоном докторской колбасы, сдобренной значительным количеством кетчупа, я запустил свой любимый дизассемблер IDA, и… не знаю у кого как, а у меня вид консольной IDA, распахнутой на весь экран, всегда вызывает чувство благоговения. ОК, ну-ка посмотрим где скрываются те текстовые строки, которые выводятся при отсутствии лицензии на экран. Результат: ни "No such feature exists", ни "could not checkout" в ASCII-строках (т. е. тех строках, что сумел распознать автоматический анализатор IDA) не найдено. Хорошо, зайдем с другого конца: нажимам для переключения в hex-режим и давим для поиска текстовых строк в "сыром" виде. Что ж, на этот раз поиск "could not checkout" увенчался успехом!


.data1:0042D9C0 63 6F 75 6C 64 20 6E 6F-74 20 63 68 65 63 6B 6F "could not checko"

.data1:0042D9D0 75 74 20 46 4C 45 58 6C-6D 20 6C 69 63 65 6E 73 "ut FLEXlm licens"

.data1:0042D9E0 65 00 00 00 63 6F 75 6C-64 20 6E 6F 74 20 6C 6F "e...could not lo"

.data1:0042D9F0 63 61 74 65 20 46 4C 45-58 6C 6D 20 72 65 67 69 "cate FLEXlm regi"

.data1:0042DA00 73 74 72 79 20 6B 65 79-00 00 00 00 63 6F 75 6C "stry key....coul"

^ Листинг 2 поиск ругательных строк в исполняемом файле (строка, выводимая защитой на экран выделена жирным шрифтом)

Нажимаем еще один раз для возврата в режим дизассемблера, подводим курсор к адресу 42D9C0h и нажимаем для преобразования цепочки байт в ASCII-строку. В результате мы получаем:


.data1:0042D9C0 aCouldNotChecko db 'could not checkout FLEXlm license',0

^ Листинг 3 определение адреса ругательной строки (выделен жирным шрифтом)

А как узнать: кто же выводит строку-ругательство на экран? Нет ничего проще! Вновь переключившись в режим дизассемблера по , давим для поиска последовательности "C0 D9 42 00" – адрес строки, представленный в обратном (с учетом порядка следования старших байтов) виде. Опа! Мы видим код наподобие следующего:


.data:00420CE8 db ^ 0С0h

.data:00420CE9 db 0D9h ; ▐

.data:00420CEA db 42h ; B

.data:00420CEB db 0 ;

.data:00420CEC db 1 ;

.data:00420CED db 0 ;

.data:00420CEE db 0 ;

.data:00420CEF db 0 ;

.data:00420CF0 db 2Ch

.data:00420CF1 db 0DEh ; ▐

.data:00420CF2 db 42h ; B

.data:00420CF3 db 0 ;

.data:00420CF4 db 2 ;

.data:00420CF5 db 0 ;

.data:00420CF6 db 0 ;

.data:00420CF7 db 0 ;

^ Листинг 4 результат поиска обращений к ругательной строке по ее адресу (выделен жирным шрифтом)

Косвенный вызов строки! Ну, собственного, этого и следовало ожидать (иначе с чего бы это автоматических анализатор IDA их не распознал?). Хорошо, преобразуем двойные слова в смещения, руководствуясь при этом тем, что число "42h" должно выпадать на младший байт старшего слова (иначе адрес ссылки уйдет за диапазон предельно допустимых значений) и получаем:


.data:00420DE8 dd offset aCouldNotLoca_0 ; "could not locate FLEXlm registry direct"

.data:00420DEC dd 21h

.data:00420DF0 dd offset aCouldNotLocate ; "could not locate FLEXlm registry key"

.data:00420DF4 dd 22h

.data:00420DF8 dd offset aCouldNotChecko ; "could not checkout FLEXlm license"

.data:00420DFC dd 23h

^ Листинг 5 восстановление структуры, хранящей смещения ругательных строк

Попробуем теперь найти ту су…, в общем тот код, что обращается к указателю на ругательную строку, расположенному по адресу 420CE8h? Не надо спешить! По виду полученной таблицы смещений можно с уверенностью заключить, что прямого обращения к ее элементам не будет. Можно предположить, что числа, стоящие возле ссылок на строки – это коды ошибок, а сами строки – соответствующие тексты сообщений. Если так, то с вероятностью близкой к единице, разработчиками программы использовалась относительная адресация, т. е. для вычисления эффективного адреса элемента ее смещение в таблицы суммируются с базовым адресом таблицы, – единственным адресом, который загружается явно.

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


.data:00420CDE db 0 ;

.data:00420CDF db 0 ;

.data:00420CE0 off_420CE0 dd offset unk_42DE80 ; DATA XREF:sub_403370+5Er

.data:00420CE4 dword_420CE4 dd 0 ; ^ DATA XREF:sub_403370+19r

.data:00420CE4 ; sub_403370+39↑r

.data:00420CE8 dd offset aCouldNotFindD ; "could not find dir…"

.data:00420CEC dd 1

Листинг 6 поиск вероятного начала таблицы смещений (выделено серой заливкой)

Ага! Есть две перекрестных ссылки! Это хорошо! Теперь поднимемся по ним вверх, – прямиком к вызывающему их коду? Можно, конечно, поступить и так, но есть и более универсальное решение: запустив soft-ice, мы устанавливаем точку останова на чтение ячейки 420DE8h (если вы еще не забыли – это адрес элемента таблицы, ссылающийся на искомую ругательную строку). Теперь – кто бы к ней не обращался, soft-ice обязательно всплывет, и ведь действительно он всплывает! Пару раз отдаем команду "P RET", поднимающую нас из дебрей глубоко вложенных процедур поближе к свету. Наконец, мы взбирается на вершину стека и очередной "P RET" приводит к завершению программы. ОК, повторяем все заново, делая на этот раз на один "P RET" меньше. Записываем любой из близлежащих адресов (пусть это будет для определенности адрес 4031C4h) и натравливаем на него IDA.


.text:004031C4 call lc_checkout

.text:004031C9 test eax, eax

.text:004031CB jz short loc_403215

.text:004031CD cmp eax, 0FFFFFFF6h

.text:004031D0 jz loc_41B000

.text:004031D6 cmp eax, 0FFFFFFB7h

.text:004031D9 jz loc_41B01A

.text:004031DF

.text:004031DF loc_4031DF: ; CODE XREF:.text:0041B015

.text:004031DF ; .text1:0041B026↓j

.text:004031DF mov [esp+240h+var_240], 23h

.text:004031E6 call sub_405B00

.text:004031EB mov eax, dword_424C9C

.text:004031F0 mov [esp+240h+var_240], eax

.text:004031F3 mov [esp+240h+var_23C], offset aCheckoutFailed

.text:004031FB call lc_perror

.text:00403200 mov eax, dword_424C9C

.text:00403205 mov [esp+240h+var_240], eax

.text:00403208 call lc_get_errno

.text:0040320D mov [esp+240h+var_240], eax

.text:00403210 call sub_405BA0

.text:00403215

.text:00403215 loc_403215: ; CODE XREF:sub_403000+1CB

.text:00403215 mov eax, dword_424C9C

.text:0040321A mov edx, dword_421E3C

.text:00403220 mov [esp+240h+var_240], eax

.text:00403223 mov [esp+240h+var_23C], edx

.text:00403227 call lc_auth_data

.text:0040322C mov edx, eax

.text:0040322E mov eax, dword_424C9C

.text:00403233 call sub_40A6F8

^ Листинг 7 сердце защитного механизма (говорящие за себя имена функций выделены жирным шрифтом)

Вот это да! – восклицаем мы, пришибленно уставившись на экран. Многое мы ожидали от IDA, но вот чтобы она так запросто представила символьные имена защитных функций, говорящих за себя: lc_chekout, lc_perror, lc_auth_data… Черт, возьми, как?! Вдохновленные смутной надеждой мы неуверенно подгоняем курсор к lc_chekout и нажимаем на .


.idata:0041D12C ; Imports from LMGR327A.dll

.idata:0041D12C ;

.idata:0041D12C extrn __imp_lc_init:dword ; DATA XREF: lc_init↑r

.idata:0041D130 extrn __imp_lc_expire_days:dword

.idata:0041D130 ; DATA XREF: lc_expire_days↑r

.idata:0041D134 extrn __imp_lc_free_job:dword ; DATA XREF: lc_free_job↑r

.idata:0041D138 extrn __imp_lc_checkin:dword ; DATA XREF: lc_checkin↑r

.idata:0041D13C extrn __imp_lc_auth_data:dword ; DATA XREF: lc_auth_data↑r

.idata:0041D140 extrn __imp_lc_get_errno:dword ; DATA XREF: lc_get_errno↑r

.idata:0041D144 extrn __imp_lc_perror:dword ; DATA XREF: lc_perror↑r

.idata:0041D148 extrn __imp_lc_checkout:dword ; DATA XREF: lc_checkout↑r

.idata:0041D14C extrn __imp_lc_set_attr:dword ; DATA XREF: lc_set_attr↑r

^ Листинг 8 символьные имена функций, экспортируемые защитным модулем

Святой Кондратий! И это они еще называют защитой?! Все защитные функции вынесены в отдельную динамическую библиотеку (наверное, чтобы взломщику разбираться было легче?) – LMGR327A.DLL, в названии которой угадывается "Library ManaGeR", причем, это штатные функции FLEX lm, описание которых можно найти в его же SDK (хоть SDK на FLEX ln с компилятором и не поставляется, найти его в Сети – плевое дело).

Отыскав в текущем каталоге этот самый LMGR327A.DLL, мы открываем его HIEW'ом на предмет полного переписывания функции lc_checkout. Ну, насчет "переписывания" автор, ясное дело, загнул. Всего-то и требуется, – заставить lc_checkout всегда возвращать нуль, для чего первые две команды ее тела должны выглядеть приблизительно так: "XOR EAX, EAX/RETN". Записываемся и с дрожью в сердце, запускам icl.exe на выполнение. Критическая ошибка приложения? А чего мы хотели?! Ведь теперь функция lc_auth_data получает неверные данные и гробит все к черту. Впрочем, не будет спешить. Беглое исследование процедуры sub_40A6F8 как будто не выявляет никаких следов шифрования и поэтому ее можно смело удалить, не забыв тоже самое "на всякий пожарный" случай проделать и с lc_auth_data (самое простое – впихнуть в ее начало RETN). Сохраняемся, запускам icl.exe и… компилятор работает! Все! Больше тут нечего ломать!

Самое забавное, что размер защитного механизма (413 Кб) в два с половиной раза превышает размер защищенной с его помощью программы (176 Кб)! Как говорится – no comment.
^ Intel Fortran 4.5


Рисунок 2 0х002 Логотип Intel Fortran Compiler

Ситуация с этим компилятором вкратце такова. В процессе работы над третьим томом "^ Образа мышления IDA" я исследовал большое количество компиляторов на предмет особенностей их кодогенерации и вытекающих отсюда трудностей восстановления исходного кода. Не избежал этой участи и "Intel Fortran Compiler", обнаруженный на диске "Научись сам программировать на FORTRAN". Краткая аннотация на буклете гласила "Intel FORTRAN Compiler 4.5 – новейшая версия знаменитого компилятора. Для регистрации программы смотрите поддиректорию CRACK". Ну, на счет "новейшего" составили диска явно приврали, т. к. на тот момент уже вышла седьмая версия, да и CRACK оказался некорректным. Вместо того, чтобы ломать защиту, он ломал сам компилятор, необратимо его гробя. К счастью, оригинальный ifl.exe на диске все-таки имелся и это давало возможность заставить работать компилятор мне самому. В конце концов использовать в коммерческих целях этот, бесспорно, замечательный программный продукт я все равно не собирался, а для серии тестовых прогонов не то, что месяца (положенного мне по праву) даже нескольких дней было вполне предостаточно, поэтому с этической точки зрения ничего кощунственного я не совершал (просто мне очень уж не хотелось тянуть ~160 метров из Интернета, с моим междугородним Интернетом это действительно проблематично).

Итак, запускаем оригинальный файл компилятора на выполнение и лицезрим как он спускает на нас Полкана (ругается в смысле):


KPNC$C:\Program Files\Intel\compiler45\bin>ifl1.exe >1

Intel(R) Fortran Compiler Version 4.5 000403

Copyright (C) 1985-2000 Intel Corporation. All rights reserved.

Evaluation Copy

ifl1: error: The evaluation period has expired.


The evaluation period for this trial version of the

Intel(R) Fortran Compiler has expired. For product ordering

information, please refer to the product release notes or visit the

Intel Developer web site at the following URL:


http://developer.intel.com/vtune

^ Листинг 9 ругательное сообщение, выдаваемое компилятором при его запуске

Ни слова о FLEX lm! (см. "Intel С++ 5.0.1 compiler") и файл LMGxxx.DLL отсутствует. Странно! Похоже, что Fortran Compiler защищен иначе, что, собственно и не удивительно, поскольку их делали разные группы.

Что ж, запускаем IDA и натравливаем на нее исполняемый файл, который, кстати, занимает всего 176,128 Кб, что с точностью до байта соответствует размеру Intel C++ 5.0.1 compiler. Странно! Но, как бы там ни было, ASCII-строки "The evaluation period has expired" автоматический анализатор IDA в тексте дизассемблируемого файла так и не нашел. Что ж, тогда мы сделаем это сами. , , "The evaluation period" и…


.data1:0042A220 54 68 65 20 65 76 61 6C-75 61 74 69 6F 6E 20 70 "The evaluation p"

.data1:0042A230 65 72 69 6F 64 20 68 61-73 20 65 78 70 69 72 65 "eriod has expire"

.data1:0042A240 64 2E 0A 0A 20 20 20 20-54 68 65 20 65 76 61 6C "d.◙◙ The eval"

.data1:0042A250 75 61 74 69 6F 6E 20 70-65 72 69 6F 64 20 66 6F "uation period fo"

.data1:0042A260 72 20 74 68 69 73 20 74-72 69 61 6C 20 76 65 72 "r this trial ver"

.data1:0042A270 73 69 6F 6E 20 6F 66 20-74 68 65 0A 20 20 20 20 "sion of the◙ "

^ Листинг 10 результат поиска ругательных сообщений контекстным поиском (адрес строки и сама строка выделены жирным шрифтом)

Теперь, вновь нажимаем для поиска последовательности "20 A2 42 00" – адреса начала строки, заданной в обратном виде. Результат не заставляет себя долго ждать:


.data:00419390 60 A3 42 00 4F 00 00 00-20 A2 42 00 50 00 00 00 "`гB.O... вB.P..."

.data:004193A0 00 A2 42 00 51 00 00 00-E0 A1 42 00 52 00 00 00 ".вB.Q...рбB.R..."

.data:004193B0 C0 A1 42 00 53 00 00 00-A0 A1 42 00 54 00 00 00 "└бB.S...абB.T..."

.data:004193C0 60 A1 42 00 55 00 00 00-40 A1 42 00 56 00 00 00 "`бB.U...@бB.V..."

.data:004193D0 20 A1 42 00 57 00 00 00-00 A1 42 00 58 00 00 00 " бB.W....бB.X..."

^ Листинг 11 поиск обращений к ругательной строке по ее адресу (выделено жирным)

Переключаемся обратно в дизассемблер, трижды жмем для преобразования цепочки байт в двойное слово, затем для перевода его в смещение и… в результате таких манипуляций получаем приблизительно такую же таблицу, как и в нашем предыдущем случае с Intel C++:


.data:00419390 dd offset aSNoteTheEvalua ; "%s: NOTE: The evaluation period for thi"

.data:00419394 dd 4Fh

.data:00419398 dd offset aTheEvaluationP ; "The evaluation period has expired.\n\n "

.data:0041939C dd 50h

.data:004193A0 dd offset aCommandLineErr ; "Command line error"

.data:004193A4 dd 51h

.data:004193A8 dd offset aCommandLineWar ; "Command line warning"

.data:004193AC dd 52h

^ Листинг 12 восстановление таблицы смещений строк (адрес "нашей" строки выделен жирным шрифтом)

А посему и действовать мы будем точно так же: поставим бряк на адрес 0419390h и дождемся пока отладчик не получит управления. Кстати, на счет отладчика. В момент написания этих строк у автора как раз закачивалась седьмая версия компилятора Intel C++ и от использования soft-ice пришлось воздержаться (в момент своей активации soft-ice полностью "замораживает" операционную систему, что пагубно влияет на Интернет, а точнее на установленные TCP/IP соединения). И вместо soft-ice автор решил для разнообразия использовать Microsoft WDB, который кстати, справился со своей задачей ничуть не хуже.

Запускам WDB на выполнение, нажимаем , указываем имя загружаемого файла, переходим в окно команд ("Command Window") и устанавливаем точку остановка на адрес 0419398h для чего отдаем команду "BA r4 0x0419398" (что расшифровывается как: "Break on Access of Read 4 bytes long"). Затем для продолжения выполнения программы пишем "G" и с полсекунды ждем…




^ Рисунок 3 0х003 Внешний вид отладчика MS WBD в процессе ломания программы

Ага, отладчик говорит "Hard coded breakpoint hit" ("сработала аппаратная точка останова") и приостанавливает выполнение отлаживаемой программы. Сама же отлаживаемая программа к этому моменту уже успела вывести на экран:


Intel(R) Fortran Compiler Version 4.5 000403

Copyright (C) 1985-2000 Intel Corporation. All rights reserved.

Evaluation Copy

ifl1: error:

Листинг 13 вывод программы на экран

Обратите внимание на строку, выделенную жирным шрифтом! Очевидно, она свидетельствует о том, что мы попали не в самое начало защитной процедуры, а где-то в ее середину. Кстати, а что у нас там лежит на стеке? Смотрим (~View  Stack, см. рис. 0х003). Всего три адреса, – довольно неглубокий уровень вложения не так ли? Причем (обратив свой взор к окну дизассемблера), сейчас уровень вложения еще понизится, т. к. следующей командой мы выходим из этой процедуры:


0040C4CC 8B00 mov eax,dword ptr [eax]

0040C4CE 83C414 add esp,14

0040C4D1 C3 ret

Листинг 14 выход из вложенной процедуры на один уровень вверх

Теперь неспешно трассируем код, попеременно поглядывая то на дизассемблированный листинг, то на консоль отлаживаемой программы. Следующая трассируемая функция (внутрь которой мы не заходим, а "заглатываем" ее одним нажатием ) выводит на экран "The evolution period has expired", но не завершает программу, а продолжает ее выполнение. Что ж! Тогда и мы продолжим (трассировку)! Вызов функции 040F5FEh проходит без каких либо внешних проявлений и, так и не поняв, зачем она собственно нужна, мы поднимается на еще один уровень вверх, куда нас забрасывает завершающий функцию RET.


00403C7C E833880000 call 0040C4B4

; отсюда ^^^^^^^^^^^^^^^^^^^^^ мы только что вышли


00403C81 89442404 mov dword ptr [esp+4],eax

00403C85 891C24 mov dword ptr [esp],ebx

00403C88 896C2408 mov dword ptr [esp+8],ebp

00403C8C E8A8BB0000 call 0040F839

; эта процедура выводит "The evaluation period has expired."


00403C91 C70424C04C4200 mov dword ptr [esp],424CC0h

00403C98 895C2404 mov dword ptr [esp+4],ebx

00403C9C E85DB90000 call 0040F5FE

; эта процедура ничего не делает


00403CA1 83C414 add esp,14h

00403CA4 5B pop ebx

00403CA5 5D pop ebp

00403CA6 C3 ret

^ Листинг 15 тупая трассировка программы с комментариями

…и таким Макаром мы трассируем код до тех пор, пока не наткнемся на следующую конструкцию:


0040105A E8E1800000 call 00409140 ; отсюда мы только что вышли по RETN

^ 0040105F 0FB6C0 movzx eax,al

00401062 85C0 test eax,eax

00401064 0F84C4000000 je 0040112E

Листинг 16 первое, встретившееся нам ветвление, анализирующее значение, возращенное дочерней функцией (условный переход выделен жирным шрифтом)

…что в ней необычного? А то, что это первая встретившаяся нам материнская процедура, которая анализирует код возврата дочерней функции. В нашем случае регистр EAX содержит значение "ноль" и, стало быть, следующий условный переход выполняется. Но не тот ли это переход который нам нужен? Что ж, сейчас мы это узнаем – нажимаем клавишу еще несколько раз… Опля! Наш условный переход перебрасывает нас на ту ветку программы, которая спустя несколько команд скоропостижно сдыхает, захлопывая окно программы. А что произойдет, если команду "JE" в строке 401064h заменить на противоположную (или, как вариант, просто удалить этот условный переход)? Пробуем…

Компилятор по прежнему смачно ругается на "evaluation expired", но… он работает! Работает!! Работает!!! По соображением экономии экранного места (в самом деле, ругательство занимает чуть ли не половину экрана и смотрится крайне некрасиво) мы забиваем вызов процедуры 0409140h командами NOP. Проверяем – сработало ли? Ну… это смотря как посмотреть. Трехэтажный мат действительно исчез, но вот лаконичная строка "Evaluation Copy" так и осталась. Найдем что за код ее выводит? Зачем? – лучше найти саму эту строку и тем же HIEW'ом ее переписать во что ни будь более привычное, например: "hacked by mother-fucker guy". Переписываем, и… пользуемся компилятором в свое удовольствие, не забывая, однако о том, что по истечении 30-дневного срока вы будете должны его стереть, в противном случае вы поступите очень и очень нехорошо, да и незаконно.
^ Intel C++ 7.0 compiler
…компилятор Intel C++ 7.0 докачался глубокой ночью, часу где-то в пятом утра. Спать хотелось неимоверно, но и любопытство: была ли усилена защита или нет, тоже раздирало. Решив, что до тех пор, пока не разберусь с защитой я все равно не усну, я, открыв новую консоль, и переустановив системные переменные TEMP и TMP на каталог C:\TEMP, наскоро набил неприлично длинное имя инсталлятора W_CC_P_7.0.073.exe в командной строке (необходимость в установке переменных TEMP и TMP объясняется тем, что в Windows 2000 они по умолчанию указывают на очень глубоко вложенный каталог, а инсталлятор Intel C++ – да и не только он – не поддерживает путей такого огромного размера).

Сразу же выяснилось, что политика защиты была кардинально пересмотрена и теперь наличие лицензии проверялось уже на стадии установки программы (в версии 5.x установка осуществлялось без проблем). ОК, даем команду dir и смотрим на содержимое того, с чем нам сейчас предстоит воевать:


>dir

Содержимое папки C:\TMP\IntelC++Compiler70

17.03.2003 05:10 html

17.03.2003 05:11 x86

17.03.2003 05:11 Itanium

17.03.2003 05:11 notes

05.06.2002 10:35 45 056 AutoRun.exe

10.07.2001 12:56 27 autorun.inf

29.10.2002 11:25 2 831 ccompindex.htm

24.10.2002 08:12 126 976 ChkLic.dll

18.10.2002 22:37 552 960 chklic.exe

17.10.2002 16:29 28 663 CLicense.rtf

17.10.2002 16:35 386 credist.txt

16.10.2002 17:02 34 136 Crelnotes.htm

19.03.2002 14:28 4 635 PLSuite.htm

21.02.2002 12:39 2 478 register.htm

02.10.2002 14:51 40 960 Setup.exe

02.10.2002 10:40 151 Setup.ini

10.07.2001 12:56 184 setup.mwg

19 файлов 2 519 238 байт

6 папок 886 571 008 байт свободно

Листинг 17 содержимое распакованного дистрибьютива (файлы, содержащие защиту, выделены жирным шрифтом)

Ага! Программа установки setup.exe занимает всего сорок с хвостиком килобайт. Очень хорошо! В такой объем серьезную защиту навряд ли спрячешь, а если даже так – этот крохотный файл ничего не стоит проанализировать целиком – до последнего байта дизассемблерного листинга. Впрочем, не факт, что защитный код расположен именно в setup.exe, он может находится и в другой месте, вот например… ChkLic.dll/ChkLic.exe, занимающими в совокупности немногим менее семисот килобайт. Постой, какой такой ChkLic? Это сокращение от Check License что ли?! Гм, у ребят из Intel очевидно серьезные проблемы с чувством юмора. Уж лучше бы они назвали этот файл "Hack Me" честное слово! Ладно, судя по объему, ChkLic это тот самый FLEX lm и есть, а с ним мы уже сталкивались (см. "Intel C++ 5.0.1 complier") и приблизительно представляем как его ломать.

Даем команду "dumpbin /EXPORTS ChkLic.dll" для исследования экспортируемых функций и… крепко держимся за Клаву, чтобы не упасть со стула:


Dump of file ChkLic.dll


File Type: DLL


Section contains the following exports for ChkLic.dll


0 characteristics

3DB438B4 time date stamp Mon Oct 21 21:26:12 2002

0.00 version

1 ordinal base

1 number of functions

1 number of names


ordinal hint RVA name


1 0 000010A0 _CheckValidLicense

Листинг 18 символьное имя функции, экспортируемой защитным модулем

Черт побери! Защита экспортирует всего одну-единственную функцию с замечательным именем CheckValidLicense. "Замечательным" – потому, что назначение функции становится понятным ее названия и появляется возможность избежать кропотливого анализа дизассемблерного кода. Ну вот, отбили весь интерес… уж лучше бы они ее по ординалу экспортировали что ли, или, по крайней мере, окрестили ее каким ни будь отпугивающим именем типа DES Decrypt.

…размечтались! Ладно, вернемся к нашим баранам. Давайте рассуждать логически: если весь защитный код сосредоточен непосредственно в ChkLic.dll (а, судя по "навесному" характеру защиты, это действительно так), то вся "защита" сводится к вызову CheckValidLicense из Setup.exe и проверке возращенного ею результата. Поэтому для "взлома" достаточно лишь пропадчить ChkLic.dll, заставляя функцию ChekValidLicense всегда возвращать… да, кстати, что она должна возвращать? Точнее: какое именно возвращаемое значение соответствует успешной проверки лицензии? Нет, не торопитесь дизассемблировать setup.exe для определения, ведь возможных вариантов не так уже и много: либо FALSE, либо TRUE. Вы делаете ставку на TRUE? Что ж, в каком-то смысле это логично, но с другой стороны: а почему мы, собственно, решили, что функция CheckValidLicense возвращает именно флаг успешности операции, а не код ошибки? Ведь должна же она как-то мотивировать причины отказа устанавливать компилятор: файл с лицензией не найден, файл поврежден, лицензия просрочена и так далее? Хорошо, попробуем возвратить ноль, а если это не прокатит, возвратим единицу.

ОК, пристегивайтесь, поехали! Запускаем HIEW, открываем файл ChkLic.dll (если же он не открывается – трижды помянув сусликов, временно скопируем его в корневую или любую другую директорию, не содержащую в своем имени спецсимволов, которые так не нравятся HIEW'у). Затем, обратившись еще раз к таблице экспорта, полученной с помощью dumpbin, определяем адрес функции CheckValidLicense (в данном случае 010A0h) и через , ".10A0" переходим в ее начало. Теперь, – режем по "живому", перезаписывая поверх старого кода "XOR EAX, EAX/RETN 4". Почему именно "REN 4", а не просто "RET"? Да потому, что функция поддерживает соглашение stdcall, о чем можно узнать взглянув в HIEW'e на ее эпилог (просто пролистывайте экран дизассемблера вниз до тех пор, пока не встретите RET).

Проверяем… Это работает!!! Несмотря на отсутствие лицензии, инсталлятор, не задавая лишних вопросов, начинает установку! Стало быть, защита пала. Ой, не верится нам, что все так просто и, чтобы не сидеть, тупо уставившись в монитор в ожидании завершения процесса инсталляции программы, мы натравливаем на setup.exe свой любимый дизассемблер IDA. Первое, что бросается в глаза, отсутствие CheckValidLicense в списке импортируемых функций. Может быть, она файл ChkLic.exe как-то запускает? Пробуем найти соответствующую ссылку среди автоматически распознанных строк: "~View Names", "ChkLic"… строки "Chklic.exe" здесь вообще нет, но зато обнаруживается "Chklic.dll". Ага, понятно, значит, библиотека ChkLic загружается явной компоновкой через LoadLibrary. И переход по перекрестной ссылке подтверждает это:


.text:0040175D push offset aChklic_dll ; lpLibFileName

.text:00401762 call ds:LoadLibraryA

.text:00401762 ; загружаем ChkLic.dll ^^^^^^^^^^^^^^^^^

.text:00401762 ;

.text:00401768 mov esi, eax

.text:0040176A push offset a_checkvalidlic ; lpProcName

.text:0040176F push esi ; hModule

.text:00401770 call ds:GetProcAddress

.text:00401770 ; получаем адрес функции CheckValidLicense

.text:00401770 ;

.text:00401776 cmp esi, ebx

.text:00401778 jz loc_40192E

.text:00401778 ; если такой библиотеки нет, то выходим из программы установки

.text:00401778 ;

.text:0040177E cmp eax, ebx

.text:00401780 jz loc_40192E

.text:00401780 ; если такой функции в библиотеке нет, то выходим из установки

.text:00401780 ;

.text:00401786 push ebx

.text:00401787 call eax

.text:00401787 ; вызываем функцию ChekValidLicense

.text:00401787 ;

.text:00401789 test eax, eax

.text:0040178B jnz loc_4019A3

.text:0040178 ; если функция возвратила не ноль, то выходим из программы установки

Листинг 19 дизассемблерный листинг "сердца" защитного механизма с комментариями

Невероятно, но эта до ужаса примитивная защита построена именно так! Причем, полуметровый файл ChkLic.exe вообще не нужен! И чего ради стоило тащить его из Интернета? Кстати, если вы надумаете сохранять дистрибьютив компилятора (внимание: я не говорил "распространять"!), то для экономии дискового места ChkLic.* можно стереть: либо пропадчив setup.exe, навсегда отучив его к ним обращаться, либо же просто создав свою собственную ChkLic.dll, экспортирующую stdcall функцию CheckValidLicence вида: int CheckValidLicence(int some_flag) { return 0;}

Так-с, пока мы все это обсуждали, инсталлятор закончил установку компилятора и благополучно завершил свою работу. Интересно ли запустится ли компилятор или все самое интересное только начинается? Лихорадочно спускаемся вниз по разветвленной иерархии вложенных папок, находим icl.exe, который как и следовало ожидать, находится в каталоге bin, нажимаем и… Компилятор естественно не запускается, ссылаясь на то, что "icl: error: could not checkout FLEX lm license", без которой он не может продолжить свою работу.

Выходит, что Intel применила многоуровневую защиту и первый уровень оказался грубой защитой от дураков. Что ж! Мы принимаем этот вызов и, опираясь на свой предыдущий опыт, машинально ищем файл LMGR*.DLL в каталоге компилятора. Бесполезно! На этот раз такого файла здесь не оказывается, зато выясняется, что icl.exe сильно прибавил в весе, перевалив за отметку шестиста килобайт… Стоп! А не прилинковали ли разработчики компилятора этот самый FLEX lm статической компоновкой? Смотрим: в Intel C++ 5.0 сумма размеров lmgr327.dll и icl.exe составляла 598 Кб, а сейчас одни лишь icl.exe занимает 684 Кб. С учетом поправки на естественное старческое "ожирение", цифры очень хорошо сходятся. Значит, все-таки FLEX lm! Ой-ой! А ведь теперь, – без символических имен функций, ломать защиту будет намного труднее… Впрочем, не будем раньше времени паниковать! Давайте думать, только спокойно! Навряд ли команда разработчиков полностью переписала весь код, взаимодействующей с этой "конвертной" защитой. Скорее всего, ее "усовершенствование" одной лишь сменой типа компоновки и закончилось. А раз так, то шансы взломать программу по прежнему велики!

Памятуя о том, что в прошлый раз защитный код находится в функции main, мы, определив ее адрес, просто устанавливаем точку останова и, дождавшись всплытия отладчика, тупо трассируем код, попеременно поглядывая то на отладчик, то на окно вывода программы: не появилась ли там ругательное сообщение? При этом, все встретившиеся нам условные переходы, мы отмечаем на отдельном листке бумаги (или откладываем в своей собственной памяти, если вы так хотите), не забыв указать выполнялся ли каждый условный переход или нет… Стоп! Что-то заболтались мы с вами, а ведь ругательное сообщение уже выскочило! ОК, хорошо! Посмотрим, какой условный переход ему соответствовал. Наши записи показывают, что последним встретившимся переходом, был условный переход JNZ, расположенный по адресу 0401075h и "реагирующий" на результат, возращенной процедурой sub_404C0E:


.text:0040106E call sub_404C0E

.text:00401073 test eax, eax

.text:00401075 jnz short loc_40107F

.text:00401077 mov al, 1

.text:00401079 mov byte ptr [esp+40h+var_18], al

.text:0040107D jmp short loc_4010BA

.text:0040107F ; ─────────────────────────────────────────────────────────────────────

.text:0040107F

.text:0040107F loc_40107F: ; CODE XREF: _main+75↑j

.text:0040107F mov eax, offset aFfrps ; "FFrps"

.text:00401084 mov edx, 21h

.text:00401089 call sub_404C0E

.text:0040108E test eax, eax

.text:00401090 jnz short loc_40109A

^ Листинг 20 поиск "заветного" условного перехода тупой трассировкой с ожиданием вывода ругательного сообщения на экран

Очевидно, что sub_404C0E и есть та самая защитная процедура, которая осуществляет проверку лицензии на ее наличие. Как ее обхитрить? Ну, тут много вариантов… Во-первых, можно, вдумчиво и скрупулезно проанализировать содержимое sub_404C0E на предмет выяснения: что именно и как именно она проверяет. Во-вторых, можно просто заменить JNZ short loc_40107F на JZ short loc_40107F или даже NOP, NOP. В третьих, команду проверки результата возврата TEST EAX, EAX можно превратить в команду установки нуля: XOR EAX, EAX. В-четвертых, можно пропадчить саму sub_404C0E, чтобы она всегда возвращала ноль.

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

Поразительно, но компилятор больше не ругается и работает!!! Действительно, как и следовало ожидать, его разработчики ничуть не усилили защиту, а, напротив, даже ослабили ее!
Record Now
…и угораздило же меня приобрести "писец" (то бишь CD-RW) в OEM-поставке! И ведь спрашивал продавца: а где, позвольте, тут пишущий софт или, по крайней мере, драйвера? На что продавец, удивленно так пожимая плечами, ответил: какие драйвера? Втыкаете – работает. А пишущие программы подходят любые, вот купите в соседнем магазине диск с Nero CD. Мне, обладателю retail-"писца" от PHILPS, еще тогда это показалось странным, поскольку, я хорошо помнил, что диск с драйверами в коробке PHILPS'а был, а Easy CD Creator – непосредственно сам пишущий софт, – располагался совсем на другом диске. Но ведь как-то же справляются с OEM-продукцией другие люди, подумал я, и… купил.

Наскоро воткнув новехонький 40-скоростной NEC в свой компьютер, я был немало удивлен, когда Nero CD наотрез отказался признать его "писцом". Не помог тут и Easy CD Creator, взятый с Филечкиного CD. Провозившись битый час и, ничего ровным счетом так и не выяснив, я, зверски разозленный на продавца, решил сделать ход конем, установив NEC на компьютер с "девяносто восьмой" Windows, вернув PHILPS'а себе. Никаких изменений! Собравшись было отдавать привод назад продавцу, я неожиданно вспомнил, что в одном из последних номеров Компьютер Пресс был обзор пишущих программ, причем демонстрационные версии всех этих программ содержались на прилагаемом к журналу компакт-диске. Из всех программ NEC'овый писец опознала лишь одна: Record NOW, которая, к счастью не имела никаких функциональных ограничений, за исключением 30-дневного триального периода
еще рефераты
Еще работы по разное