Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Взлом Sky Commander v1.5.1.270 и написание кейгена

Обсудить статью на форуме

Массу крэкерских инструментов, видеоуроков и статей вы сможете найти на видеокурсе от нашего сайта. Подробнее здесь.

Автор: Devil_guy <Devil_guy@mail.ru>

Уровень сложности: Новичок, крекер.

Инструменты
SoftIce or OllyDebuger
W32Dasm 8.9 or 10
Quick Unpack 0.7
PeID
Delphi

Шаг 1. Сбор информации.
Sky Commander – не плохой файловый менеджер от NMZ Labs. Удобный и простой интерфейс, возможность лечения ZIP архивов, доступ к локальной сети, возможность настраивания proxy – сервера и многое другое. В незарегистрированной версии триал 30 дней, да ещё надоедливое окно при старте, больше известное как NAG – Screen. В общем прога неплохая и я решил её сломать.

Шаг 2. Анализ.
Первое что желательно сделать при исследовании какой либо программы, это узнать на каком языке она написана, или каким пакером (протектором) она упакована. Легче всего это сделать двумя способами.
Первый способ – посмотреть ресурсы программы с помощью редактора ресурсов, например Restorator. В первом случае при попытке открыть какой – нибудь ресурс, Restorator скажет что «Ресурс поврежден (вероятно, файл сжат или зашифрован)», из этого можно понять, что программа упакована. Кстати, обратите внимание на секцию «RCData» в ресурсах программы, этот фактор железно свидетельствует о том, что программа написана на Delphi, позже это подтвердится.
Второй способ – открыть программу в анализаторе, например PeID, или Stud_Pe (я лично пользуюсь PeID’ом, но Stud_Pe тоже не плох). Открываем. PeID показал «ASPack 2.12 ->Alexey Solodovnikov». К сожалению, я не смог восстановить импорт после распаковки, поэтому распаковал программу при помощи Quick Unpack 0.7, вы уж не пинайте я еще новичок в распаковке.
После распаковки PeID показывает Borland Delphi 4.0 - 5.0 и мы можем приступать к исследованию программы.

Шаг 3. Взлом.
Запускаем распакованною программу и пробуем регистрироваться. Вводим свое имя, регистрационный код от балды и давим на кнопку «Зарегистрировать». Оппа, как ни странно сообщение о неверной регистрации. Запомните строку в сообщении, это нам пригодиться для поиска адреса этого сообщения в программе.
Далее загружаем распакованною программу в W32Dasm, если же засунуть в дисассемблер запакованною программу, то секции строк будут не доступны. Это связано с тем что, в теле файла присутствуют секции с запакованными данными. После дисассемблирования программы открываем окно поиска строк, для этого идем в меню Search -> Find Text и в поле Find what вводим строку, которая была в сообщении о неверной регистрации «Неверный регистрационный код!». Давим на кнопку «Find Next» и попадаем сюда:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|: 004FBEED
|

* Possible StringData Ref from Code Obj -> “Неверный регистрационный код!”
: 004FBF50 B8ACBF4F00 mov eax, 004FBFAC
: 004FBF55 E8825BF9FF call 00491ADC

Если у вас вместо строки * Possible StringData Ref from Code Obj -> “Неверный регистрационный код!” появиться какая – то непонятная надпись, то вам следует поменять шрифт. Сделать это можно зайдя в меню Disassembler -> Font -> Select Font, а затем Disassembler -> Font -> Save Default Font. Но вернемся к исследованию. В строке по адресу 004FBF55 мы видим команду call 00491ADC, эта команда какраз и вызывает окошко о неправильной регистрации.
Что такое команда call спросите вы? Команда call – это команда низкоуревнего языка программирования Ассемблер, предназначенная для вызова подпрограммы или функции. Вот детальное описание:

Схема команды: call цель

Назначение:
• передача управления близкой или дальней процедуре с запоминанием в стеке адреса точки возврата;
• переключение задач.
То есть когда программа выполнит команду по адресу 004FBF55, она покажет нам сообщение о неправильном регистрационном номере.
Обратите внимание и на такую строку:

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|: 004FBEED

Она означает, что данная подпрограмма вызвана из адреса 004FBEED. Проверим. Открываем окно поиска строк и вводим в поле «Find what» адрес 004FBEED, но перед тем как запустить поиск, в группе «Direction» надо выбрать поле «Up» для того чтобы дисассемблер искал нужную строку снизу – вверх, так как адрес 004FBEED идет перед адресом вызова нашего сообщения (004FBF55). Жмем два раза «Find Next» и попадаем сюда:

: 004FBEE6 E89DB60300 call 00537588
: 004FBEEB 84C0 test al, al
: 004FBEED 7461 je 004FBF50 <- сюда мы попали

* Possible StringData Ref from Code Obj -> “Спасибо за регистрацию!”

: 004FBEEF B88CBF4F00 mov eax, 004FBF8C
: 004FBEF4 E8E35BF9FF call 00491ADC <- это вызов сообщения об успешной регистрации

Теперь внимание! При нажатии на кнопку «Find Next» мы попали на команду условного перехода «je» по адресу 004FBEED, эта команда при некотором условии делает прыжок на адрес команды вызова сообщения о неверной регистрации. Давайте посмотрим на команду выше. Что делает команда test? Команда test сравнивает два операнда, в нашем случае это две младшее части регистра еах – al. При успешном выполнении команды, test устанавливает флаг нуля в единицу (подробнее смотрите далее). Это и есть то самое условие, при котором команда «je» выполнит свой прыжок. Еще выше можно увидеть вызов, какой – то подпрограммы. Тоесть сначала идет вызов подпрограммы или функции (у нас это подпрограмма), потом сравнение операндов, если test установил флаг нуля в единицу, то прыгаем на вызов о неудачной регистрации, если же нет, то команда условного перехода не выполняется и дальше мы попадаем на вызов сообщения об успешной регистрации (004FBEF4). Это всё наводит на мысль что по адресу 004FBEE6, лежит процедура генерации регистрационного кода. Так и есть.
В большинстве случаев это стандарт, сначала идет генерация, потом сравнение командой test (команда test не сравнивает два пароля, она сравнивает только с нуль), а далее условный переход, либо на верность регистрации, либо нет.
Теперь подробнее о выше упомянутых командах:

Схема команды: test приемник, источник

Назначение: операция логического сравнения операндов приемник и источник размерностью байт (byte – 1 байт), слово(word – 2 байта) или двойное слово(dword – 4 байта).
Алгоритм работы:
• выполнить операцию логического умножения над операндами приемник и источник: бит результата равен 1, если соответствующие биты операндов равны 1, в остальных случаях бит результата равен 0;
• установить флаги.
Применение:
Команда test используется для логического умножения двух операндов. Результат операции, в отличие от команды and, никуда не записывается, устанавливаются только флаги. Эту команду удобно использовать для получения информации о состоянии заданных битов операнда приемник. Для анализа результата используется флаг zf, который равен 1, если результат логического умножения равен нулю.
Схема команды: jz или je метка

Назначение: переход если флаг нуля установлен в единицу или условие равно
• jz (Jump if Zero) – переход если флаг нуля установлен.
• je (Jump if Equal) – переход, если равно.
Команды jz и je одинаковы. Например, дисассемблер может показывать je, а отладчик jz.
Схема команды: jnz или jne метка

Назначение: переход если флаг нуля не установлен в единицу или условие не равно
• jnz (Jump if not Zero) – переход если флаг нуля не установлен.
• jne (Jump if not Equal) – переход, если не равно.
И опять же команды jnz и jne одинаковы.

Всё, на этом работу в дисассемблере заканчиваем.
Шаг 4. Исследование генерации регистрационного кода.
В предыдущей, так сказать, главе мы выяснили, что генерация регистрационного кода в программе происходит по адресу 004FBEE6. Легче всего исследовать генерацию, да и вообще любую процедуру, с помощью отладчика. Для этого надо поставить брэкпоинт на адрес или функцию, у нас это адрес 004FBEE6. Кто еще не знает, брэкпоинт – это точка останова программы. Приступим.

Установка брэкпоинта при помощи OllyDebuger:
Для новичков лучше использовать OllyDebuger. Запускаем отладчик и открываем распакованный файл. Если появиться окошко «Entry Point Alert», то не волнуйтесь просто нажмите «OK». Ждем немного пока отладчик проанализирует файл. После анализа мы попали на Entry Point программы. Теперь надо поставить брэкпоинт на адрес вызова процедуры генерации регистрационного номера, найдем в окне кода (окно кода – это левое верхнее окно с ассемблерными командами) адрес 004FBEE6 и, выделив его мышкой, нажимаем F2, адрес должен выделиться красным цветом. Когда программа дойдет до адреса 004FBEE6, мы попадем в отладчик. Запускаем программу нажатием клавиши «F9». Программа сразу не запуститься, для этого надо обойти все исключения нажатием клавиш «Shift+F9». После запуска программы открываем окно регистрации и вводим любые данные, у меня это имя «Devil_guy» рег. код «1234567890», жмем «Зарегистрировать» и попадаем сюда:

004FBEE6 |. E8 9DB60300 CALL SkyComma.00537588

Теперь надо зайти внутрь этой процедуры нажатием «F7». Вы должны попасть на адрес 00537588, это и есть тот самый вызываемый адрес, с которого начинается процедура генерации. Саму процедуру я приведу далее.

Установка брэкпоинта при помощи SoftIce:
Запускаем Sky Commander и открываем окно регистрации. Запускаем SoftIce (Ctrl+D) и вводим «addr Skycommander». Это мы сделали для того, чтобы наш процесс был текущим, иначе брэкпоинт может не сработать. Теперь нужно поставить брэкпоинт всё на тот же 004FBEE6. В окне SoftIce’а вводим «bpx 004FBEE6» (BPX – Устанавливает/отменяет точку останова на выполнение). Выходим из отладчика (F5). Жмем «Зарегистрировать» и попадаем в отладчик на адрес 004FBEE6. Дальше следует зайти внутрь подпрограммы нажатием «F8» и мы в процедуре генерации.

Процедура генерации регистрационного кода.
Исследуя процедуру генерации в отладчике нам надо пошагово выполнять каждую команду ассемблера, для того чтобы следить какие изменения произошли в программе при выполнении той или иной команды. Этот процесс называется трассировкой программы. Трассировка – это пошаговое выполнение программы, с возможностью заходом внутрь процедуры.
В SoftIce: «F8» - трассировка с заходом внутрь процедуры или функции, «F10» - трассировка без захода внутрь процедуры или функции.
В OllyDebuger: «F7» - трассировка с заходом внутрь процедуры или функции, «F8» - трассировка без захода внутрь процедуры или функции.
Но перед самой процедурой приведу новые команды ассемблера которые встретятся в генерации.

Схема команды: mov приемник, источник

Назначение: пересылка данных между регистрами или регистрами и памятью.

Алгоритм работы:
копирование второго операнда в первый операнд.

Применение:
Команда mov применяется для различного рода пересылок данных, при этом, несмотря на всю простоту этого действия, необходимо помнить о некоторых ограничениях и особенностях выполнения данной операции:
• направление пересылки в команде mov всегда справа налево, то есть из второго операнда в первый;
• значение второго операнда не изменяется;
• оба операнда не могут быть из памяти (при необходимости можно использовать цепочечную команду movs);
Схема команды: movzx приемник, источник

Назначение: преобразование элементов без знака меньшей размерности в эквивалентные им элементы без знака большей размерности.

Алгоритм работы:
• считать содержимое источника;
• записать содержимое операнда источника в операнд приемник, начиная с его младших разрядов;
• распространить двоичный нуль на свободные старшие разряды операнда назначения.
Применение:
Команду movzx обычно используют для получения эквивалентного, но большего по размеру операнда без учета знака. Она может быть использована для согласования операндов различной размерности. Но не следует думать, что все эти разнотипные пересылки делает одна машинная команда. На самом деле существует несколько машинных команд, каждая из которых работает со своими размерами операндов. Генерацию же нужной команды обеспечивает транслятор на основе анализа исходного текста программы.
Схема команды: cmp операнд1,операнд2

Назначение: сравнение двух операндов.
Алгоритм работы:
• выполнить вычитание (операнд1-операнд2);
• в зависимости от результата установить флаги, операнд1 и операнд2 не изменять (то есть результат не запоминать).
Применение:
Данная команда используется для сравнения двух операндов методом вычитания, при этом операнды не изменяются. По результатам выполнения команды устанавливаются флаги. Команда cmp применяется с командами условного перехода и командой установки байта по значению setcc.
Схема команды: add приемник, источник

Назначение: сложение двух операндов источник и приемник размерностью байт (byte – 1 байт), слово (word – 2 байта) или двойное слово (dword – 4 байта).
Алгоритм работы:
• сложить операнды источник и приемник;
• записать результат сложения в приемник;
• установить флаги.
Применение:
Команда add используется для сложения двух целочисленных операндов. Результат сложения помещается по адресу первого операнда. Если результат сложения выходит за границы операнда приемник (возникает переполнение), то учесть эту ситуацию следует путем анализа флага cf и последующего возможного применения команды adc. Например, сложим значения в регистре ax и области памяти ch. При сложении следует учесть возможность переполнения.
Схема команды: inc операнд

Назначение: увеличение значения операнда в памяти или регистре на 1.
Алгоритм работы:
команда увеличивает операнд на единицу.
Применение:
Команда используется для увеличения значения байта (byte – 1 байт), слова (word – 2 байта), двойного слова (dword – 4 байта) в памяти или регистре на единицу. При этом команда не воздействует на флаг cf.
Схема команды: dec операнд

Назначение: уменьшение значения операнда в памяти или регистре на 1.

Алгоритм работы:
команда вычитает 1 из операнда.
Применение:
Команда dec используется для уменьшения значения байта (byte – 1 байт), слова (word – 2 байта), двойного слова (dword – 4 байта) в памяти или регистре на единицу. При этом заметьте то, что команда не воздействует на флаг cf.
Схема команды: lea приемник, источник

Назначение: получение эффективного адреса (смещения) источника.
Алгоритм работы:
алгоритм работы команды зависит от действующего режима адресации (use16 или use32):
• если use16, то в регистр приемник загружается 16-битное значение смещения операнда источник;
• если use32, то в регистр приемник загружается 32-битное значение смещения операнда источник.
Применение:
Данная команда является альтернативой оператору ассемблера offset. В отличие от offset команда lea допускает индексацию операнда, что позволяет более гибко организовать адресацию операндов.
Итак, в отладчике стоим на адресе 004FBEE6, дальше заходим внутрь и попадаем на начало процедуры генерации. Вообще то в любой процедуре генерации, много лишнего кода, поэтому я буду приводить только главное, то, что на прямую касается генерации регистрационного кода.
Дотрассируем программу до такого адреса:

00537596 894DF0 MOV DWORD PTR SS:[EBP-10],ECX <- грузим в адрес [EBP-10] количество введенных символов
00537599 8955F8 MOV DWORD PTR SS:[EBP-8],EDX <- грузим в адрес [EBP-8] введенный нами регистрационный код
0053759C 8945FC MOV DWORD PTR SS:[EBP-4],EAX <- грузим в адрес [EBP-4] введенное нами имя
- - - - вырезано - - - -
005375C3 8B45FC MOV EAX,DWORD PTR SS:[EBP-4] <- грузим в ЕАХ введенное имя
005375C6 E8 91D3ECFF CALL 0040495C <- тут в ЕАХ заносится количество символов введенного имени
005375CB 83F808 CMP EAX,8 <- количество символов введеного имени сравнивается с 8
005375CE 0F8CC9000000 JL 0053769D <- если количество меньше 8, то прыгаем на облом
005375D4 8B45F8 MOV EAX,DWORD PTR SS:[EBP-8] <- грузим в ЕАХ введений регистрационный код
005375D7 E880D3ECFF CALL 0040495C <- тут в ЕАХ заносится количество символов введеного регистрационного кода
005375DC 83F808 CMP EAX,8 <- проверка количества символов введенного кода с 8
005375DF 0F8CB8000000 JL 0053769D <- если количество меньше 8, то прыгаем на облом
005375E5 8B45FC MOV EAX,DWORD PTR SS:[EBP-4] <- грузим в ЕАХ введенное имя
005375E8 E86FD3ECFF CALL 0040495C <- тут в ЕАХ заноситься количество символов введенного имени
005375ED 8BF0 MOV ESI,EAX <- грузим в ESI количество символов введенного имени (дальше количество повтора цикла №1)
005375EF 85F6 TEST ESI,ESI
005375F1 7E13 JLE 00537606
- - - - цикл №1 - - - -
005375F3 BB01000000 MOV EBX,1 <- загрузить в EBX единицу
005375F8 8B45FC MOV EAX,DWORD PTR SS:[EBP-4] <- грузим в ЕАХ наше имя
005375FB 0FB64418FF MOVZX EAX,BYTE PTR DS:[EAX+EBX-1] <- грузим в ЕАХ первый символ введенного имени (в НЕХ коде), а дальше второй и третий символы, и т.д.
00537600 03F8 ADD EDI,EAX <- додаем к EDI код символа имени
00537602 43 INC EBX <- увеличиваем на единицу EBX
00537603 4E DEC ESI <- уменьшаем на единицу ESI
00537604 75F2 JNZ 005375F8 <- если в ESI не нуль, то пригаєм на повтор цикла
- - - - конец цикла №1 - - - -
- - - - цикл №2 - - - -
00537606 BB01000000 MOV EBX,1 <- загрузить в EBX единицу
0053760B B8E4765300 MOV EAX, 005376E4 <- грузим в ЕАХ адрес строки "Aria4Ever"
00537610 0FB64418FF MOVZX EAX,BYTE PTR DS:[EAX+EBX-1] <- грузим в ЕАХ первый символ строки "Aria4Ever" (в НЕХ коде), а дальше второй и третей символы, и т.д.
00537615 03F8 ADD EDI,EAX <- додаем до EDI код символа строки "Aria4Ever"
00537617 43 INC EBX <- увеличиваем на единицу EBX
00537618 83FB0A CMP EBX, Ah <- сравним ЕВХ с Ah (10), приставка «h» к числу означает шестнадцатеричное число
0053761B 75EE JNZ 0053760B <- если не десять, то пригаєм на повтор цикла
- - - - конец цикла №2 - - - -
- - - - вырезано - - - -
- - - - цикл №3 - - - -
0053762B BB01000000 MOV EBX,1 <- загрузить в EBX единицу
00537630 83FB01 CMP EBX,1 <- сравниваем ЕВХ с единицей
00537633 7415 JE 0053764A <- если единица то прыгаем
00537635 8B45FC MOV EAX,DWORD PTR SS:[EBP-4] <- грузим в ЕАХ введенное имя
00537638 0FB64418FF MOVZX EAX,BYTE PTR DS:[EAX+EBX-1] <- грузим в ЕАХ второй символ введенного имени (в НЕХ коде), а дальше четвертый символ, и т.д.
0053763D 8B55FC MOV EDX,DWORD PTR SS:[EBP-4] <- в EDX грузим введенное нами имя
00537640 0FB6541AFE MOVZX EDX,BYTE PTR DS:[EDX+EBX-2] <- грузим в EDX первый символ введенного имени (в НЕХ коде), а дальше третий символ, и т.д.
00537645 03C2 ADD EAX,EDX <- додаем эти два символа (в НЕХ коде), и сохраняем в ЕАХ
00537647 8945EC MOV DWORD PTR SS:[EBP-14],EAX <- загрузить в адрес [EBP-14], результат предыдущего сложения
0053764A 8B45FC MOV EAX,DWORD PTR SS:[EBP-4] <- грузим в ЕАХ введенное имя
0053764D E80AD3ECFF CALL 0040495C <- тут в ЕАХ заноситься количество символов введенного имени
00537652 3BD8 CMP EBX,EAX <- ЕВХ сравнивается с количеством символов введенного имени
00537654 7414 JE 0053766A <- если да то пригаєм
00537656 8B45FC MOV EAX,DWORD PTR SS:[EBP-4] <- в ЕАХ грузим введенное нами имя
00537659 0FB64418FF MOVZX EAX,BYTE PTR DS:[EAX+EBX-1] <- грузим в ЕАХ первый символ введенного имени (в НЕХ коде), а дальше третий символ, и т.д.
0053765E 8B55FC MOV EDX,DWORD PTR SS:[EBP-4] <- в EDX грузим введенное нами имя
00537661 0FB6141A MOVZX EDX,BYTE PTR DS:[EDX+EBX] <- грузим в EDX второй символ введенного имени (в НЕХ коде), а дальше четвертый символ, и т.д.
00537665 03C2 ADD EAX,EDX <- додаем эти два символы (в НЕХ коде), и сохраняем в ЕАХ
00537667 8945EC MOV DWORD PTR SS:[EBP-14],EAX <- загрузить в адрес [EBP-14], результат предыдущего сложения
0053766A 017DEC ADD DWORD PTR SS:[EBP-14],EDI <- додаем к сумме опкодов двух символов результат исполнения циклов №1 и №2
0053766D 8D4DE8 LEA ECX, DWORD PTR SS: [EBP-18]
00537670 BA03000000 MOV EDX, 3
00537675 8B45EC MOV EAX,DWORD PTR SS:[EBP-14] <- грузим в ЕАХ сумму 2-ох опкодов и результат исполнения циклов №1 и №2 (это и есть первые символы правильного рег. кода)
00537678 E84B30EDFF CALL 0040A6C8
0053767D 8B55E8 MOV EDX,DWORD PTR SS:[EBP-18] <- грузим в EDX первые символы правильного рег. кода
00537680 8D45F0 LEA EAX, DWORD PTR SS: [EBP-10]
00537683 E8DCD2ECFF CALL 00404964
00537688 43 INC EBX <- увеличиваем ЕВХ на единицу
00537689 4E DEC ESI <- уменьшаем ESI на единицу
0053768A 75A4 JNZ 00537630 <- если не нуль то пригаєм
- - - - конец цикла №3 - - - -
0053768C 8B45F8 MOV EAX,DWORD PTR SS:[EBP-8] <- кладем в ЕАХ введенный нами регистрационный код
0053768F 8B55F0 MOV EDX,DWORD PTR SS:[EBP-10] <- кладем в EDX сгенерированный регистрационный код
00537692 E8D5D3ECFF CALL 00404A6C <- сравниваем
- - - - вырезано - - - -

Подведем итог. Сначала узнается количество символов введенного имени и рег. кода. Потом количество этих символов поочередно сравнивается с восьмью. Если количество меньше, то прыгаем на сообщение о неверной регистрации, если же нет, то начинаем генерировать регистрационный код. Цикл №1 будет повторяться то количество раз, сколько в имени символов. Например, в моем нике, «Devil_guy», девять символов, значит, цикл №1 будет выполняться девять раз. А что собственно делает цикл №1? Он берет первый символ имени и кладет его в EDI. Потом второй символ и додает его в EDI, таким образом, цикл №1 вычисляет сумму опкодов всех символов имени в НЕХ коде и сохраняет результат в EDI. Затем в цикле №2 делается то же самое только со строкой «Aria4Ever», тоесть в конце двух циклов EDI будет содержать сумму опкодов имени и строки «Aria4Ever». Например, 3A8h (Devil_guy) + 343h (Aria4Ever) = 6EBh. Хочу напомнить, что символ «h» в конце числа не имеет значения, это приставка, обозначающая шестнадцатеричное число. Перейдем к циклу №3, который тоже повторяться то количество раз, сколько в имени символов. В нем генерируется окончательный регистрационный код.
В самом начале цикла EBX равен единице, поэтому прыгаем на 0053764A, но самое интересное начинается с адреса 00537659. Что же там делается? Сначала грузим в ЕАХ первый символ введенного имени (во втором повторе цикла третий и т.д.), чуть дальше по адресу 00537661, грузим в EDX второй символ введенного имени (во втором повторе цикла четвертый и т.д.), сумму добавляем в ЕАХ (см. 00537665). Эту же сумму загрузим в адрес [EBP-14]. Ну а дальше роковой момент дорогие друзья, по адресу 0053766A к [EBP-14] (результат сложения двух символов) добавляется EDI (результат циклов №1 и №2). В результате выполнения этой операции мы имеем первые символы правильного регистрационного кода которые, сохраняются в ЕАХ по адресу 00537675. Итак до тех пор пока цикл не дойдет до последнего повтора. Дело в том что, цикл, дойдя до последнего повтора должен загрузить в EAX последний символ имени, а загружать в EDX уже ничего нету. Поэтому он не будет доходить до адреса 00537659, а по адресу 00537638 в EAX он загрузит последний символ, а в EDX (00537640) предпоследний символ и перейдет на адрес 0053766A. Но результат цикла прибавляется к предыдущему как строка символов и получается рег. код.
Например, у меня регистрационный код получился таким: «7947C67CA7C07B67B17C77D97D9». Но чтобы лучше понять алгоритм приведу генерацию на своем примере.
Имя: D e v i l _ g u y
| | | | | | | | |
Hex значение: 44 65 76 69 6C 5F 67 75 79
Сумма Hex значений имени: 44 + 65 + 76 + 69 + 6C +5F + 67 + 75 + 79 = 3A8 (это делает цикл №1)
Сумма Hex значений имени и строки «Aria4Ever»: 3A8 + 343 = 6EB (это делает цикл №2) (сумма Hex значений строки «Aria4Ever» равна «343»)
Сумма двух первых символов имени и сумма значений имени и строки «Aria4Ever»: 44 + 65 = A9; 6EB + A9 = 794 (это делает цикл №3, заметьте, что результатом являются первые символы сгенерированного регистрационного кода).
Дальше: 65 + 76 = DB; 6EB + DB = 7C6 (это второй повтор цикла №3, заметьте, что результатом являются уже вторые символы сгенерированного регистрационного кода).
Предпоследний повтор цикла: 75 + 79 = EE; 6EB + EE = 7D9 (это предпоследние символы рег. кода)
Последний повтор цикла: 79 + 75 = EE; 6EB + EE = 7D9 (это последние символы рег. кода, заметьте, что два последних операнда просто поменялись местами).
Ну все, думаю вы поймете, если нет, то читайте статью и рассматривайте процедуру генерации в отладчике еще раз.

Шаг 5. Алгоритм реализованный в Delphi.

Алгоритм реализованный в Delphi будет немного отличатся. Сначала регистрационный код вычислится в десятичной системе счисления, а потом конвертируется в шестнадцатеричную как строка.
Запускаем Delphi. Создаем новый проект. Бросаем на форму два компонента TEdit (поле ввода) и компонент TButton (кнопка). При событии OnClick на кнопке, пишем такой код:

var //наши переменные
Len, i : integer; //длинна символов и счетчик циклов
Summa : integer; //сумма опкодов всех символов имени в десятичном виде
Ch1,Ch2 : integer; //индексы массивов
Opcode, Opcode2 : array [1..33] of integer; //опкоды символов
HexString : array [1..33] of string; //символы рег.кода
Pass : string; //окончательный регистрационный код
begin
Len := Length(Edit1.Text); //получим количество символов введённого имени
Summa := 0;
for i := 1 to Len do
begin
Opcode := Ord(Edit1.Text);
//присвоим первому индексу массива, код первого символа имени
Summa := Summa + Opcode;
//додаем каждый символ имени к переменной Summa
end;
Summa := Summa+835; // додаем к сумме символов число 835 (343h)
Ch1 := 1;
Ch2 := 2;
for i := 1 to Len do
begin
if i = Len then
//если последний цикл, то последний индекс массива становится предыдущим
begin
Ch1 := Ch1;
Ch2 := Ch2-2;
Opcode2 := Summa + Opcode[Ch1]+ Opcode[Ch2];
//к сумме символов прибавляем последний и предпоследний символы
HexString := IntToHex (Opcode2,0); //переводим это в НЕХ
Pass := Pass + HexString;
//прибавляем результат к общему рег. коду
Edit2.Text := Pass; //выводим окончательный регистрационный код на экран
end
else
Opcode2 := Summa + Opcode[Ch1]+ Opcode[Ch2];
//к сумме символов прибавляем 1-ый и 2-ой символы
HexString := IntToHex (Opcode2,0); //переводим это в НЕХ
Pass := Pass + HexString;
//прибавляем результат к общему рег. коду
Ch1 := Ch1+1;
Ch2 := Ch2+1;
//увеличиваем индексы массива на единицу
end;
end;

Вот и вся процедура генерации. При нажатии на кнопку, в поле Edit2 будет выведен регистрационный код, для введенного имени.
И еще очень желательно ввести такой код на событие FormActivate:
begin
Edit1.MaxLength := 33; //максимальная длинна имени 33 символа, это я для себя так решил
Edit1.SetFocus; //устанавливаем курсор в поле ввода 1
Edit2.Text := ’Длинна имени должна быть не меньше восьми символов!’; //уведомим пользователя об особенности генерации
end;

Вот и все. К сожалению, рабочий кейген сжатый UPX’ом, весил у меня аж 209Кб с картинкой на форме. Знаю что много, пробовал писать на WinAPI, но обломался на функции конвертации.

Заключение.
Я вообще не понимаю, зачем граждане программисты пишут такую хреновую защиту для такой программы. Уж элементарную защиту от отладчика, при помощи функции IsDebuggerPresent, могли сделать. Наверное, им бабок не надо. Ну а всем крэкерам желаю хороших мозгов и упорства.
P.S. для новичков: если что – то не получается, то не следует опускать руки, все придет с опытом и упорством. У меня, например, не все сразу получается, иногда со второго или третьего раза.

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


Обсуждение статьи: Взлом Sky Commander v1.5.1.270 и написание кейгена >>>


Комментарии к статье: Взлом Sky Commander v1.5.1.270 и написание кейгена

sewell 19.06.2006 17:07:45
Спасибо! Для новичка все разжевано и разложено по полочкам. Кое что новое для себя вынес полезное!
---

Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS