Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #103, ИЮЛЬ 2007 г.

Секреты кряка

Вольф Д.А. aka payhash

Хакер, номер #103, стр. 072

Альтернативный метод написания генератора серийных номеров

В этой статье мы и поговорим об альтернативном (нетрадиционном) методе написания генераторов серийных номеров для самых маленьких.

Мануальная терапия

Итак, мы будем использовать стандартные средства отладки программного обеспечения (OllyDbg), а для наглядности возьмем незамысловатые примеры программных защит (далее keygenme’сов) с ресурса www.crackmes.de.

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

Ломаем ReHPer KeyGenMe v1.1

В качестве первого примера мы берем ReHPer KeyGenMe v1.1 (crackmes.de). Заходим на сайт http://crackmes.de, скачиваем ReHPer KeyGenMe v1.1 (уровень сложности 3-4) и запускаем.

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

Видим два TextEdit, скорей всего это поля Name и Serial. От фонаря вводим в них данные, жмем Check, обламываемся - другого мы и не ожидали. Загружаем OllyDbg, жмем <F3>, вскрываем объект для изучения. Смотрим: на первый взгляд, ни чем не упаковано. Можешь проверить через PEiD, но мы не станем прибегать к его помощи, так как невооруженным глазом видно, что код чистенький и неупакованный (автор гарантирует), и это уже радует, спасибо ReHPer.

Далее стартуем программу по нажатию <F9>, заполняем в произвольном виде форму (включая поле Edit2.Serial), подтверждаем через Check, пошагово трассируем программу по <F8> до тех пор, пока не дойдем до процедуры обработки ошибок ввода поля Edit2.Serial.

00464FB1 PUSH KeyGenMe.00465044 ; ASCII "Incorrect Password!"

00464FB6 MOV EAX,EBX

00464FB8 CALL KeyGenMe.0043F574

00464FBD PUSH EAX ; |hOwner

00464FBE CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA

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

0012FC18 ASCII "BLACKSMITH7051595229000" ; искомая сигнатура

0012FC1C ASCII "Gan1GqjJJKbKI3SmDJ4rEJKoCZamC30" ;нужный ключик

0012FC20 ASCII "lol"

0012FC24 ASCII "payhash"

В нашем случае найденный ключ хранится в области памяти по адресу 0x009763D8 и представляет собой ASCII-строку, у тебя это может быть другой адрес. Теперь посмотри на инструкцию, расположившуюся по адресу 0x00464FB1 (PUSH 465044).

00464FB1 68 44504600 PUSH KeyGenMe.00465044 ; ASCII "Incorrect Password!"

Немного подумав, ты понимаешь, что если в стек перед вызовом функции MessageBoxA вместо адреса, по которому располагается строка ASCII «Incorrect Password!» (0x465044), поместить адрес, указывающий на ASCII-строку с искомым ключом, находящемся в буфере (0x009763D8), то вместо ASCII-строки «Incorrect Password!» мы увидим Gan1GqjJJKbKI3SmDJ4rEJKoCZamC30. То есть вместо окна с надписью о том, что мы неудачники, высветится искомый серийный номер.

Выделяем инструкцию PUSH 465044, давим пробел, меняем PUSH 465044 на PUSH 009763D8, нажимаем правую кнопку мыши в окне с нашей декомпилированной программой, выбираем «Copy to Executable -> All Modifications -> Copy All». В появившемся окне снова жмем правую кнопку мыши, выбираем Save to File. Кейген написан.

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

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

Ломаем KeygenMe No.4 by n00b

Снова заходим на сайт http://crackmes.de, скачиваем KeygenMe No.4 by n00b (уровень сложности около пяти), запускаем. Посидев над его отладкой и сделав для себя очень полезные выводы, через некоторое время понимаем, что механизм генерации серийного номера этого софта может привести к инсульту. Лично мой ленивый и немолодой мозг уже не может переживать подобные перегрузки, да и нервы уже не те. В общем, заочный респект автору (n00b), молодец, хорошая защита. За целые сутки я выяснил только принцип генерации ключа, а с алгоритмом такими темпами разбираться было лень. Но keygen все же удалось нарисовать (как-никак это условие keygen*me/са.). Итак, начнем.

Запускаем в отладчике KeygenMe No.4 by n00b, давим <F9> и видим такую же картинку, как и в предыдущем примере. Заполняем форму, нажимаем «Is it correct?» - и ничего не происходит. Очевидно, праздничное событие произойдет при правильно введенном серийном номере. Огорчает тот факт, что это в некотором смысле затрудняет использование нетрадиционного метода написания генератора ключей (как в предыдущей части статьи). Перезапускаем программу по <Ctrl-F12> и пробуем провести поверхностный анализ дизассемблированного кода. Не спеша поднимаемся выше, ищем, за что можно зацепиться, помним, что нам необходимо найти участок, где выводится сообщение с поздравлением; в большинстве случаев рядом находятся точки входа в нужные процедуры. И вот мы обнаружили искомый код.

0045AFE7 POP EAX

0045AFE8 CALL keygenme.00404340

0045AFED JNZ SHORT keygenme.0045AFF9

; ASCII "Damn, your good! Make a keygen and send me the solution!"

0045AFEF MOV EAX,keygenme.0045B1EC

; вызываем процедуру вывода сообщения

0045AFF4 CALL keygenme.0042E0D0

Что можно такого придумать для того, чтобы выполнить задание? Интересным нам показался вызов CALL 00404340. Что же, ставим на него break point (<F2>), затем стартуем программу на выполнение (<F9>), заполняем необходимые поля и подтверждаем выполнение. После выполнения отладчик остановился в забронированном нами месте (там, где ставили бряк). Теперь смотрим правое нижнее окошечко и видим, что в памяти уютно расположился искомый серийный номерок.

0012F5A4 ASCII "ad" ; третья часть ключика

0012F5A8 ASCII "3A5A" ; вторая часть ключика

0012F5AC ASCII "0189" ; первая часть ключика

0012F5B0 ASCII "0189-3A5A-ad" ; нужный ключик

Как мы можем написать генератор, если не выводится печальное сообщение? Все просто - мы будем использовать функцию, выводящую праздничное сообщение, изменив условие программы (вернее, вообще ликвидировать всю условность проверки). Но метод прямой подмены адреса строки в процедуре, как это выполнялось выше, в этом случае не работает. Соответственно, немного модифицируем код (тут придется вспомнить уроки по ассемблеру). Взглянем на то, что творится в регистрах нашего ЦПУ перед тем, как будет произведен вызов «CALL 00404340». Радует то, что в регистре EDX находится указатель на адрес в буфере, по которому расположился искомый серийный номер.

EAX 009260D4 ASCII "lolz"

ECX 00000001

EDX 00926378 ASCII "0189-3A5A-ad"

EBX 00921978

ESP 0012F590

EBP 0012F618

ESI 0042AE2C keygenme.0042AE2C

EDI 0012F798

EIP 0045AFE8 keygenme.0045AFE8

Очевидно, что по этому адресу происходит сравнение введенного нами серийного номера и того, который сейчас в EDX. Сделаем так, чтобы инструкция CALL 00404340 на этом участке никогда больше не выполнялась, сотрем ее инструкцию, следуя закону сохранения байтов, заполним ее NOP’ами. Выделяем инструкцию, нажимаем на ней правую клавишу мыши, выбираем «Binary -> Fill with NOPs». У нас должно получиться следующее:

0045AFE7 POP EAX

0045AFE8 NOP

0045AFE9 NOP

0045AFEA NOP

0045AFEB NOP

0045AFEC NOP

0045AFED JNZ SHORT keygenme.0045AFF9

; ASCII "Damn, your good! Make a keygen and send me the solution!"

0045AFEF MOV EAX,keygenme.0045B1EC

0045AFF4 CALL keygenme.0042E0D0

Очевидно, что и в инструкции «JNZ SHORT keygenme.0045AFF9» мы тоже не нуждаемся, поэтому ее также заполняем NOP’ами или переправляем на JNZ SHORT 0045AFEF. Теперь у нас есть, куда выводить, осталось получить, что выводить. Операция «MOV EAX,keygenme.0045B1EC» загружает указатель на ASCII-строку «Damn, your good! Make a keygen and send me the solution!». Но наша задача - выводить правильный серийный номер, а указатель на него хранится в регистре EDX, поэтому поменяем эту инструкцию на MOV EAX, EDX, а после инструкции POP EAX запишем PUSH EAX. После выполнения операций у нас должно получиться следующее.

0045AFE7 POP EAX

0045AFE8 PUSH EDX

0045AFE9 NOP

0045AFEA NOP

0045AFEB NOP

0045AFEC NOP

0045AFED JNZ SHORT keygenme.0045AFEF

0045AFEF MOV EAX,EDX

0045AFF1 NOP

0045AFF2 NOP

0045AFF3 NOP

0045AFF4 CALL keygenme.0042E0D0

Сохраняем модифицированный код, например, как serial.exe вышеописанным способом или способом, указанным в документации OllyDbg. Запускаем serial.exe, вводим в поле «Yer name...» любое слово, нажимаем подтверждение и радуемся ключику и готовому халявному генератору ключей.

Нам могут сказать: «Так нечестно!» Но мы выполнили все условия задания keygenme/са KeygenMe No.4 by n00b.

KeygenMe No.4 by n00b README:

ЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕЕ

Tasks:

1:=) Code a complete keygen...

2:=) Send your solution to me...

NOTE:

-----

This keygenme IS NOT RATED for newbies!

Условия задания крякмиса KeygenMe No.4 by n00b

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

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

Несколько советов начинающему крякеру

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

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

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

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

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

В ремесле реверсного инженера ничего не дается даром, поэтому, если что-то непонятно, читай дополнительную литературу в офф- и онлайне, но никогда не останавливайся, не достигнув свой цели.

Содержание