special
  •  #StandWithUkraine Ukraine flag |
  • ~492290+1210
     Enemy losses on 816th day of War in Ukraine

This webpage has been robot translated, sorry for typos if any. To view the original content of the page, simply replace the translation subdomain with www in the address bar or use this link.

Для новичков в крекинге, мишень HP-crackme




Мишень: HP-crackme (272кб)
Что еще нужно:
1. OllyDbg + плагины
2. ImpRec 1.6 Final
3. IDA
4. Ну и, естессно, некривые рики ;)

Для кого это написано?

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

Ручная распаковка


Так выглядит наш крекми

Запустим OllyDbg и загрузим в него наш крекми. Мы остановимся на EP и увидим такую картину:


Находим оригинальную точку входа

видим, что вызывается какая-то функция, которой передаются 3 аргумента. Далее выполняется прыжок на тоже пока не известный код. Замечаем, что по адресу 00482019 находится массив интересных строк. Судя по ним, наша программа запакована паковщиком PKLite и чтобы ее исследовать, модифицировать ее придется распаковывать. (пойдя путем наименьшего сопративления было решено воспользоваться плагином автораспаковки в PEID 0.92, но ему, почему-то, пакер пришелся "не по зубам"). Немного протрассировав код можно узнать, что по адресу 0040200F находится процедура распаковки упакованного "тела" программы. После завершения ее работы крекми в памяти будет находиться в полностью функционильном состоянии. Чтобы его отдампить нужно найти OEP. Самое интересное то, что сразу после процедуры распаковки и выполняется прыжок на эту самую OEP (JMP 00468A48). Жмем F8 и очутимся на ней. Теперь можно и дампить. Для этого можно использовать плагин к Оле OllyDump (Plugins-OllyDump-DumpDebuggedProcess-Dump). Появляется такое окно:


Дампим...



Восстановление импорта


Просто дампнутый крекми(я назвал файл dumped.exe) запускаться не будет(выдается ошибка нахождения точки входа одной из апи) - ему нужно восстановить таблицу импортированных функций. Для этого запустим крекми(hp.exe) и после него ImpRec. В нем вводим адрес нашей OEP и кликаем по "IAT AutoSearch"-"Get Imports"-"Fix Dump"


Imprec восстанавливает импорт...



итак, мы получили ПОЛНОСТЬЮ работоспособный распакованый крекми (dumped_.exe)! Приступим к его анализу...



Дизассемблирование и взлом нахождением верного ключа


Дизассемблируем дамп Идой и загружаем сигнатуру Delphi(поскольку прога написана именно в этой среде программирования). Даже при беглом просмотре кода в глаза сразу кидается огромное количество операций со строками (начиная с адреса 00466BC7). Смотрим немного выше:
loc_466B0C: ; CODE XREF: CODE:00466B11j
 push 0
 push 0
 dec ecx
 jnz short loc_466B0C
 push ecx
 push ebx
 push esi
 push edi
 mov [ebp-4], eax
 mov ebx, offset unk_46BC58
 mov esi, offset unk_46BC78
 xor eax, eax
 push ebp
 push offset loc_468100
 push dword ptr fs:[eax]
 mov fs:[eax], esp
 lea edx, [ebp-8]
 mov eax, [ebp-4]
 mov eax, [eax+308h]
 call @TControl@GetText$qqrv ; считываем имя юзера с Edit1
 cmp dword ptr [ebp-8], 0
 jnz short loc_466B58 ; прыгаем если ввели хоть что-то mov eax, offset _str________________.Text
 call @Dialogs@ShowMessage$qqrx17System@AnsiString ; Dialogs::ShowMessage(System::AnsiString)
 jmp loc_4680C0 ; jmp на выход

Далее (00466C43) идет код считывания имени, ключа, серийника и проверка ввели лы мы их:
 call @TControl@GetText$qqrv ; eax = length(name)
 mov edx, [ebp-0Ch]
 mov eax, offset dword_46BC64
 call @System@@LStrAsg$qqrv ; System::__linkproc__ LStrAsg(void)
 lea edx, [ebp-10h]
 mov eax, [ebp-4]
 mov eax, [eax+2F4h]
 call @TControl@GetText$qqrv ; eax = length(key)
 mov edx, [ebp-10h] ; edx = *key
 mov eax, offset unk_46BC5C
 call @System@@LStrAsg$qqrv ; System::__linkproc__ LStrAsg(void)
 lea edx, [ebp-14h]
 mov eax, [ebp-4]
 mov eax, [eax+2F0h]
 call @TControl@GetText$qqrv ; eax=length(serial)
 mov edx, [ebp-14h] ; edx= *serial
 mov eax, offset unk_46BC60
 call @System@@LStrAsg$qqrv ; System::__linkproc__ LStrAsg(void)
 mov eax, ds:dword_46BC64
 call @System@_16823 ; eax=length(name)
 mov edi, eax
 test edi, edi
 jle loc_46740E ; если не ввели имя, то выходим
 mov ds:dword_46BC7C, 1

Пропустив около 100 операций копирования и преобразования строк и столько же арифметических (автор, видимо, думал что такое их количество должно отпугнуть начинающих крекеров) видим уже более интересную картину: IDA - C:\статья\dumped_.idb (dumped_.exe)
 push eax
 lea edx, [ebp-6Ch]
 mov eax, [ebp-4]
 mov eax, [eax+2F4h]
 call @TControl@GetText$qqrv ; считываем ключ
 mov edx, [ebp-6Ch]
 pop eax ; eax = valid key!
 call @System@@LStrCmp$qqrv ; System::__linkproc__ LStrCmp(void)
 jnz loc_4680C0 ; прыгаем если не равны
 push ds:dword_46BD00
 push ds:dword_46BD04
 push ds:dword_46BD08
 push ds:dword_46BD0C
 push offset _str___22.Text
 push ds:dword_46BC98
 push ds:dword_46BC9C
 push ds:dword_46BCA0
 push ds:dword_46BCA4
 push ds:dword_46BCA8
 push offset _str___22.Text
 push ds:dword_46BCF4
 push ds:dword_46BCF8
 push ds:dword_46BCFC
 lea eax, [ebp-70h]
 mov edx, 0Eh
; --------------- S U B R O U T I N E ---------------------------------------
sub_468062 proc near
 call @System@@LStrCatN$qqrv ; подс4ет валидного регномера
 mov eax, [ebp-70h] ; сохраняем его в eax
 push eax
 lea edx, [ebp-74h]
 mov eax, [ebp-4]
 mov eax, [eax+2F0h]
 call @TControl@GetText$qqrv ; TControl::GetText(void)
 mov edx, [ebp-74h]
 pop eax
 call @System@@LStrCmp$qqrv ; финальное сравнение !
 jnz short loc_4680C0 ; прыгаем, если BadGuy
 mov edx, 190h
 mov eax, ds:dword_46BC50
 call @Forms@TCustomForm@SetClientWidth$qqri ; Forms::TCustomForm::SetClientWidth(int)
 mov eax, [ebp-4]
 mov eax, [eax+310h]
 mov dl, 1
 call @Controls@TControl@SetVisible$qqro ; Controls::TControl::SetVisible(bool)
 mov eax, [ebp-4]
 mov eax, [eax+314h]
 mov dl, 1
 call @Controls@TControl@SetVisible$qqro ; Controls::TControl::SetVisible(bool)
 mov ds:dword_46BCC4, 1
loc_4680C0: ; CODE XREF: CODE:00466B53j
 ; CODE:00468002j ...
 xor eax, eax ; выходим...
 pop edx
 pop ecx
 pop ecx
 mov fs:[eax], edx
 push offset loc_468107

Итак, грузим Олю и ставим бряки на 00467FFD и 00468080, где в eax'ах храняться наши верные регистрационные данные. Подсматриваем их и вводим в крякми. Мои валидные данные таковы:


Взлом jump-коррекцией

А для нежелающих долго ковыряться в отладчике могу предложить просто создать несложный *.crk файл и пропатчить кряк. Теперь он не будет проверять длинну вводимых имен и будет думать, что валидные данные вводятся всегда =)
00066B47: 75 EB
00068002: 0F 90
00068003: 85 90
00068004: B8 90
00068005: 00 90
00068006: 00 90
00068007: 00 90
00068085: 75 90
00068086: 39 90

Copyright © 2005 NGH Group


Дата створення/оновлення: 25.05.2018

Back