Фундаментальные основы хакерства искусство дизассемблирования

Фундаментальные основы хакерства искусство дизассемблирования

Скачать книгу

О книге "Фундаментальные основы хакерства. Искусство дизассемблирования"

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

На нашем сайте вы можете скачать книгу "Фундаментальные основы хакерства. Искусство дизассемблирования" Касперски Крис бесплатно и без регистрации в формате fb2, rtf, epub, pdf, txt, читать книгу онлайн или купить книгу в интернет-магазине.

Программирование

Программирование
C/C++
Ассемблер
Паскаль
Basic
Delphi
Фортран
Программирование в WIN32
Программирование в xNIX
СТЕПЛЕР Сканы старых журналов
Мир ПК
Мир ПК 1992 год
Мир ПК 1995 год
1998
1999
2000
2001
2002
1996
Компьютер Пресс
1990
1991
1992
1993
1994
1996
Домашний компьютер
2001
1999
2003
Softalk
PC Magazine
Hard&Soft
Компьютер-63
Магия ПК
1997
1998
Softpanorama
Vol.1 (1989)
Vol.2 (1990)
Vol.4 (1992)
BYTE
Системный администратор
2008 год
2009 год
Интерфейс
Вычислительная техника и её применение
1988 год
1989 год
1990 год
1991 год
Компьютеры&Программы
Монитор
Компьютерное Обозрение
1997
1996
Мой игровой компьютер
1999 Руководства
Руководства Windows Автоматизация Мультимедиа Статьи
OT vaaal17 Журнал Downgrade Информация о программах Система
Эмуляторы ОС Безопасность Интернет Аппаратные средства Sinclair ZX Spectrum

Диск к книге Криса Касперски "Фундаментальные основы хакерства. Искусство дизассемблирования" Описание Информация Содержимое диска (полностью), прилагаемого к книге Криса Касперски "Фундаментальные основы хакерства. Искусство дизассемблирования", серия "Кодокопатель", книга 5, 2002, 448 стр, тираж 2500.

Список всех файлов с исходными текстами, упоминание которых можно найти в книге, находится в файле INDEX.HTM.

Шаг первый. Разминочный
Шаг второй. Знакомство с дизассемблером
Шаг третий. Хирургический
Шаг четвёртый. Знакомство с отладчиком
Шаг пятый. На сцене появляется IDA
(Шаг шестой в файле INDEX.HTM отсутствует)
Шаг седьмой. Идентификация ключевых структур языков высокого уровня

Приёмы против отладчиков
Приёмы против дизассемблеров

Содержание статьи

Следующие статьи

Проверка аутентичности

Проверка аутентичности (от греч. authentikos — подлинный) — «сердце» подавляющего большинства защитных механизмов. Должны же мы удостовериться, то ли лицо, за которое оно себя выдает, работает с программой и разрешено ли этому лицу работать с программой вообще!

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

  • защиты, основанные на знании (пароля, серийного номера);
  • защиты, основанные на обладании (ключевым диском, документацией).

Основные типы защит

Если защита базируется на одном лишь предположении, что ее код не будет изучен и/или изменен, — это плохая защита. Отсутствие исходных текстов отнюдь не служит непреодолимым препятствием для изучения и модификации приложения. Современные технологии обратного проектирования позволяют автоматически распознавать библиотечные функции, локальные переменные, стековые аргументы, типы данных, ветвления, циклы и прочее. А в недалеком будущем дизассемблеры, вероятно, вообще научатся генерировать листинги, близкие по внешнему виду к языкам высокого уровня.

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

Шаг первый. Разминочный

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

Читайте также:  Личный кабинет сбербанк виза вход

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

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

Листинг 1. Пример простейшей системы аутентификации

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

Не так уж редко пароли представляют собой осмысленные слова наподобие Ferrari, QWERTY, имена любимых хомячков или названия географических пунктов. Угадывание пароля сродни гаданию на кофейной гуще — никаких гарантий на успех нет, остается рассчитывать на одно лишь везение. А удача, как известно, птица гордая — палец в рот ей не клади. Нет ли более надежного способа взлома?

Давайте подумаем. Раз эталонный пароль хранится в теле программы, то, если он не зашифрован каким-нибудь хитрым образом, его можно обнаружить тривиальным просмотром двоичного кода программы. Перебирая все встретившиеся в ней текстовые строки, начиная с тех, что более всего смахивают на пароль, мы очень быстро подберем нужный ключ и откроем им программу! Причем область просмотра можно существенно сузить — в подавляющем большинстве случаев компиляторы размещают все инициализированные переменные в сегменте данных (в PE-файлах он размещается в секции .data или .rdata). Исключение составляют, пожалуй, ранние багдадские (Borland’овые) компиляторы с их маниакальной любовью всовывать текстовые строки в сегмент кода — непосредственно по месту их вызова. Это упрощает сам компилятор, но порождает множество проблем. Современные операционные системы, в отличие от старушки MS-DOS, запрещают модификацию кодового сегмента, и все размещенные в нем переменные доступны лишь для чтения. К тому же на процессорах с раздельной системой кеширования они «засоряют» кодовый кеш, попадая туда при упреждающем чтении, но при первом же обращении к ним вновь загружаются из медленной оперативной памяти (кеша второго уровня) в кеш данных. В результате — тормоза и падение производительности.

Что ж, пусть это будет секция данных! Остается только найти удобный инструмент для просмотра двоичного файла. Можно, конечно, нажать клавишу F3 в своей любимой оболочке (FAR, например) и, придавив кирпичом клавишу Page Down, любоваться бегущими цифирьками до тех пор, пока не надоест.

Можно воспользоваться любым hex-редактором (QView, Hiew. ) — кому какой по вкусу, — но в статье, по соображениям наглядности, приведен результат работы утилиты DUMPBIN из штатной поставки Microsoft Visual Studio. DUMPBIN запускается из Developer Command Prompt.

Натравим утилиту на исполняемый файл нашей программы, в котором лежит пароль, и попросим ее распечатать содержащую инициализированные только для чтения данные секцию rdata (ключ /SECTION:.rdata ) в «сыром» виде (ключ /RAWDATA:BYTES ), указав значок > для перенаправления вывода в файл (ответ программы занимает много места, и на экране помещается один лишь «хвост»).

Листинг 2

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

Один из способов сделать это — насильно поместить эталонный пароль в собственноручно выбранную нами секцию. Такая возможность не предусмотрена стандартом, и потому каждый разработчик компилятора (строго говоря, не компилятора, а линкера, но это не суть важно) волен реализовывать ее по-своему или не реализовывать вообще. В Microsoft Visual C++ для этой цели предусмотрена специальная прагма data_seg, указывающая, в какую секцию помещать следующие за ней инициализированные переменные. Неинициализированные переменные по умолчанию располагаются в секции .bss и управляются прагмой bss_seg соответственно.

В листинг 1 перед функцией main добавим новую секцию, в которой будем хранить наш пароль:

Внутри функции main проинициализируем массив:

Немного изменилось условие сравнения строк в цикле:

Натравим утилиту DUMPBIN на новый исполняемый файл:

Ага, теперь в секции данных пароля нет и хакеры «отдыхают»! Но не спешите с выводами. Давайте сначала выведем на экран список всех секций, имеющихся в файле:

Читайте также:  Родословное дерево семьи в детский сад

Нестандартная секция .kpnc сразу же приковывает к себе внимание. А ну-ка посмотрим, что там в ней?

Вот он, пароль! Спрятали, называется… Можно, конечно, извратиться и засунуть секретные данные в секцию неинициализированных данных (.bss) или даже секцию кода (.text) — не все там догадаются поискать, а работоспособность программы такое размещение не нарушит. Но не стоит забывать о возможности автоматизированного поиска текстовых строк в двоичном файле. В какой бы секции ни содержался эталонный пароль, фильтр без труда его найдет (единственная проблема — определить, какая из множества текстовых строк представляет собой искомый ключ; возможно, потребуется перебрать с десяток-другой потенциальных «кандидатов»).

Шаг второй. Знакомство с дизассемблером

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

Хакнуть, говорите? Что ж, это несложно! Куда проблематичнее определиться, чем именно ее хакать. Инструментарий хакеров чрезвычайно разнообразен, чего тут только нет: и дизассемблеры, и отладчики, и API-, и message-шпионы, и мониторы обращений к файлам (портам, реестру), и распаковщики исполняемых файлов, и… Сложновато начинающему кодокопателю со всем этим хозяйством разобраться!

Впрочем, шпионы, мониторы, распаковщики — второстепенные утилиты заднего плана, а основное оружие взломщика — отладчик и дизассемблер.

Итак, дизассемблер применим для исследования откомпилированных программ и частично пригоден для анализа псевдокомпилированного кода. Раз так, он должен подойти для вскрытия парольной защиты passCompare1.exe. Весь вопрос в том, какой дизассемблер выбрать.

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

Логичнее всего воспользоваться услугами дизассемблера-интеллектуала (если он есть), но… давайте не будем спешить, а попробуем выполнить весь анализ вручную. Техника, понятное дело, штука хорошая, да вот не всегда она оказывается под рукой, и неплохо бы заранее научиться работе в полевых условиях. К тому же общение с плохим дизассемблером как нельзя лучше подчеркивает «вкусности» хорошего.

Воспользуемся уже знакомой нам утилитой DUMPBIN, настоящим «швейцарским ножиком» со множеством полезных функций, среди которых притаился и дизассемблер. Дизассемблируем секцию кода (как мы помним, носящую имя .text), перенаправив вывод в файл, так как на экран он, очевидно, не поместится:

Заглянем еще раз в секцию данных (или в другую — в зависимости от того, где хранится пароль): см. листинг 2.

Запомним найденный пароль: myGOODpassword . В отличие от Visual C++ 6.0, которой пользовался Крис, Visual C++ 2017 не обращается к инициализированным переменным по шестнадцатеричному смещению, а подставляет значение прямо в секцию кода. Таким образом, попробуем найти выявленный ранее пароль в дизассемблированном листинге тривиальным контекстным поиском с помощью любого текстового редактора.

Смотрите, центральная часть этого листинга отвечает за сравнение значений регистров EAX и ECX. В последний, как мы видим, в первой строке листинга записывается эталонный пароль, следовательно, в первом — введенный пользователем. Затем происходит сравнение и выполняются переходы почти в одну и ту же точку: 0x4010A2 и 0x40109E. Заглянем, что там:

Здесь центральную роль играет инструкция test eax,eax , расположенная по смещению 0x4010A7. В случае если eax равен 0, следующая за ней команда JE совершает прыжок на 0x40110E. В противном же случае на вершину стека выталкивается строка Wrong password:

а следом — вызов функции с говорящим названием:

Значит, ненулевое значение EAX свидетельствует о ложном пароле, а ноль — об истинном.

О’кей, тогда переходим к анализу валидной ветви программы, что делается после прыжка на 0x40110E. А тут притаилась инструкция, которая помещает строку Password OK на вершину стека, после чего вызывается процедура _printf, которая, очевидно, выводит строку на экран:

Оперативные соображения следующие: если заменить команду JE на JNE, то программа отвергнет истинный пароль как неправильный, а любой неправильный пароль воспримет как истинный. А если заменить TEST EAX,EAX на XOR EAX,EAX, то после исполнения этой команды регистр EAX будет всегда равен нулю, какой бы пароль ни вводился.

Читайте также:  Почему происходит сбой загрузки страницы

Дело за малым — найти эти самые байтики в исполняемом файле и слегка подправить их.

Шаг третий. Хирургический

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

Ну, с «выкидыванием запчастей» справиться как раз таки просто — достаточно забить код командами NOP (опкод которой 0x90, а вовсе не 0x0, как почему-то думают многие начинающие кодокопатели), то есть пустой операцией (вообще-то NOP — это просто другая форма записи инструкции XCHG EAX,EAX — если интересно). С «раздвижкой» куда сложнее! К счастью, в PE-файлах всегда присутствует множество «дыр», оставшихся от выравнивания, в них-то и можно разместить свой код или свои данные.

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

Приходится резать программу вживую. Легче всего это делать с помощью утилиты Hiew, «переваривающей» PE-формат файлов и упрощающей тем самым поиск нужного фрагмента. Подойдет любая версия этого hex-редактора. Например, я использовал далеко не самую новую версию 6.86, прекрасно уживающуюся с Windows 10. Запустим ее, указав имя файла в командной строке hiew32 passCompare1.exe, двойным нажатием клавиши Enter, переключимся в режим ассемблера и при помощи клавиши F5 перейдем к требуемому адресу. Как мы помним, команда TEST, проверяющая результат на равенство нулю, располагалась по адресу 0x4010A7.

Чтобы Hiew мог отличить адрес от смещения в самом файле, предварим его символом точки: .4010A7.

Ага, как раз то, что нам надо! Нажмем клавишу F3 для перевода Hiew в режим правки, подведем курсор к команде TEST EAX,EAX и, нажав клавишу Enter, заменим ее на XOR EAX,EAX.

Hiew в режиме правки ассемблерной команды

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

Получилось! Защита пала! Хорошо, а как бы мы действовали, не умей Hiew «переваривать» PE-файлы? Тогда пришлось бы прибегнуть к контекстному поиску. Обратим свой взор на шестнадцатеричный дамп, расположенный дизассемблером слева от ассемблерных команд. Конечно, если пытаться найти последовательность 85 C0 — код команды TEST EAX,EAX, ничего хорошего из этого не выйдет — этих самых TEST’ов в программе может быть несколько сотен, а то и больше. А вот адрес перехода, скорее всего, во всех ветках программы различен, и подстрока TEST EAX,EAX/JE 0040110E имеет хорошие шансы на уникальность. Попробуем найти в файле соответствующий ей код: 85 C0 74 63 (в Hiew для этого достаточно нажать клавишу F7).

Опп-с! Найдено только одно вхождение, что нам, собственно, и нужно. Давайте теперь попробуем модифицировать файл непосредственно в hex-режиме, не переходя в ассемблер. Попутно возьмем себе на заметку — инверсия младшего бита кода команды приводит к изменению условия перехода на противоположное, то есть 74 JE -> 75 JNE.

Hiew в режиме правки шестнадцатеричного кода

Работает? В смысле защита свихнулась окончательно — не признает истинные пароли, зато радостно приветствует остальные. Замечательно!

Взломанная программа принимает любые пароли

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

Итак, ты прочел (прочел ведь?) начальный отрывок классической книги Криса Касперски «Фундаментальные основы хакерства» в современном переосмыслении. Получилось ли у нас обновить эти знания до актуального уровня? Стоит ли продолжать? Поделись своим мнением в комментариях.

Крис Касперски

Известный российский хакер. Легенда ][, ex-редактор ВЗЛОМа. Также известен под псевдонимами мыщъх, nezumi (яп. 鼠, мышь), n2k, elraton, souriz, tikus, muss, farah, jardon, KPNC.

Юрий Язев

Широко известен под псевдонимом yurembo. Программист, разработчик видеоигр, независимый исследователь. Старый автор журнала «Хакер».

Ссылка на основную публикацию
Установить программу для сканирования документов бесплатно
Загрузите бесплатно пробную полнофункциональную версию программы для сканирования Scanitto Pro. Данная версия работает без каких-либо ограничений в течение 30 дней....
Террария мешок с сюрпризом
Мешок с сокровищамиTreasure Bag Характеристики Тип Мешок Подсказка Открывать правой кнопкой мыши Редкость Внутренний ID предмета: 3318-3332 Эксклюзивный контент ПК...
Термопринтер для печати чеков
Термопринтер для чеков — это печатное устройство, которое применяется в торговле и ряде других сфер. Большинство моделей являются стационарными и...
Установить протокол mtp media transfer protocol
Описание Компания Microsoft содержит под своим крылом множество драйверов, среди этой коллекции находится и Media Transfer Protocol, тот самый драйвер,...
Adblock detector