For newcomers to cracking, HP-crackme target




The target: the HP-crackme (272kb)
What else is needed:
1. OllyDbg + plugins
2. ImpRec 1.6 Final
3. IDA
4. Well, estessno nekrivye Rica;)

For whom is it written?

Shoyu article I wrote, especially for newcomers to the cracking, which (as I hear) are often not everything is clear in a few one-sided modern approach to the issue of cracking. Indeed, over time disappear in front of splints, which can not be described, only one of the approaches reversing (only decompression, restoration of import, edit code in program memory, finding the correct serial number, or Patching a program), and they used the complex. Premonition that the "aces" cracking c grin read the last line, and I will repeat that, for example, decompression - is already more than half of the work performed. But in spite of this, I decided to write a splint, "A to Z" - from manual extraction "victim" of hacking before patching the file and finding the correct login information. I think many beginners will be useful for "touching" the various options krekmi hacking.

Manual decompression


It looks like our krekmi

Run OllyDbg and download it to our krekmi. We will focus on the EP and see the following picture:


We find the original entry point

We see what is called a feature, which passed 3 arguments. Next, you jump on the same code is not known. We note that at 00482019 An array of interesting lines. According to him, our program is packed with a runtime packer PKLite and to explore it, modify it will have to unpack. (Go the path of least soprativleniya it was decided to use the plug-in avtoraspakovki PEiD 0.92, but he, for some reason, Packer went "too tough"). Few at tracing the code you can see that at 0040200F is the procedure of extracting compressed "body" of the program. After completion of its work krekmi in memory will be in a position to fully funktsionilnom. To his otdampit to find OEP. The most interesting thing is that immediately after unpacking procedures and performed a jump on this very OEP (JMP 00468A48). Hit F8 and find ourselves on it. Now you can and dump. You can use the plugin to Ole OllyDump (Plugins-OllyDump-DumpDebuggedProcess-Dump). There is such window:


Dump ...



Recovery of import


Just dampnuty krekmi (I called dumped.exe file) will not start (error finding issued entry point of one of the api) - he needs to restore the table of imported functions. To do this, run the krekmi (hp.exe) and after ImpRec. In it, enter the address of our OEP and click on the "IAT AutoSearch" - "Get Imports" - "Fix Dump"


Imprec restores import ...



So, we have a fully functional raspakovanom krekmi (dumped_.exe)! Proceed to its analysis ...



Disassembling and breaking finding the correct key


Disassemble Ida dump and load Delphi signature (because the program is written in the programming environment). Even a cursory viewing of code into the eyes immediately throws a huge number of string operations (since 00466BC7 address). Look a little higher:
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 на выход 
Next (00466C43) is the name of the read code key, and test seriynika formula we introduced them:
 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
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 
Skipping around 100 operations copying and converting lines and the same number of arithmetic (the author seems to think that such a number should scare off novice crackers) see more than an interesting picture: IDA - C: \ article \ 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 ; --------------- SUBROUTINE --------------------------------------- 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 qqri; 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 ; --------------- SUBROUTINE --------------------------------------- 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 qqro; 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 ; --------------- SUBROUTINE --------------------------------------- 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 qqro; 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 ; --------------- SUBROUTINE --------------------------------------- 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
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 ; --------------- SUBROUTINE --------------------------------------- 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 
So Olga ship and set breakpoints on 00467FFD and 00,468,080, which are stored in eax'ah our loyal registration data. To spy them and enter into crackme. My data codes are as follows:


Hacking jump-correction

And for a long time not wishing to be picked in the debugger can offer just create a simple * .crk file and patch the crack. Now he will not check the length of the input names and will think that valid data are entered always =)
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