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

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


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

Попробуем OfflineExplorer 3.0 Enterprise Edition

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

Хорошая подборка видеоуроков, инструментов крэкера, книг и статей - здесь.

Автор: Ra$cal <Rascalspb@yandex.ru>

Статья приводится не в первоначальном виде, а с некоторми изменениями и дополнениями, сделанными под натиском Bad_Guy’a =)

Инструменты:
OllyDebug
ImpRec
PEEditor
DeDe
Qview
WinDasm или IDA

Приветствую всех, кто интересуется Reverse Engineering’ом. Сегодня мы будем изучать суперский качок сайтов OffLineExplorer v3.0 Enterprise Edition(стоит эта штука 400$). Пользюсь я этой прогой с v2.3 (если память не изменяет),и пока нареканий у меня она не вызывала. Увидев цену, у меня закралась мысль, что за такую цену защита должна быть на высшем уровне. Как я заблуждался. Защиту будем обходить 3 способами. Но для начала внимательно изучим экзешник:

Размер - 1342468 байт
Программа запакована AsPack’ом 2.11b (В этом нас убедил PeSnifer)
Компилятор - Delphi
Работает без ограничений функциональности, но только 30 дней.

Начнём.
Что ж, будем распаковывать, причём ручками.
UPX и более ранние версии AsPack я распаковывал в olly, находя POPAD и смотря ниже либо JMP ......(если паковщик - UPX), либо JNZ ; RET ; MOV ; PUSH ; RET (если паковщик - AsPack). Для тех, кто не знает: при запуске запакованной программы сначала работает распаковщик, потом, сделав своё дело и распаковав программу в память, он передаёт ей управление. Причём перед передачей управления распакованной программе паковщик(распаковщик) должен вернуть значения регистров, которые были перед запуском программы, иначе могут быть ошибки. Наша задача - дождаться момента передачи управления, зациклить программу, сделать дамп и найти OEP. Этот AsPack место передачи управления тоже пакует, поэтому в дизасме мы не увидим привычного набора команд. Его можно засечь только вручную протрейсив распаковку. Этим мы сейчас и займёмся...
Запускаем olly и открываем в нём OE.EXE. Мы оказываемся тут:

0080C001 > 60 PUSHAD Сохраняем регистры, чтобы потом их восстановить
0080C002 E8 02000000 CALL 1OE.0080C009
0080C007 EB 09 JMP SHORT 1OE.0080C012
0080C009 5D POP EBP
0080C00A 55 PUSH EBP
0080C00B 81ED 39394400 SUB EBP,1OE.00443939
0080C011 C3 RETN
0080C012 E9 3D040000 JMP 1OE.0080C454
0080C017 -E9 25050101 JMP 0181C541

Трейсим всё через F8... Неожиданно программа запустилась. Значит мы пропустили переход на OEP. Теперь внимательно следим за каждым шагом и обнаруживаем, что OE грузится после Call’a по адресу 0080C47A. Значит всё заканчивается в нём. Значит туда нам и дорога. Становимся на этот адрес и жмём F7, а дальше трейсим через F8. Циклы очень рекомендую обходить - ставя после комнды прыга бряк и нажимая F9.

0080C454 E9 1C000000 JMP 1OE.0080C475
0080C459 ^E1 A4 LOOPDE SHORT 1OE.0080C3FF
0080C45B 5B POP EBX
0080C45C F9 STC
0080C45D 332A XOR EBP,DWORD PTR DS:[EDX]
0080C45F 7B 8C JPO SHORT 1OE.0080C3ED
0080C461 D9B5 CB803F6B FSTENV (28-BYTE) PTR SS:[EBP+6B3F80CB]
0080C467 1D 48313A0F SBB EAX,0F3A3148
0080C46C B2 A3 MOV DL,0A3
0080C46E ^77 EB JA SHORT 1OE.0080C45B
0080C470 E4 29 IN AL,29 ; I/O command
0080C472 4E DEC ESI
0080C473 64:9D POPFD ; Superfluous prefix
0080C475 BE A9D276AA MOV ESI,AA76D2A9
0080C47A E8 14000000 CALL 1OE.0080C493 Внутри этого вызова происходит переход на OEP, так что стоя тут давим на F7

Трассировать придётся прилично, главное не пропустить POPAD
...
Ну вот мы и вылезли к POPAD. Ещё пару раз нажмите F8 и остановитесь на RETN

0080C3BA 61 POPAD Восстанавливаем регистры
0080C3BB 75 08 JNZ SHORT 1OE.0080C3C5 Это обычный набор команд перед распаковкой для AsPack
0080C3BD B8 01000000 MOV EAX,1
0080C3C2 C2 0C00 RETN 0C
0080C3C5 68 18596F00 PUSH 1OE.006F5918 Это и есть OEP распаковываемой проги
0080C3CA C3 RETN А это сам переход на OEP. Здесь мы и остановимся


Почему мы трейсим в ручную, а не используем "bpm esp-4" - К сожалению
в olly нет команды "bpm esp-4", поэтому я хотел показать,
как распаковывать UPX или AsPack при помощи трейсинга. Правда,
в olly есть команда TC, но чё-то она криво работает.


Теперь запускаем PEEditor, жмём Tasks, давим правую кноку мыши на OE.EXE и выбираем Dump(Full). Сохраняем. Теперь будем восстанавливать дамп. Сначала OEP:
Идём в olly, смотрим, что "пушится" перед ретом. Видим 1OE.006F5918. Из этого числа вычитаем значение, указанное в PEEditor’е в поле Image Base. Получим 2F5918. Это число пишем в поле entry point. Apply changes. Затем cheksum, correct it. Всё, PEEditor закрываем (olly тоже(пока))
Осталось восстановить таблицу импорта:
1) Запускаем запакованный OfflineExplorer
2) Следом ImpRec
3) В процессах выбираем OE.exe
4) OEP пишем тот, который написали в PEEditor
5) IAT Autosearch
6) GetImports
7) Удаляем пункты, в которых написано valid:NO (их будет 2)
8) FixDump (выбираем наш дамп)
9) Всё!!! Распаковка закончена.

Реконструкция импорта после ASPack вроде бы не нужна (если
дамп с подправленным EP запускается)? - вроде бы не нужна, но у меня без восстановления импорта не пашет ни AsPack, ни UPX (может быть причина этого - WinXP Corporate Edition), а если и заработает, то токо на своей машине, то есть другу тащить прогу без восстановленной таблицы импорта бессмысленно. Кстати, снял с UPX
дамп олей так, что она(оля)(он(отладчик) восстановил(а) таблицу импорта
без всяких ImpRec, но на AsPack этот метод не сработал.


Обходим защиту (Все 3 способа-патч).

Почему все 3 способа взлома - патчинье?
Даже в сети на Асте самое "продвинутое" средство - лодырь(правда давно
это было).

Пытаюсь объяснить, почему не стоит искать пароль:

Обычно в программах есть несколько полей:имя, пароль, mail.
Пароль генерируется из имени, и мы можем его подсмотреть в памяти,
потом написать в поле Password и увидеть радостные буквы "Registered".
Тут в номере зашифрованы данные о пользователе и пароль. По какому-то
алгоритму он расшифровывается и получаются имя, мыло и пароль. НОМЕР для
своего имени можно получить ТОЛЬКО разобрав алгоритм и сделав keygen.
Я посмотрел, что творится внутри, но, кроме 18-ти значных чисел,
ничего интересного не увидел. Усерднее колупаться не охота, т.к.
функциональных ограничений нет, а номерок искать в одиночку -
мазахизм(трудозатраты на поиск номера(читай: создание keygen’a)
несоизмеримо больше, чем на патч).
Валидность номера предположительно проверяется так:
из НОМЕРА расшифровывается имя, мыло и ПАРОЛЬ, из имени и мыла по
другому алгоритму получается ПАРОЛЬ и сравнивается с тем, который
расшифровался из номера. Таким образом, даже если мы увидим истинный
ПАРОЛЬ, не зная алгоритма шифровки мы не сможем записать его В НОМЕР
(то есть зашифровать обратно, чтобы ОЕ его расшифровал и проверил).
А если авторы программы не поленились и потратили достаточно времени
для разработки своего сложного алгоритма (или на худой конец стырили
или купили чужой, но сложный), то колупаться можно О-О-ОЧЕНЬ долго.
Ещё раз повторю, что функциональных ограничений, снимаемых вводом пароля, нет,
поэтому не стоит заморачиваться, хотя я ни кого не отгавариваю - сделаете
keygen - кукарекните, а то любопытно, угадал я алгоритм защиты или нет.
Вот это я намудрил. Надеюсь, ты понял, что я имел ввиду, а то я после
прочтения запутался %)


Способ 1(не очень действенный, но способ)

Запускаем распакованный OE, жмём about и пробуем регистрироваться. Видим сообщение "Sorry..."
Отлично. Пихаем дамп в WinDasm и ищем строку "Sorry..."
(листинг из IDA)
00663881 mov edx, 7
00663886 call loc_404608
0066388B mov eax, [ebp-30h]
0066388E call loc_40470C
00663893 push eax
00663894 lea eax, [ebp-44h]
00663897 mov ecx, [ebp-0Ch]
"Sorry, registration information is invalid"...

Смотрим выше
*Referenced by a (U)nconditional or (C)onditional Jump at Adress:
|:006637DA(C)

Переходим по этому адресу и видим ...
|:006637DA jnz 006637E6

Меняем в Qview jnz на jz, жмём About, регистрируем и... нас поздравляют. Это конечно хорошо, но только до следующего запуска :(

Значит будем искать дальше.

Способ 2 (действенный, но длинный)

Теперь нам пригодится DeDe. Этот инструмент значительно упрощает работу с Delphi-программами.Подробнее описывать не буду - если захотите, сами найдёте достаточно статей. Так вот. Пихаем туда распакованный ОЕ и переводим время вперёд на 2 месяца. Теперь думамем. Окно с сообщением о просроченом сроке возникает при загрузке главного окна. Это может происходить при событии main.Initialization или Form.Show или Form.Create. Ещё мы видим, что в заголовке окна присутствует надпись [Not Registered]. И эта надпись должна появится рядом с окном, т.к. сначала должны проверять, зарегестрированы ли мы, потом время, потом нам покажут окно. Вот теперь и ищем эту надпись в каждой процедуре... Находим мы её в Form.Create... Вот листинг.
Но немного выше мы видим прыг, который проскакивает этот кусок. Очевидно, что поменяв его на JMP, мы больше не увидим этой надписи. Проверяем и убеждаемся в этом, но окно по прежнему появляется. Думаем дальше.

006CC658 80B89408000000 cmp byte ptr [eax+$0894], $00
006CC65F 7527 jnz 006CC688 -а вот прыг через строку Not Registered

* Reference to MainForm
|
006CC661 8B45FC mov eax, [ebp-$04]

* Reference to field TMainForm.OFFS_098C
|
006CC664 8B908C090000 mov edx, [eax+$098C]
006CC66A 8D85A4FEFFFF lea eax, [ebp+$FFFFFEA4]

* Possible String Reference to: ’ - [ Not Registered ]’ -вот строка, которая нас интересует
|
006CC670 B9C0E76C00 mov ecx, $006CE7C0



Окно может появляться и до надписи Not Registered, и после. Смотрим по листингу вниз. Т.к. надпись мы убрали, а окно появляется, то логично предположить, что перед появлением окна должен быть прыг (иначе как регеные пользователи, да и мы до окончания 30 дней, этого окна не видим). Далеко внизу мы видим следующее:

* Reference to: menus.TMenuItem.SetVisible(TMenuItem;Boolean);
|
006CC72D E866EFD7FF call 0044B698

* Reference to pointer to GlobalVar_007154F0
|
006CC732 A1302C7100 mov eax, dword ptr [$00712C30]

* Reference to field GlobalVar_007154F0.OFFS_00E9
|
006CC737 80B8E900000000 cmp byte ptr [eax+$00E9], $00
006CC73E 7408 jz 006CC748 -прыг, да не тот прыг

* Reference to MainForm
|
006CC740 8B45FC mov eax, [ebp-$04]

* Reference to: Main.Proc_006D8390
|
006CC743 E848BC0000 call 006D8390
Это явно связано с главной формой (меню в окне о регистрации нет). Значит это не то. Нужное место мы проскакали. Тогда смотрим выше:

* Reference to: Unit_0045B9CC.Proc_0045C444
|
006CC5D8 E867FED8FF call 0045C444
006CC5DD 84C0 test al, al
006CC5DF 7427 jz 006CC608 -то, что нужно
006CC5E1 8D95ACFEFFFF lea edx, [ebp+$FFFFFEAC]
006CC5E7 8B45F4 mov eax, [ebp-$0C]

* Reference to: Unit_0049105C.Proc_00493BDC

Это уже интереснее, т.к. сверху подозрительные наборы символов, напоминающие правильные рег. номера для более ранних версий ОЕ (в Serials dbltk), а под ними условный переход. Пробуем поменять JZ на JMP. Всё заработало!!! Тут нам повезло, что проверка не делается в каком-нибудь из Call’ов, иначе бы мы задолбались выискивать один прыг среди сотен подобных.

Способ 3

Жестокий способ :) Мы понимаем, что прога работает 30 дней :) Была замечательная тулза под названием вперёд в прошлое. Она переводила время, запускала программу, а потом восстанавливала время. Считается, что программа проверит время при загрузке и больше следить за часами не будет. ОЕ же проверяет время каждую секунду, поэтому такой способ тут не прокатит. Но если она смотрит время, значит она куда пишет дату последнего запуска. Я задумал сделать так, чтобы там всегда была та дата, которая нас устраивает. Но найти это место мне не удалось. Тогда я подумал - а что, если программа будет всегда возвращать одну и ту же дату. Системное время она получает АПИ функцией GetLocalTime. Значит запускаем olly, открываем там ОЕ, ставим бряк на GetLocalTime. Их нашлось 4 штуки. Это хорошо, т.к. можно предположить, что за триал отвечает только одна ф-ия, а остальные будут работать нормально и отображать время начала загрузки, окончания и другое время истинным, а не тем, которое мы зашьём в прогу. Ну ладно, мы отвлеклись. Запускаем и смотрим, какой бряк срабатывает каждую секунду... Угу, это третий. Остальные убираем, а остановившись на нужном смотрим, что он возвращает в CX, DX, AX. Итак:
CX - число
DX - месяц
AX - год
Есстественно всё в HEX. Теперь двойным щелчком в olly по строке и правим WORD PTR SS:[ESP+E] на нужное нам

0040C921 66:8B4C24 0E MOV CX,WORD PTR SS:[ESP+E]

Вспоминаем, в каком месяце, какого числа и года программа работала без проблем, и пишем (у меня 21 мая 2004)

0040C91C E8 F3BFFFFF CALL <JMP.&KERNEL32.GetLocalTime>

0040C921 66:B9 1500 MOV CX,15
0040C925 90 NOP
0040C926 66:BA 0500 MOV DX,5
0040C92A 90 NOP
0040C92B 66:B8 D407 MOV AX,7D4
0040C92F 90 NOP

Фактически мы запарываем АПИ, то есть и АПИ эту можно в принципе заNOPить, ну да бог с ней, пускай будет.

Теперь правая кнопка мыши на коде, Copy to Executable (4 пункт снизу), AllModifications, SaveFile. Всё, программа работает и без ограничений!!!

Спасибо за интерес к этой статье.

PS: В About осталась надпись, что мы Unregistered, да и в заголовке присутствует Not Registered, но тут всё просто - открываем в Qview, ищем строки с таким содержанием и меняем их на своё усмотрение.

PPS: написал статейку и заглянул на CrackLab. Оказывается, там уже есть 2 статьи по поводу ОЕ, правда версий 2.**. Оказалось, что защита осталась такой же, как и была. Очень странно - стоит 400$, функциональность улучшается, а про защиту как-будто забыли?!

PPPS: как вы уже знаете, эта статья только для обучения тому, как не стоит защищать свои программы.

Обсуждение статьи: Попробуем OfflineExplorer 3.0 Enterprise Edition >>>


Комментарии к статье: Попробуем OfflineExplorer 3.0 Enterprise Edition

Shar 15.06.2004 19:55:36
Раньше с предыдущей версией 2.8 я просто делал активным заднее окно(появляется после окончания месяца) и, вроде, всё работало, не красиво, но зато быстро.
---

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



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


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