рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Mov dwordptr [esi], offset off_0_4035C8

Mov dwordptr [esi], offset off_0_4035C8 - раздел Информатика, NAG SCREEN 40139E Mov Eax, Esi 4013A0 Pop Esi 4013Ai Retn 401...

40139E mov eax, esi

4013A0 pop esi

4013AI retn

4013AI sub_0_401390 endp

Становится ясно, что sub_0_401440 — это виртуальная функция CDocu-ment::On3aveDocument()! Но разработчик не передает управления последней, а выводит диалоговое окно и отказывается от записи.

А что если заменить sub_0_401440 на вызов функции по умолчанию OnSave-Document? Для этого сначала необходимо узнать, импортируется ли эта функция программой или нет. Воспользуемся для этой цели IDA и изучим секцию rdata. К нашему глубокому сожалению, OnSaveDocument в таблице импорта отсутствует. Можно, конечно, вызвать любую функцию непосредственно из DLL или загрузить. ее LoadLibrary. Это, разумеется, потребует немало места для размещения нового кода в файле. Но, к счастью, оно там с избытком имеется. Компилятор выравни­вает прологи всех функций по границе 0х10 байт для оптимизации выполнения программы, поэтому остается много "дыр", которые взломщик может использо­вать для своих целей.

Это действительно очень просто, достаточно иметь минимальные навыки программирования под Windows. Однако, первая же попытка реализации сталки­вается с серьезной трудностью. Чтобы вызвать функцию по адресу, необходимо наличие GetProcAddress, а приложение не импортирует ее. Печально, на первый взгляд, но легко исправимо. Достаточно лишь слегка изменить таблицу импорта, чтобы включить недостающий вызов.

Обычно компиляторы всегда оставляют в файлах много пустого места, позво­ляющего немного расширить таблицу импорта. Чтобы это сделать, нужно знать формат РЕ-файла, который описан, например, в MSDN. Покажем это на примере. Скопирум файл cracklO.exe в myfile.exe. Теперь запустим HIEW 6.х (не ниже) и перейдем в секцию импорта. В самом ее начале расположен массив IMAGE^IM-POR1_DESCRIPOR. Подробности о его структуре можно почерпнуть в SDK или MSDN, Двойное слово, стоящее в начале, — это RVA (relative virtual address) указател^ на структуру IMAGE_THUNK_DATA. Он-то нам и нужен. Преобразо­вать rva в локальное смещение внутри РЕ-файла можно сложением его с image base, которую можно узнать из заголовка файла.

Что собой представляет IMAGE_THUNK_DATA? Это массив указателей на RVAFunctionNaine. Наглядно его можно представить, если изучать эту структуру в любом подходящем для вас шестнадцатиричном редакторе, например HIEW. Что может быть интереснее копания в РЕ-файле вручную, а не с помощью готового инструмента просмотра? Конечно, последнее намного проще и, может быть, приятнее, но не дает никаких полезных навыков. Хакер должен рассчитывать не на технику, а только на свои руки и голову. Кракер же может, особо себя не утруждая, воспользоваться готовым редактором для таблиц экспорта/импорта (например, PEKPNXE Криса Касперски) и всего лишь отредактировать одну строку, что не требует дополнительных объяснений. Ручная же работа с РЕ-файлами, напротив, пока еще не слишком хорошо описана, а сам формат лишь отрывочно документирован. Единственным маяком в мире Windows был и остает­ся заголовочный файл winnt.h, который содержит все необходимые нам структуры (но, увы, не содержит комментариев к ним). Поэтому назначение некоторых полей придется выяснить самостоятельно. Для начала загрузим исследуемый файл в HIEW. Можно было бы сразу вызвать секцию импорта, но в первый раз попытаемся для интереса найти ее вручную.

Заголовок РЕ-файла начинается не в начале файла. Там расположена dos-ob-ская заглушка, которая нам совсем не интересна. Сам же РЕ-файл начинается с одноименной сигнатуры. Двенадцатое (считая от нуля) двойное слово — это image base, который нам потребуется для вычислений, связанных с RVA: в нашем случае он равен 0х400000, что типично для Win32-фaйлoв.

Теперь нам необходимо найти адрес таблицы импорта. Он стоит вторым в директории (первый — таблица экспорта). Под директорией здесь понимается структура, расположенная в конце OPTIONAL HEADERa и содержащая необхо­димую нам информацию. Я не привожу точного описания ее формата, отсылая читателя к MSDN и winnt.h. Настоящая книга не предназначена для пересказа существующей документации, и было бы бессмысленно тратить на это десятки страниц. Замечу, что на стадии подготовки книги это вызвало некоторые возра­жения у тех людей, которые не владели английским даже на уровне чтения технических текстов со словарем и не позаботились приобрести хотя бы элект­ронную документацию, которая свободно поставляется с любым компилятором и доступна в Интернете на сайтах производителей, в первую очередь, MicroSolt. Увы, тут нечего сказать.

Итак, предположим, что мы уже выяснили, что таблица импорта располагает­ся по адресу Ох40000+ОхЗА90=Ох43а90. Перейдем к ее рассмотрению, а точнее к рассмотрению IMAGE_THUNK_DATA, которое мы уже затронули выше. Фор­мат его данных очевиден из содержания:

.00403ЕЗО; F6 3В 00 00-02 3F 00 00-16 3F 00 00-C6 3E 00 00

.00403E40: Ей 3E 00 00-26 3F 00 00-44 3F 00 00-ЭЕ 3E 00 00

.00403E50: 6A 3F 00 00-A8 3E 00 00-9A 3E 00 00-86 3E 00 00

.00403E60: 36 3F 00 00-56 31- 00 00-D8 3F 00 00-00 00 00 00

Поразмыслив над ним минутку-другую, можно догадаться, что его элементы — двойные слова — это RVA-указатели. На эту мысль наталкивает то, что само значение, например, Ox3EF6 — находится недалеко от текущей позиции, глубоко в таблице импорта. Кроме того, все близкие к друг другу и однонаправленно возрастающие значения элементов очень похожи на типичный массив указателей.

Заглянув в документацию, мы можем убедиться в правильности нашей догад­ки. Попытаемся теперь, не обращаясь к документации, угадать — это указатели на что? Логично предположить, что на непосредственно импортируемые функ­ции. Все еще не обращаясь к документации, перейдем по одному из указателей:

0403FOO; 6D 00 83 00-5Е- 5F 73 65-74 75 73 65-72 6D 61 74 ш Г __setusemat

0403FIO; 68 65 72 72-00 00 9D 00-5F 61 64 6R-75 73 74 5Г herr Э _adju5t_

0403F20: 66 64 69 76-00 00 6A 00-5F 5F 70 5F-5F 63 6F 60 fdiv j __p__corn

0403F30: 6D 6F 64 65-00 00 6F 00-5F 5F 70 5F-5F 66 6D 6F mode о __p__fitio

Это действительно имена функций, а слово, стоящее перед ними, очевидно, ординал! Однако мы едва не упустили одну важную деталь — ведь существуют функции, которые экспортируются только по ординалу, и символьная информация попросту не доступна. Неужели тогдадвойные слова-указатели будут расточи­тельно указывать на слова-ординалы? Разумеется, нет: фирма MicroSoft в стремлении к оптимизации предотвратила такой вариант. В этом случае все элементы IMAGE_THUNK_DATA представляют собой не указатели, а непосред­ственно ординалы функций. Чтобы загрузчик мог это распознать, старший бит двойного слова равен единице. В результате, получается массив наподобие следующего:

.00403ВОО; В2 10 00 80-86 II 00 80-FA 09 00 80-DO 09 00 8O

.00403BIO; 63 16 00 80-52 OF 00 80-41 04 00 80-4F 14 00 80

.00403B20; 5C 09 00 80-12 OD 00 80-B4 14 00 80-B6 14 00 80

.00403B30: А5 ОД 00 80-EF OF 00 80-5A 12 00 80-BB 14 00 80

.00403B40: A9 14 00 80-52 16 00 80-A6 0В 00 80-4B ОС 00 80

Любопытно, что в оптимизации Windows NT MicroSolt опередила сама себя, и в системных модулях все элементы вышеуказанного массива являются даже не ординалами, а непосредственными смещениями импортируемых функций. Это блестящее решение MicroSoft заслуживает глубокого уважения. Действительно, загрузчику почти совсем не остается работы, что экономит не одну сотню тактов процессора. Это лишний раз подтверждает, что "решение от Microsoft" чаще все же ирония, чем горькая правда. И хотя Windows в целом оставляет мрачное впечатление (с точки зрения общего построения системы), в ее недрах спрятано немало интересных "конфеток". И в самом деле — ведь над ней работали весьма веглупые люди.

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

Взглянем на наш файл. RVA-адрес первой структуры IMAGE_THUNK_DATA равен ОхЗВОО. Учитывая, что image base 0х400000, получаем локальное смещение Ох403ВОО. Как узнать, из какого модуля импортируются эти функции? Для этого заглянем в поле Name IMAGE_IMPORT_DESCRIPTOR, (четвертое двойное слово от начала). В нашем случае оно указывает на стоку 'MFC42.DLL' Именно в эту таблицу мы и должны добавить запись для OnSaveDocument. Разумеется, в таблице не будет свободного места, а за ее концом находится начало следующей. Кажется, ситуация неразрешимая... но подумаем немного. На каждую IMAGE_THUNK_DATA указывает всего одна ссылка. А что будет, если мы переместим одну из них в другое свободное место (которое наверняка найдется) и в освободившееся пространство внесем новую запись?

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

Благодаря выравниванию адресов на границах секций данных и ресурсов практически всегда есть бездна никем не занятого пространства. Переместим выделенную структуру, например, по адресу 0х404110. Для этого нужно скопи­ровать блок с адреса Ох403Е24 по Ох403Е6В и записать его на новое место. Теперь освободившееся место можно использовать по своему усмотрению. Но прежде необходимо скорректировать ссылку на перемещенный фрагмент. Для этого вайдем в IMAGE_IMPORT_DESCRIPTOR прежний RVA-адрес и исправим его на новый.

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

.00403ВОО: В2 10 00 BO-86 II 00 80-FA 09 00 BO-DO 09 00 80

.00403BIO: 63 16 00 80-52 OF 00 80-41 04 00 80-4Г 14 00 80

.00403B20: 5C 09 00 80-12 OD 00 80-B4 14 00 80-B6 14 00 80

.00403B30; Д5 OA 00 80-EF OF 00 ВО-5Д 12 00 80-BB 14 00 80

.00403B40; Д9 14 00 SO-52 1.6 00 80-A6 0В 00 80-4B ОС 00 80

Видно, что все они импортируются по ординалу. И нам необходимо только добавить еще один. Находим в файле MFC42.map функцию OnSaveDocument и на основе полученного смещения определяем ординал с помощью dumpbin или любой другой аналогичной утилиты; получаем, что ее ординал 0х1359. Дописыва­ем ее в конец таблицы. Запускаем dumpbin, чтобы удостовериться, что он заметил проделанные изменения. Однако это далеко не конец нашей работы, а скорее только ее начало. Что нам даст новая запись в IMAGE_THUNK_DATA? Честно говоря, ничего. Нам нужно узнать адрес функции после загрузки, а как это сделать? Для этого существует еще одно поле в IMAGE_IMPORT_DESCRIPTOR — это пятое двойное слово, указывающее адрес массива, в каждый элемент которого загрузчик операционной системы запишет реальный адрес импортируе­мой функции. В нашем случае для MFC42.DLL такая структура расположена по адресу Ох40300С. Рассмотрим ее более детально, но сначала обратим внимание на то, что адрес Ох40300С находится за пределами секции импорта и принадлежит уже секции .rdata. Это обстоятельство, на самом деле, очень важно, так как иначе загрузчик просто не смог бы получить доступ к памяти на запись, а следовательно, изменить значение. Таким образом, эта таблица перемещаема только в пределах .rdata. Но что она собой представляет? Гораздо проще и быстрее выяснить это самостоятельно, чем искать в документации среди множества бесполезной для нас сейчас информации. Рассмотрим ее более детально:

.00403000: вС 3F 00 00-78 3F 00 00-00 00 00 00-B2 10 00 80

.00403010: 86 II 00 60-FA 09 00 80-DO 09 00 80-53 16 00 80

.00403020: 52 OF 00 80-41 04 00 SO-4F 14 00 80-5C 09 00 8О

.00403030: 12 OD 00 80-B4 14 00 80-B6 14 00 80-A5 OR 00 80

.00403040: EF OF 00 80-5A 12 00 80-BB 14 00 80-Д9 14 00 80

Не правда ли, эти таблицы идентичны? И та и другая перечисляет ординалы. Однако между ними все же есть существенная разница. Первая сохраняется неизменной на всем протяжении работы, а последняя замещается реальными адресами импортируемых функций уже на стадии загрузки. И именно ее прило­жение использует для вызовов типа CALL DWORD PTR [0х403010].

Очевидно, что в случае импорта по имени все элементы таблицы будут указателями на ASCIIZ-строки с именем и ординалом функции. Заглянув в MSDN, можно с гордостью констатировать тот факт, что мы нигде не ошиблись в наших предположениях. Со временем большинство исследователей недр Win­dows все реже и реже заглядывают в документацию, поскольку многое и так достаточно очевидно и не требует разъяснения.

Печально, что это служит примером для начинающих и неопытных хакеров, которые отказываются от документации вообще. В результате они тычутся вслепую или начинают задавать глупые вопросы наподобие таких: "какой функ­цией Windows открывает файл. Я установил на OpenFile точку останова, а она не сработала. Почему?" Действительно, общий объем документации для разработчи­ка Win32 столь велик, что даже беглый просмотр заголовков отнимет не один месяц времени. Это верно. Еще про Windows 3.1 говорили, что нужно не меньше года обучения, чтобы стать полноценным программистом под эту платформу. Насколько же все усложнилось с тех пор! Самое обидное, что на этом фоне делается основной упор на каркасные библиотеки типа MFC, технологии OLE и ActiveX, а системному программированию просто не остается места — ни в умах разработчиков, ни в документации. Лозунг "все, что Вам нужно, уже сделано компанией Microsoft" сейчас очень популярен, но многих людей он приводит в ярость. Программисты старшего поколения до сих пор любят все делать своими руками и не передают выполнения своей программы чужому коду, пока его не изучат.

Полноценным системщиком может стать лишь тот, кто откажется от MFC и C++ и попробует написать несколько серьезных приложений на старом добром Си. Даже не на ассемблере, а на простом высокоуровневом языке. Непосредст­венное общение с Win32 может с первого взгляда показаться пугающим, но только так можно почувствовать архитектуру системы. Без этого говорить о хакерстве просто смешно.

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

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

.004018DO: FF25C4314000 jmp MFC42.4612

.004018D6: FF2590314000 jmp MFC42.4610

.004018DC: FF25S4314000 Jmp MFC42.6375

.004018Е2: FF2510304000 jmp MFC42.4486

.001016Е8; FF2514304000 jmp MFC42.2554

.004018ЕЕ: FF2518304000 jmp MFC42.2512

.004018F4: FF251C304000 jmp MFC42.5731

.004018FA: FF2520304000 jmp MFC42.3922

.00401900: FF2524304000 jmp MFC42.1.089

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

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

Поскольку сразу за концом IMAGE_IMPORT_DESCRIPTOR следует IMAGE_THUNK_DATA, то очевидно, что добавить еще одну запись можно только в том случае, если переместить одну из двух на свободное место. Первая несравненно короче, поэтому и найти бесхозное пространство для нее легче, Строго говоря, нам необходимо разместить ее в пределах таблицы импорта, и никто не разрешит перемещать ее в секцию .data — получится перекрывание секций, и последствия не заставят себя ждать... HIEW "заругается" на такой файл. И, пожалуй, все. Действительно, если изучить код загрузчика Windows, становится ясно, что ему совершенно все равно, в какой секции расположена таблица импорта, и, более того, совершенно безразличен размер последней, а точнее, его соответствие с реальным. Конец определяется null-записью.

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

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

Скопируем IMAGE_IMPORT_DESCRIPTOR в любое свободное место секции данных и изменим на нее ссылку в Import Directory. Теперь нам необходимо создать в ней новую запись. Начнем с четвертого двойного слова, указывающего на имя функции. Можно сослаться на уже существующую строку 'MFC42.DII' или создать свою и указать на нее. Последнее дает нам больше свободы и независимости. Поэтому поступим именно так: .004041DO; 4D 46 43 34-32 2E 44 4C-4C 00 00 00-00 00 00 00 MFC42.DLL

Итак, имя экспортируемого модуля мы уже записали. Теперь необходимо создать массив IMAGE_THUNK_DATA ("массив" громко сказано, всего лишь одну запись). .004041ЕО: 59 13 00 80-00 00 00 00-00 00 00 00-00 00 00 00 Y!! A

Понятно, что 0х1359 и есть импортируемая функция OnSaveDocument, а старший бит 0х8000 указывает, что последняя импортируется по ординалу. Остается создать таблицу адресов — точнее, таблицу создавать нет никакой необходимости. Несмотря на то что каждый ее элемент должен по теории ссылаться на соответствующую функцию, оптимизация загрузчика привела к тому, что он никак не использует начальные значения таблицы адресов, а вносит записи в том порядке, в котором они перечислены в таблице имен (IMAGE_THUNK_DATA). Поэтому достаточно лишь найти незанятое пространст­во и установить на него указатель в последнем поле IMAGE_IMPORT_DESCRI. POR.

Однако тут мы наталкиваемся на серьезные ограничения. Загрузчику на запись доступна только .rdata, в которой — скажем так — свободного места не густо. Более того, ни один элемент нельзя перемещать, поскольку ссылки на него разбросаны по всему коду программы. Остается только надеяться, что в резуль­тате выравнивания в конце таблицы найдется немножко пространства для наших целей. И действительно, несколько десятков байт свободно. Для нас этого более чем достаточно.

0403FCO: 57 69 6Е 64-6F 77 00 00-55 53 45 52-33 32 2E 64 Window USER32.d

0403FDO: 6C 6C 00 00-М 01 5F 73-65 74 6D 62-63 70 00 00 II KB_aetmbcp

0403FEO: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00

0403FFO: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00

Остается только скорректировать IMAGEJTHUNK^DATA. Финальный вари­ант может выглядеть так:

0404160: ЕО 41 00 00-00 00 00 00-00 00 00 00-DO 41 00 00 pA ^A

0404170: EO 3F 00 00-00 00 00 00-00 00 00 00-00 00 00 00 p?

Убедимся с помощью dumpbin, что он исправно работает.

MFC42.DLL

403FE0 Import Address Table

4041ЕО Import Nаmе Table

0 time date stamp

0 Inden of first forwarder reference

Ordinal 4953

Если заглянуть отладчиком по адресу Ox403FEO, то там мы обнаружим готовый к употреблению адрес функции OnSaveDocument. Проверим, что это действительно так. Дизассемблируем (командой и в Soft-Ice) этот регион памяти. При этом отладчик должен вывести в прологе ординал функции. Это убеждает нас, что все работает. Остается эту функцию всего лишь вызвать. Для этого вернемся далеко назад, когда мы нашли перекрытую функцию OnSaveDocLiment. Нам стоит переписать ее. Рассмотрим код еще раз:

.00401440: бДОО push 000

.00401442: бАОО push 000

.00401444: 6890404000 push 000404090

.00401449: E812070000 call AfxMessageBox

.0040144E: ЗЗСО xor еаx,еах

.00401450; С20400 retn 00004

Очевидно, что ее нужно переписать, — например, следующим образом:

.00401440: FF742404 push d, [esp] [00004]

.00401444: 90 пор

.00401445: 90 пор

.00401446: 90 пор

.00401447: 90 пор

.00401448: 90 пор

.00401449: 2EFF15E03F4000 call d,c3: [000403FEO]

.00401450: С20400 retn 00004

Для понимания этого обратимся к SDK. Вот какой прототип имеет функция virtual BOOL OnSaveDocument ( LPCTSTR IpssPathName );

Отсюда вытекает строка push dword [esp][00004]. Остается объяснить вызов функции. Как мы помним, загрузчик в ячейку Ox403FEO записал ее адрес, — он и был использован для вызова. И это все! Мы дописали недостающий код. Этот момент очень важен. Читатель может упрекнуть меня за выбор искусственной ситуации. Действительно, часто ли встречаются подобные примеры в жизни? Даже применительно к MFC используемая функция с большой степенью вероят­ности может быть перекрыта функцией разработчика. Как быть тогда? Но не спешите. Пусть функция перекрыта, тогда положение осложняется лишь тем, что хакеру сперва нужно будет понять ее алгоритм, а затем воссоздать недостающий код и... поместить его в собственную DLL, а оттуда уже аналогичным образом сделать вызов. При этом нет надобности изощряться и втискивать код в скудные клочки пустого места, беспорядочно разбросанные по файлу. Можно выбрать любое симпатичное средство разработки (например MS VC) и написать на нем недостающую функцию, используя всю мощь MFC и объективно-ориентированно­го Си++. Это гораздо легче и, кроме того, попросту удобно.

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

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

Вернемся к нашему примеру. Попробуем его запустить. Появляется другое диалоговое окно с сообщением об ограниченности версии. Выходит, автор защиты предусмотрел двойную проверку. Выкинул ли он еще кусок кода или только вернул управление? Чтобы это выяснить, необходимо изучить вызывающий это сообщение код. Не будем прибегать к столь мощному инструменту как IDA, а воспользуемся компактным и шустрым hiew-om. Достаточно лишь найти ссылку на строку, смещение которой можно узнать, заглянув в сегмент данных. После чего нетрудно будет найти следующий фрагмент:

.00401410; 8В442404 mov eax.[esp] 100004]

.00401414: 8B5014 mov edx,[eax] [00014]

.00401417: F7D2 not edx

,00401419: F6C201 test 111,001

.0040141C; 7411 je .00040142F

.0040141E: 6AOO push 000

.00401420: 6ДОО push 000

.00401422: 6854404000 push 000404054 ; << строка

.00401427: E834070000 call AfxMessageBox

.0040142C: C20400 retn 00004 ;"

.00101430; 8B4130 шоу eax, (ecu] [00030]

.00401433: 8B4808 mov есх,[еах] [00008]

.00401436; E81F070000 call Serialize

.0040143В: C20400 retn 00004

MFC-программистам нетрудно понять, как он работает. Если происходит запись файла, то edx становится равно единице, если чтение — то нулю. Именно на этом и построена защита. В оригинале это могло выглядеть приблизительно так:

Void CCRACK10Doc::Serialize (CArchive& ar)

{

// CEditView contains an edit control which handles all serialization

if (ar.IsStoring() )

(

RfxMessageBox("Это ограниченная версия. Пожалуйста, приобретайте полную");

return;

}

((CeditView&*)m_viewList.GetHead())->SerializeRaw(ar);

}

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

Попробуем убрать ret, заменив его, скажем, на пор. казалось бы это не отразится на работоспособности программы. Однако, запустив программу и попытавшись сохранить файл, мы получаем до боли знакомый GPF — "программа выполнила некорректную операцию и будет завершена". В чем же дело? С первого взгляда этот вопрос нас ставит в тупик, поэтому воспользуемся отладчи­ком и внимательно потрассируем измененный фрагмент. Причина обнаруживает­ся достаточно быстро. Функция AfxMessageBox не сохраняет регистров еах и есх, а код, расположенный ниже, их использует, никак не предполагая, что их содержимое было изменено. Следовательно, забота о сохранении, точнее, о написании соответствующего кода, ложится на плечи взломщика. Это нетрудно и даже не утомительно — добавить пару команд push и pop, но как-то неаккуратно выглядит. Действительно, между условным переходом и вызовом функции нет свободного пространства. Можно, конечно, сместить всю функцию немного вниз, для чего свободного места предостаточно, но, может быть, можно найти решение с изменением меньшего числа байт? В самом деле, если убрать not, a je заменить на jne, мы получим два байта — как раз столько, чтобы сохранить пару регистров. Однако это потребует коррекции точки перехода, поскольку команды push расположены "выше" ее. В итоге мы получим такой вариант:

.00401417: 50 push еах

.00401418: 51 push есх

.00401419: F6C201 test dl,001

.0040141С: 750E jne .00040142C

.0040141E: бАОО push 000

.00401420; бАОО push 000

.00401422: 6854404000 push 000404054

.00401427: E8 34070000 call . 000401B60

.0040142C: 59 pop ecx

.0040142D: 90 пор

.0040142Е: 90 пор

.0040142F: 90 пор

.00^01430: 8В4130 mov eax, [ecx] [00030]

.00401433: 8B4808 mov ecx, [eax] [00008]

.00401436: E8iF070000 call .000401В5A

.0D40143B: C20400 retn 00004

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

Итак, мы проделали большой путь — научились не только снимать ограниче­ния с программ, но и дописывать недостающий код. Конечно, все, о чем расска­зано в этой главе, — это лишь начало еще большего пути, который открывается перед нами. Что он сулит? Модификация программ непосредственно в исполняе­мом коде не только заменой пары байт, но и внесением принципиальных измене­ний в код и добавлением новых возможностей — воистину великая вещь! Читатель, вероятно, понял, что для рассказа об этом не хватило бы и отдельной книги, не то что одной главы. Но и в этом случае от него потребовались бы собственные исследования и копания в коде.

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

– Конец работы –

Эта тема принадлежит разделу:

NAG SCREEN

Каждому предоставлена полная свобода выбора — или терпи Nag Screen...

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Mov dwordptr [esi], offset off_0_4035C8

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

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

SetTimer
18C Is Iconic 195 KillTimer B7 EnableWindow 146 GetSystemMetrics 19E LoadIconA Попробуем найти код, который вызывает SetTimer, для чего установим на пос

Ограничение возможностей
Многие незарегистрированные версии отличаются тем, что часть их возмож­ностей заблокирована. Если программа предусматривает регистрацию, то обычно больших проблем при взломе не возникает. Совсем др

Text;004015CFp
jmp ds: ?EnableWindow@cwnd@@QREHH@z j_?EnableWindow@cwnd@@QAEHH@z endp Их всего два. Как раз по числу элементов управления. Пока защита не предвещает ничего необычного и ее код вы

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

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

Приемы против отладчиков
Самым первым отладчиком под MS-DOS был Debug.com фирмы MicroSoft. Совершенно очевидно, что этот инструмент годился разве что для забавы и изучения ассемблера. Но рынок не терпит пустого ме

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

J E9 EC EF JMP F125
2298;0139j F2 REPNE Полученный мусор может привести систему к краху, но едва ли будет нормально выполняться. При этом защитный механизм настолько "размазан" по коду, что обнаружи

Приемы против отладчиков защищенного режима
Позже появился 80286 (с точки зрения хакера мало чем отличавшийся от своего предшественника), а вслед за ним и 80386, принесший принципиально новые возможности отладки. Точнее, "принципиально

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

Дизассемблирование в уме
"— Мне известны политические аргументы. — Но меня интересуют человеческие доводы." Ф. Херберт. "Мессия Дюны". Очень часто под рукой не оказывается ни отладчика,

Структура команд INTEL 80х86
"— Потому ты и опасен, что ояладел своими страстями." Ф. Херберт. "Мессия Дюны". Дизассемблирование (тем более в уме) невозможно без понимания того, как процессо

Add b, [00100],002
00000105: 00B406B2 add [si][OB206],dh | ----------ip Т.е. текущая команда станет на байт короче! И "отрезанный" ноль теперь — часть другой команды! Но при выпол

Есть базирование если 2bit=1 то 0 –BP, 1 - BX
если 3bit=0 то 0 –база BX, 1 – база BP если 3bit=1 то 0 –индексный регистр 1 - базовый Возможно, кому-то эта схема покажется витиеватой и трудной для запомина­ния, но зубрить все

В4 ОЭ БД 77 01 CD 21
Вот она! Но что представляет собой опкод ОхВА? Попробуем определить это in трем младшим битам. Они принадлежат регистру DL(DX). А ОхВ4 0х9 — это шоу АН,9. Теперь нетрудно догадаться, что оригинальн

F2 AC 02 EO E2 FB BE 3В 01 30 24 46 61
Чтобы превратить его в знаковое целое, необходимо дополнить его до нуля (операция NEG, которую большинство калькуляторов не поддерживают). Тот же результат мы получим, если отнимем от 0х100 указанн

Маленькие хитрости
"Главная часть дисциплинирующей выучки — это ее сокрытая часть, предназначенная не освобож­дать, но ограничивать." Ф. Херберт. "Еретики Дюны". Хорошо, если в ваш

Х1 0х2 0х4 0х8 0х10 0х20 0х40 0х80
Причем все математические операции с такими круглыми числами делать^ уме на порядок проще, за что я и люблю шестнадцатиричную систему счисления. Разумеется, описанные приемы ни для кого не должны б

Ассемблирование в уме
"Ничто не превосходит по сложности человече­ский ум." Ф. Херберт. "Еретики Дины". Мы уже проделали титаническую работу, дизассемблировав в уме крохотный файл в п

Int 021
Дело в том, что указанным способом невозможно ввести с клавиатуры символ #8. А смещение строки как раз и есть 0х108. Чтобы избавиться от восьмерки, можно было бы, конечно, исполнить следующую после

B90123 456789
1111 111111 MOV DX, 0х100+2+2 ; OxlOO-адрес загрузки, 2 длина MOV АН, 9, 2 длина jmp JMP SHORT $+20 — резервирует 20 символов для строки. Предполагается, что этого окажется достат

Маска отображения файлов —*
Вообще навигатор очень напоминает Norton Commander, и общение с ним проблем вызвать не должно. На всякий случай я все же опишу назначение клавиш управления: Alt-FI (Drive)

Text 00000452 |D:KPNCHIEWDEXEM.EXE
При этом кроме собственно имен сохранятся текущий режим и позиция курсора (что особенно приятно). Последнее позволяет использовать HIEW для чтения больших текстовых файлов (электронных книг, докуме

Ассемблер
"Убийство острием лишено артистизма. Но пусть тебя это не останавливает, если плоть, раскрываясь, сама себя предлагает." Ф. Херберт. "Дюна". Пере

Дизассемблер
Дизассемблер в HIEW великая вещь. фактически это основной режим работы хакера. Не то чтобы некоторые ленились дизассемблировать в уме hex-коды, (что, скажем, частенько приходится делать при работе

Adc dh,[si]
……………….. 00000104:xxxx Разница в том, что ссылка во втором случае указывает "в космос", но никак не на переменную 0х4. Это можно исправить, указав HIEW-y вручную начальное

Adc dh, [si] <—
00000106: 0100 add [bx] [si], ax 00000108: E3F7FF call 000000102-------- (i) И все ссылки при этом работают правильно. Заметим, что базирование никак не влияет на

Манипуляции с блоками
"Соединение невежества и знания, соединение ди­кости и культуры — не начинается ли оно с того чувства достоинства, с которым мы относимся к своей смерти?" Ф. Хербер

Поддержка LE/PE/NE/LX/NLM-ФОРМАТОB
"Понятие прогресса, служит защитным механиз­мом, отгораживающим нас от ужасов будущего." Ф. Херберт. "Дюна". Вообще-то шестнадцатиричный редактор идеологически д

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

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

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

Крипт-система
"Не считай человека мертвым, пока не увидишь его тело. И даже тогда ты можешь ошибиться." Ф. Херберт. "Дюна". Уникальность HIEW-a прежде всего в том, чт

Описание файла HIEW.INI
"— Осторожность — важное качество для чело­века, который будет вождем." Ф. Херберт. "Дюна". HIEW хранит часть настроек в ini-файле, который немного напоминает од

JumpTable]
Задает таблицу переходов по call/jmp в дизассемблере. По умолчанию она выглядит следующим образом: "0123456789ABCDEFGHIJKLMOPQRSTUVWXYZ". При этом первый символ — это клавиша отката, т.е.

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги