Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Техника и философия хакерских атак II (фрагмент [2/3])

Крис Касперски
kk@sendmail.ru

классификация защит по стойкости к взлому

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

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

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

Конечно, для рядовых пользователей, абсолютно ничего не смыслящих ни в дизассемблерах, ни в отладчиках, совершенно все равно каким путем осуществляется проверка вводимого ими регистрационного номера. Защищенное приложение с их точки зрения представляет собой "черный ящик", на вход которого подается некоторая ключевая информация, а на выходе: "success" или "fuck out, shit mother fucker!". Хакеры - другое дело. Если регистрационный номер используется для расшифровки критически важных модулей программы, - дело дрянь и, если процедура шифрования реализована без ошибок, единственное, что остается - найти рабочую (читай - легально зарегистрированную) программу и снять с нее дамп. Если же защита тем или иным путем сравнивает введенный пользователем пароль с заложенным в нее эталонным паролем, - у хакера есть все шансы ее сломать. Как? Исследуя защитный код хакер может:

а) найти эталонный пароль и "подсунуть" ее программе как ни в чем не бывало;

б) заставить защиту сравнивать веденный пароль не с эталоном, а: с самим собой!

в) выяснить какой именно условный переход выполняется при вводе неверного пароля и скорректировать его так, чтобы он передавал управление не на ругательное сообщение, а на "легальную" ветку программы;

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

Возникает вопрос: если логические защиты и вправду настольно слабы, то почему же их так широко используют? Во-первых, большинство разработчиков программного обеспечения совершенно не разбираются в защитах и просто не представляют во что именно компилятор "перемалывает" исходный код (судя по всему, машинный код им представляется таким дремучим лесом, из которого живым никто выбраться не сможет). Во-вторых, в ПО массового назначения надежность защитных механизмов все равно ничего не решает. Как было сказано выше, при наличии хотя бы одной-единственной зарегистрированной копии, хакер просто "снимет" с программы дамп и все! Защита, даже не успев сказать "мяу", отлетит в мир иной (туда - где, находится тот самый Сервер, на который попадают все деинсталируемые программы без исключения). В-третьих, основной доход от продаж ПО приходится на долю тех страх, граждане которых законопослушны и защиты на ломают. Что же до нас, - россиян - мы программы вообще не покупаем. Даже если защитный механизм окажется хакерам не по зубам, акты легальной покупки программы будут носить единичный характер.

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

классификация защит по роду секретного ключа

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

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

а) защитный механизм нейтрализуется (в особенности это относится к тем защитам, которые просто проверяют ключевой носить на наличие неких уникальных характеристик, но реально никак их не используют);

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

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

Очевидно, что защиты, основанные на знании, полагаются исключительно на законодательство и законопослушность пользователей. Действительно, что помешает легальному пользователю поделиться паролем или сообщить серийный номер всем желающим? Конечно, подобное действие квалифицируется как "пиратство" и с недавнего времени преследуется по закону. Но точно также преследуются (и наказываются!) все нелегальные распространители контента, охраняемого авторским правом, вне зависимости от наличия/отсутствия на нем защиты. Тем не менее, несмотря на резко ожесточившуюся борьбу с пиратами, нелегальное программное обеспечение по-прежнему свободно продается как в центральных магазинах, так и на радиорынках. Практически под любую программу, распространяемую через Internet как share-ware, в том же самом Интернете можно найти готовый "кряк" или ее бесплатный аналог (и нечего тут смеяться!).

В этих условиях "спасение утопающих - дело рук самих утопающих". Наивно, конечно, думать, что количество легальных продаж прямо пропорционально крутизне вашей защиты, но: share-ware программа без защиты рискует перестать продаваться вообще (даже американские "зомби" предпочитаю не платить за программу, которая каждый день об этом им не напоминает). В первом издании настоящей книги я писал "Самые распространенные сегодня защиты - это пароли и серийные номера". Изменилось что ни будь за истекшие четыре года? Анализ программ, прилагаемых к журналу "Компьютер Пресс" на CD показал, что многие разработки наконец-то вняли советам хакеров и убрали пункт "Registers" из меню и теперь программа требует для регистрации: неизвестно что. Это может быть и ключевой файл, и запись в реестре, и некоторая последовательность "вслепую" нажимаемых клавиш, и: еще много всего! Так же исчезли текстовые сообщения о успешности/не успешности регистрации, в результате чего локализация защитного механизма в коде исследуемой программы значительно усложнилась (при наличии текстовых сообщений нетрудно по перекрестным ссылкам найти кто именно их выводит, после чего защитный механизм можно легко "раскрутить").

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

Тем не менее, такие защиты очень просто обнаружить и еще проще устранить. Обращение к Интернету не может пройти незаметным, - сам факт такого обращения легко распознается даже штатной утилитой NET STAT, входящий в комплект поставки операционных систем Windows 9x/NT, ну а эстеты могут воспользоваться TCPVIEW Марка Русиновича. Локализовать код защитного механизма так же не составит большого труда, - достаточно пойти по следу тех самых API-функций, которые, собственно, и демаскируют защиту, причем, все известные мне защиты этого типа пользовались исключительно библиотекой WINSOCS и ни одна из них не отважилась взаимодействовать с сетевым драйвером напрямую, да, впрочем, это все равно не усложнило бы взлом:

шаг первый - создаем защиту и пытаемся ее сломать

Предложим, что мы хотим оградить некоторую программу от доступа посторонних. Как это можно сделать? Самое простое, что приходит нам в голову - сразу же после запуска программы затребовать у пользователя пароль и сравнить его с эталоном. Затем, в зависимости от результата сравнения, либо послать пользователя к черту, либо продолжить нормальное выполнение программы. ОК, на словах все выглядит хорошо, но как это реализовать программно?

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

#define legal_psw	"my.good.password"

main()
{
	char user_psw[666];
	
	cout << "crackme 00h\nenter passwd:"; cin >> user_psw;
	if (strcmp(legal_psw, user_psw))
		cout << "wrong password\n";
	else
		cout << "password ok\nhello, legal user!\n";
	
	return 0;
}

Листинг 1 C5F11EA6h пример простейшей парольной защиты

Откомпилируем crackme.C5F11EA6h.cpp и запустим его на выполнение. Ага, программа требует ввести пароль. Чтобы сравнить введенным пароль с эталонным, последний должен как-то храниться в программе, так? А тестовые строки, между прочим, никак не уродуются компилятором и в откомпилированном файле хранятся в своем "естественном" виде!

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

Для просмотра дампа подойдет любой hex-вьювер (например, всем известный HIEW), а при его отсутствии вас выручит знаменитая утилита dumpbin входящая в штатный комплект поставки подавляющего большинства Windows-компиляторов.

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

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

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

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

 ------------> смещение в файле
 ¦
 ¦          -------> текстовая строка
 ¦          ¦ 
00007D11:LCMapStringW
00007D1F:KERNEL32.dll
0000805C:crackme 00h
0000806A:enter passwd:
0000807D:my.good.password
0000808F:wrong password
0000809C:password ok
000080AF:hello, legal user!
000080C2:.?AVios@@
000080DE:.?AVistream@@
00008101:.?AVistream_withassign@@
0000811E:.?AVostream@@
00008141:.?AVostream_withassign@@
00008168:.?AVstreambuf@@
0000817E:.?AVfilebuf@@
000081A0:.?AVtype_info@@

Листинг 2 результат автоматической фильтрации двоичного тела программы

Рассмотрим полученный листинг. Обратим внимание на строку "my.good.password", находящуюся по адресу 807Dh. Не правда ли, она могла бы быть паролем? Чаще всего (но необязательно) искомая строка располагается близко к тексту "введите пароль". Ниже (80AFh) мы видим еще одного "кандидата". Давайте проверим, подойдет ли хотя бы один из них?

> crackme. C5F11EA6h.exe
enter passwd:my.good.password
password ok
hello, legal user!

Листинг 3 скармливание программе первого пароля-кандидата. ответ защиты красноречиво свидетельствует о ее полной и безоговорочной капитуляции

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

шаг второй от EXE до CRK

Бесспорно, среди существующих на сегодняшний день дизассемблеров лучшим является IDA Pro. Особенно идеально она подходит для взлома и изучения защищенных программ. Очевидно, что crackme.C5F11EA6h не является таковой в полном смысле этого слова. В нем нет ни шифрованного кода, ни "ловушек" для дизассемблеров. SOURCER или любой другой справился бы с этой задачей не хуже. Поэтому окончательный выбор я оставляю за читателем (кстати, четвертая версия ИДЫ с некоторого времени начала распространяться бесплатно).

После того как дизассемблер завершит свою работу и выдаст километровый листинг, неопытный читатель может испугаться: как войти в эти дебри непонятного и запутанного кода? Сотни вызовов функций, множество условных переходов... Как во всем этом разобраться? И сколько времени потребуется на анализ? К счастью, нет никакой нужды разбираться во всем дизассемблированном листинге целиком. Достаточно изучить и понять алгоритм защитного механизма, ответственного за сверку паролей. Единственная проблема как найти этот механизм в бескрайних степях дизассемблерного кода? Можно ли этого добиться иначе, чем полным анализом всей программы? Разумеется, можно! Давайте, например, попробуем воспользоваться перекрестными ссылками на ASCII-строки типа "неверный пароль", "пароль ОК", "введите пароль", прямым текстом содержащиеся в программе. Чаще всего код, ответственный за их вывод на экран, находится непосредственно в гуще защитного механизма или, на худой конец, расположен где-то поблизости.

Сами же строки в подавляющем большинстве случаев находятся в сегменте данных, именуемом ".data". (В старых программах под DOS это правило часто не соблюдалось. В частности, компилятор Turbo Pascal любил располагать константы непосредственно в кодовом сегменте). Для перехода в сегмент данных в IDA нужно в меню "View" выбрать пункт "Segments" и среди перечисленных в появившемся окне сегментов отыскать сегмент с именем "data". Прокручиваем экран дизассемблера на несколько страниц вниз и, - вот они наши строки, сразу же бросающиеся в глаза даже при беглом просмотре:

.data:00408050 aCrackme00hEnte db 'crackme 00h',0Ah      ; DATA XREF: sub_401000+D^o
.data:00408050                 db 'enter passwd:',0
.data:0040806A                 align 4
.data:0040806C aMy_good_passwo db 'my.good.password',0   ; DATA XREF: sub_401000+2A^o
.data:0040807D                 align 4
.data:00408080 aWrongPassword  db 'wrong password',0Ah,0 ; DATA XREF: sub_401000+62^o
.data:00408090 aPasswordOkHell db 'password ok',0Ah      ; DATA XREF: sub_401000+7A^o
.data:00408090                 db 'hello, legal user!',0Ah,0
.data:004080B0                 dd offset off_4071A0

Листинг 4 текстовые строки и перекрестные ссылки

Смотрите, - IDA автоматически восстановила перекрестные ссылки на эти строки (т. е. опередила адрес кода, который к ним обращается) и оформила их в виде комментария (в приведенном выше листинге они выделены жирным шрифтом). Каббалистическая грамота типа "DATA XREF: sub_40100+62" расшифровывается как "перекрестная ссылка [X - References] на данные [DATA], ведущая к коду, расположенному по смещению 0x62 относительно начала функции sub_40100". Для быстрого перехода в указанное место достаточно лишь подвести курсор в границы "sub_401000+62" и долбануть по <ENTER'у> или же дважды щелкнуть мышем. Через мгновение судьба нас заносит сюда:

.text:00401000 sub_401000      proc near	       ; CODE XREF: start+AF p
.text:00401000 
.text:00401000 var_29C	       = byte ptr -29Ch
.text:00401000 
.text:00401000    sub  esp, 29Ch
.text:00401006    mov  ecx, offset dword_408A50
.text:0040100B    push ebx
.text:0040100C    push esi
.text:0040100D    push offset aCrackme00hEnte      ;"crackme 00h\nenter passwd:"
.text:00401012    call ??6ostream@@QAEAAV0@PBD@Z   ; ostream::operator<<(char const *)
.text:00401017    lea  eax, [esp+2A4h+var_29C]
.text:0040101B    mov     ecx, offset dword_408A00
.text:00401020    push    eax
.text:00401021    call    ??5istream@@QAEAAV0@PAD@Z ; istream::operator>>(char *)
.text:00401026    lea     esi, [esp+2A4h+var_29C]
.text:0040102A    mov     eax, offset aMy_good_passwo ; "my.good.password"
.text:0040102F
.text:0040102F loc_40102F:			       ; CODE XREF: sub_401000+51 j
.text:0040102F    mov     dl, [eax]
.text:00401031    mov     bl, [esi]
.text:00401033    mov     cl, dl
.text:00401035    cmp     dl, bl
.text:00401037    jnz     short loc_401057
.text:00401039    test    cl, cl
.text:0040103B    jz      short loc_401053
.text:0040103D    mov     dl, [eax+1]
.text:00401040    mov     bl, [esi+1]
.text:00401043    mov     cl, dl
.text:00401045    cmp     dl, bl
.text:00401047    jnz     short loc_401057
.text:00401049    add     eax, 2
.text:0040104C    add     esi, 2
.text:0040104F    test    cl, cl
.text:00401051    jnz     short loc_40102F
.text:00401053 
.text:00401053 loc_401053:			       ; CODE XREF: sub_401000+3B j
.text:00401053    xor     eax, eax
.text:00401055    jmp     short loc_40105C
.text:00401057 ; ------------------------------------------------------------------
.text:00401057 
.text:00401057 loc_401057:			       ; CODE XREF: sub_401000+37 j
.text:00401057				       ; sub_401000+47 j
.text:00401057    sbb     eax, eax
.text:00401059    sbb     eax, 0FFFFFFFFh
.text:0040105C 
.text:0040105C loc_40105C:			       ; CODE XREF: sub_401000+55 j
.text:0040105C    pop     esi
.text:0040105D    pop     ebx
.text:0040105E    test    eax, eax
.text:00401060    jz      short loc_40107A
.text:00401062    push    offset aWrongPassword ; "wrong password\n"
.text:00401067    mov     ecx, offset dword_408A50
.text:0040106C    call  ??6ostream@@QAEAAV0@PBD@Z ; ostream::operator<<(char const *)
.text:00401071    xor     eax, eax
.text:00401073    add     esp, 29Ch
.text:00401079    retn
.text:0040107A ; ---------------------------------------------------------------------
.text:0040107A 
.text:0040107A loc_40107A:			       ; CODE XREF: sub_401000+60 j
.text:0040107A    push   offset aPasswordOkHell ;"password ok\nhello, legal user!\n"
.text:0040107F    mov     ecx, offset dword_408A50
.text:00401084    call   ??6ostream@@QAEAAV0@PBD@Z ; ostream::operator<<(char const *)
.text:00401089    xor     eax, eax
.text:0040108B    add     esp, 29Ch
.text:00401091    retn
.text:00401091 sub_401000      endp

Листинг 5 результат дизассемблирования файла crackme.C5F11EA6h.cpp, местоположение курсора выделено инверсным цветом

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

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

Впрочем, своей крутизной нам еще рано гордится. Ведь защитный код нашли не мы, а интеллектуальный анализатор дизассемблера IDA. А как быть тем несчастным у которых этого дизассемблера просто нет? Что ж, тогда можно воспользоваться любым подручным hex-редактором (пусть для определенности это будет HIEW), ну и конечно своими собственными руками и головой. Постойте! - воскликнет иной читатель. - Но какой черт мы будем возиться с HIEW'ом, загружая свою голову не весь чем, когда можно приобрести IDA, избавляя тем самым от необходимости вникать во все премудрости ручного анализа! Что ж, - отвечу я. Свой жизненный путь каждый из нас выбирает сам. И если вам в первую очередь важен конечный результат, а на понимание сути происходящего вы готовые плевать - пожалуйста, идите этим путем. Действительно, большинство защит вскрываются стандартными приемами, которые достаточно заучить как "отче наш", и которые не требуют понимания "как это работает". Далеко не каждый кракер обладает глубокими знаниями того, что он ломает. Мой тезка и в каком-то смысле коллега (широко известный среди спектрумистов уже едва ли не десяток лет) однажды сказал "Умение снимать защиту, еще не означает умения ее ставить". Это типично для кракера, ломающего программы за деньги, а не на интерес. Хакеры же в свою очередь больше интересуются именно принципом функционирования защитного механизма и взлом для них вторичен. Взломать программу, но не понять ее, - для хакера все равно, что ничего вообще не взломать. Взлом он ведь разный бывает: можно, например, просто подобрать пароль методом тупого перебора, а можно бросить защите интеллектуальный вызов и победить ее или проиграть, но как проиграть! Горечь поражение компенсирует приобретенный опыт и он же дает пищу для последующих размышлений, делает нас выше, лучше, умнее! А тупой перебор нам ничего кроме как щенячьей радости от победы не добавляет.

Итак, если вы хакер, - ваши пальцы быстро набивают на клавиатуре заветное: "hiew crackme.C5F11EA6h.exe". Теперь, вызывая диалог контекстного поиска по <F7> мы пытаемся найти по какому адресу в файле расположена строка "wrong password" (обратите внимание: именно адресу, а не смещению, - hiew несмотря на свою кажущуюся простоту, в порядке собственной инициативы анализирует заголовок PE-файла и автоматически переводит смещения в виртуальные адреса, т. е. те адреса, которые данные ячейки получат после загрузки файла в память):

.00408080:  77 72 6F 6E-67 20 70 61-73 73 77 6F-72 64 0A 00  wrong password0
.00408090:  70 61 73 73-77 6F 72 64-20 6F 6B 0A-68 65 6C 6C  password ok0hell
.004080A0:  6F 2C 20 6C-65 67 61 6C-20 75 73 65-72 21 0A 00  o, legal user!0
.004080B0:  A0 71 40 00-00 00 00 00-2E 3F 41 56-69 6F 73 40  аq@     .?AVios@
.004080C0:  40 00 00 00-00 00 00 00-A0 71 40 00-00 00 00 00  @       аq@

Листинг 6 определение адреса текстовых строк, выводимых защитой при вводе неправильного пароля

Если верить HIEW'у, то строка "wrong password" расположена по адресу 00408080h. Запоминаем (записываем его на бумажке) и, не забыв переместиться в начало файла, давим <F7> еще раз и в поле "hex" вводим адрес строки, записанный задом наперед: "80 80 40 00". Почему задом наперед?! Да потому что в x86 процессорах младшие байты всегда располагаются по меньшему адресу и, соответственно, наоборот. Если сказанное вам не очень-то понятно, обратитесь к любому учебнику по ассемблеру (или к документации на x86 процессоры наконец).

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

.0040105E: 85C0                         test      eax,eax
.00401060: 7418                         je       .00040107A   -------- (2)
.00401062: 6880804000                   push      000408080 ;" @ИИ"
.00401067: B9508A4000                   mov       ecx,000408A50 ;" @SP"
.0040106C: E884040000                   call     .0004014F5   -------- (2)
.00401071: 33C0                         xor       eax,eax
.00401073: 81C49C020000                 add       esp,00000029C ;"  O?"
.00401079: C3                           retn
.0040107A: 6890804000                   push      000408090 ;" @И?"
.0040107F: B9508A4000                   mov       ecx,000408A50 ;" @SP"
.00401084: E86C040000                   call     .0004014F5   -------- (3)
.00401089: 33C0                         xor       eax,eax
.0040108B: 81C49C020000                 add       esp,00000029C ;"  O?"
.00401091: C3                           retn

Листинг 7 результат поиска кода, выводящего строку "wrong password" на экран, положение курсора выделено инверсным цветом

Сравните его с дизассемблерным листингом IDA, не правда ли, результат работы HIEW'а несколько менее информативен? Однако мы отвлеклись. И возращение к нашим баранам мы начнем с изучения прототипа функции ostream::operator<<(char const*) (она же - функция .0004014Fh в HIEW'е). Компилятор языка Cи заносит в стек все аргументы справа налево, поэтому 0x408080 и будет тем указателем на строку (*str), которую эта функция и выводит. Таким образом, мы находимся в непосредственной близости от защитного механизма. Сделаем еще один шаг, переместив свой взор на несколько строк назад (т. е. в область меньших адресов), видите:

.0040105E: 85C0                         test      eax,eax
.00401060: 7418                         je       .00040107A   -------- (2)

Листинг 8 тот самый заветный условный переход, который отличает всех правильных пользователей от неправильных

Выводу строки "wrong password" предшествует условный переход JE .00040107A, который в случае нулевого значения регистра EAX "перепрыгивает" через функцию вывода строки "wrong password", т. е. другими словами, передает управление на "правильную" ветку программы, - именно ту, которая выводит "password ok"!

Пришло время немного "похулиганить" и изменить ту заветную пару байт, которая мешает нелегальным пользователям (а так же всем легальным, но забывшим пароль) получить доступ к программе. Достаточно очевидно, что если изменить условный переход JE .0040107A на безусловный JMP short .0040107A любой введенный пароль защита станет воспринимать как правильный. Переводим HIEW в режим редактирования, нажав <F3> и подведя курсор к строке с этим самым условным переходом, меняем "JE" на "JPMS". Теперь сохраняем изменения в файле <F9> и выходим.

Запустим программу и попробуем ввести любое слово (желательно из нормативной лексики), пришедшее нам на ум. Если все было сделано правильно, на экране победно загорается надпись "password ok". Если же программа зависла, значит, мы где-то допустили ошибку. Восстановим программу с резервной копии и повторим все сначала.

Если же взлом прошел успешно, то можно попробовать придумать какую-нибудь шутку. Вот, например, подумаем, что произойдет, если заменить JE на JNE? Ветви программы поменяются местами! Теперь, если будет введен неправильный пароль, то система воспримет его как истинный, а легальный пользователь, вводя настоящий пароль, с удивлением прочитает сообщение об ошибке.


часть 1 | часть 2 | часть 3 | часть 4

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог