GenoCide Crackme 17 [Gandalf]

by

{Cronos}

Intro

Yet another Delphi proggie from GenoCide, I am beginning to enjoy them. Now this one is very, very interesting for several reasons. First of all it asks us to patch it to enable a button, and contains anti-patching type code, including checking its image and corrupted routines..... cool! :).

Target

The crackme is just a picture with a greyed button, and we just need to enable it. Now actually enabling the button is easy! It is sorting the program out and getting it to work without crashing afterwards that is going to entertain us!

Analysis

First of all we unpack the program, and I always call the unpacked version something else, leaving the original intact. This proves of value later on when we see that the program does in fact check the file size of its disk image 'gncrk17.exe' is still low, obviously to see if it has been unpacked. This doesnt come into play though with the methods I use. OK, the first thing we find in the file, using a hex editor to check out the resources, etc:
0000000754427574 746F6E0742757474 ....TButton.Butt
6F6E31044C656674 021003546F700328 on1.Left...Top.(
0105576964746802 4B06486569676874 ..Width.K.Height
0219074361707469 6F6E0609436C6F73 ...Caption..Clos
65206D652107456E 61626C6564080854 e me!.Enabled..T
61624F7264657202 00074F6E436C6963 abOrder...OnClic
6B070C427574746F 6E31436C69636B00 k..Button1Click.
A wealth of information about the button.... in fact it has the caption 'Close me!' when we run the crackme, and these are its starting details. We have its position - top, left, width, height, taborder, routine called for the event 'onclick' and of course that it is enabled. We need to remove this, and I just chose a one byte patch to extend the length of the caption(its length is the byte before it) to take in the bytes used by 'Enabled'+length before+value after. So I added 9 to the caption length. It makes the button look crap, but what the hell.....it is now enabled. Click it and crash! lovely.

We now need to look at the program a bit, and although Delphi programs can be very verbose they do leave some nice pieces behind for us to trace. Take a look at the following, from the code segment:
s_Panel1:
1000:0042b318 0650616e656c31       ds     "Panel1"
1000:0042b31f e0                   db     e0
1000:0042b320 01                   db     01
1000:0042b321 00                   db     00
1000:0042b322 00                   db     00
1000:0042b323 01                   db     01
1000:0042b324 00                   db     00
s_Image1:
1000:0042b325 06496d61676531       ds     "Image1"
1000:0042b32c e4                   db     e4
1000:0042b32d 01                   db     01
1000:0042b32e 00                   db     00
1000:0042b32f 00                   db     00
1000:0042b330 02                   db     02
1000:0042b331 00                   db     00
s_Button1:
1000:0042b332 07427574746f6e31     ds     "Button1"
1000:0042b33a 03                   db     03
1000:0042b33b 00                   db     00
1000:0042b33c 12                   db     12
1000:0042b33d 00                   db     00
1000:0042b33e f4b34200             dd     offset 42b3f4h
s_FormDestroy:
1000:0042b342 0b466f726d44657374.. ds     "FormDestroy"
1000:0042b34e 13                   db     13
1000:0042b34f 00                   db     00
1000:0042b350 48b44200             dd     offset 42b448h
s_Button1Click:
1000:0042b354 0c427574746f6e3143.. ds     "Button1Click"
1000:0042b361 11                   db     11
1000:0042b362 00                   db     00
1000:0042b363 58b44200             dd     offset 42b458h
s_FormCreate:
1000:0042b367 0a466f726d43726561.. ds     "FormCreate"
s_TForm1:
1000:0042b372 0654466f726d31       ds     "TForm1"
1000:0042b379 03                   db     03
1000:0042b37a 00                   db     00
1000:0042b37b b49e4200             dd     offset 429eb4h
1000:0042b37f f4984200             dd     offset 4298f4h
1000:0042b383 98904200             dd     offset 429098h
1000:0042b387 90                   db     90
1000:0042b388 8cb34200             dd     offset 42b38ch
;                                                 XREFS First: 1000:0042b388 Number : 1
1000:0042b38c 07                   db     07
s_TForm1:
1000:0042b38d 0654466f726d31       ds     "TForm1"
1000:0042b394 8cb24200             dd     offset 42b28ch
1000:0042b398 1c194200             dd     offset 42191ch
1000:0042b39c 3b                   db     3b      ;';'
1000:0042b39d 00                   db     00
s_main:
1000:0042b39e 046d61696e           ds     "main"
1000:0042b3a3 00                   db     00
1000:0042b3a4 00                   db     00
1000:0042b3a5 8d                   db     8d
1000:0042b3a6 40                   db     40      ;'@'
1000:0042b3a7 00                   db     00
;                                                 XREFS First: 1000:0042b448 Number : 2
Now this might look bad in some disassemblers which might try and treat it as code, and so you need to choose your tools accordingly. This tells us a lot. Best of all it gives us the three routines: FormCreate, Button1Click and FormDestroy for the main form, and the address of each of them (how nice). Lets take a look at each.
;*****************************************************************
; formcreate
;*****************************************************************
;                                                 XREFS First: 1000:0042b363 Number : 1
1000:0042b458 55                   push   ebp
1000:0042b459 8bec                 mov    ebp, esp
1000:0042b45b 81c4a8feffff         add    esp, fffffea8h
1000:0042b461 8d85a8feffff         lea    eax, [ebp-158h]
1000:0042b467 8b15b0584000         mov    edx, [4058b0h]
1000:0042b46d e88a87fdff           call   403bfch
1000:0042b472 33c0                 xor    eax, eax
1000:0042b474 55                   push   ebp
1000:0042b475 68d0b44200           push   offset 42b4d0h
1000:0042b47a 64ff30               push   dword ptr fs:[eax]
1000:0042b47d 648920               mov    fs:[eax], esp
1000:0042b480 8d8da8feffff         lea    ecx, [ebp-158h]
1000:0042b486 ba3f000000           mov    edx, 3fh
1000:0042b48b b8e4b44200           mov    eax, s_gencrk_exe
1000:0042b490 e85fb2fdff           call   4066f4h
1000:0042b495 8d85a8feffff         lea    eax, [ebp-158h]
1000:0042b49b e8a0b2fdff           call   406740h
1000:0042b4a0 81bdacfeffffe0220200 cmp    dword ptr [ebp-154h], 222e0h
1000:0042b4aa 7e05                 jle    42b4b1h
1000:0042b4ac e8f7feffff           call   42b3a8h
;                                                 XREFS First: 1000:0042b4aa Number : 1
1000:0042b4b1 33c0                 xor    eax, eax
1000:0042b4b3 5a                   pop    edx
1000:0042b4b4 59                   pop    ecx
1000:0042b4b5 59                   pop    ecx
1000:0042b4b6 648910               mov    fs:[eax], edx
1000:0042b4b9 68d7b44200           push   offset 42b4d7h
;                                                 XREFS First: 1000:0042b4d5 Number : 1
1000:0042b4be 8d85a8feffff         lea    eax, [ebp-158h]
1000:0042b4c4 8b15b0584000         mov    edx, [4058b0h]
1000:0042b4ca e8f587fdff           call   403cc4h
1000:0042b4cf c3                   ret    
;                                                 XREFS First: 1000:0042b475 Number : 1
1000:0042b4d0 e9ff7afdff           jmp    402fd4h
1000:0042b4d5 ebe7                 jmp    42b4beh
;                                                 XREFS First: 1000:0042b4b9 Number : 1
1000:0042b4d7 8be5                 mov    esp, ebp
1000:0042b4d9 5d                   pop    ebp
1000:0042b4da c3                   ret    
Notice the cmp 222e0h in this routine, it is the filelength trap that I mentioned earlier. But since it tests gencrk17.exe, and we havent changed that file, it doesnt matter.
;*****************************************************************
; formdestroy
;*****************************************************************
;                                                 XREFS First: 1000:0042b33e Number : 1
1000:0042b3f4 6a00                 push   00h
1000:0042b3f6 6808b44200           push   offset s_Just_a_reminder_
1000:0042b3fb 681cb44200           push   offset s_Enable_the_button___send_me_the_solu
1000:0042b400 6a00                 push   00h
1000:0042b402 e811a2fdff           call   _MessageBoxA
1000:0042b407 c3                   ret    
s_Just_a_reminder_:
;                                                 XREFS First: 1000:0042b3f6 Number : 1
1000:0042b408 4a7573742061207265.. ds     "Just a reminder."
1000:0042b419 00                   db     00
1000:0042b41a 00                   db     00
1000:0042b41b 00                   db     00
s_Enable_the_button___send_me_the_solu:
;                                                 XREFS First: 1000:0042b3fb Number : 1
1000:0042b41c 456e61626c65207468.. ds     "Enable the button & send me the solution ;)"
This is just the reminder and will always be shown, we could bypass it if we wanted to but I chose not to.
;*****************************************************************
; button1click
;*****************************************************************
;                                                 XREFS First: 1000:0042b350 Number : 1
1000:0042b448 e85bffffff           call   42b3a8h
1000:0042b44d a10cd74200           mov    eax, [42d70ch]
1000:0042b452 e80db0ffff           call   426464h
1000:0042b457 c3                   ret    
And this is the culprit of our problems. We note that it calls a routine in close proximity at the start, 42b3a8h, and this warrants further attention.
;*****************************************************************
; our interesting routine from button1click
;*****************************************************************
;                                                 XREFS First: 1000:0042b448 Number : 2
1000:0042b3a8 55                   push   ebp
1000:0042b3a9 8bec                 mov    ebp, esp
1000:0042b3ab 6a00                 push   00h
;                                                 XREFS First: 1000:0042b3c3 Number : 1
1000:0042b3ad 33c5                 xor    eax, ebp
1000:0042b3af 55                   push   ebp
1000:0042b3b0 68deb34500           push   45b3deh
1000:0042b3b5 26ff7007             push   dword ptr es:[eax+07h]
1000:0042b3b9 896006               mov    [eax+06h], esp
1000:0042b3bc 45                   inc    ebp
1000:0042b3bd fc                   cld    
1000:0042b3be baf0b34200           mov    edx, 42b3f0h
1000:0042b3c3 e8e5ffffff           call   42b3adh
1000:0042b3c8 33c0                 xor    eax, eax
1000:0042b3ca 5a                   pop    edx
1000:0042b3cb 59                   pop    ecx
1000:0042b3cc 59                   pop    ecx
1000:0042b3cd 648910               mov    fs:[eax], edx
1000:0042b3d0 68e5b34200           push   42b3e5h
;                                                 XREFS First: 1000:0042b3e3 Number : 1
1000:0042b3d5 8d45fc               lea    eax, [ebp-04h]
1000:0042b3d8 e85381fdff           call   403530h
1000:0042b3dd c3                   ret    
1000:0042b3de e9f17bfdff           jmp    402fd4h
1000:0042b3e3 ebf0                 jmp    42b3d5h
1000:0042b3e5 59                   pop    ecx
1000:0042b3e6 5d                   pop    ebp
1000:0042b3e7 c3                   ret    
This is it, the culprit. It's pretty obviously fake, just take a look at the push dword ptr es:[ax+07h] !, and of course the recursive call leading to a quick crash. hmmmmmm. I decided on a one byte patch for this in the end. The byte ? Oh, yeah... the address of the button1click routine, i added 5 to it to bypass the call to this routine (so 48h becomes 4dh). The end result ? Job done :)

Conclusions

This crackme was quite interesting although most people would probably find it quite hard, although the hardest part for most people will probably be understanding how Delphi compiles programs. Once you have grasped that the rest is easy ;)

{Cronos}