Tools needed:
IDA or W32DASM (I use IDA)
|
Disassemble the crackme with IDA or W32DASM (I use IDA) and go to the string references. Look through the strings, the following one looks interesting to us:
"Now write a keygen and tut and you're done."
Go to that section of the code and you see this:
0040135F
loc_40135F:
; CODE XREF: .text:00401331j
0040135F 6A 00 push 0 00401361 68 0F 30 40 00 push offset aCruddSCrackHea ; "Crudd's Crack Head" 00401366 68 33 13 40 00 push offset aNowWriteAKeyge ; "Now write a keygen and tut 0040136B FF 75 08 push dword ptr [ebp+8] 0040136E E8 19 01 00 00 call j_MessageBoxA 00401373 00401373 loc_401373: ; CODE XREF: .text:00401306j |
Let's take a look at the cross reference at 401331:
00401316 6A 28
push 28h
00401318 68 C4 33 40 00 push offset unk_4033C4 0040131D FF 35 90 31 40 00 push dword_403190 00401323 E8 4C 01 00 00 call j_GetWindowTextA 00401328 E8 A5 00 00 00 call sub_4013D2 0040132D 3B C6 cmp eax, esi 0040132F 75 42 jnz short loc_401373 00401331 EB 2C jmp short loc_40135F |
Well, the easiest thing to do would be to NOP the JNZ, but that's
not the goal of the crackme, so we'll take a look at sub_4013D2.
We know that the serial that the user enters is in 4033C4h (because
we know our windows API functions well, right? ;) so here's the
code in sub_4013D2:
004013D2
sub_4013D2 proc near
; CODE XREF: .text:00401328
004013D2 56 push esi 004013D3 33 C0 xor eax, eax 004013D5 8D 35 C4 33 40 00 lea esi, ds:4033C4h 004013DB 33 C9 xor ecx, ecx 004013DD 33 D2 xor edx, edx 004013DF 8A 06 mov al, [esi] 004013E1 46 inc esi 004013E2 3C 2D cmp al, 2Dh 004013E4 75 08 jnz short loc_4013EE 004013E6 BA FF FF FF FF mov edx, 0FFFFFFFFh 004013EB 8A 06 mov al, [esi] 004013ED 46 inc esi 004013EE 004013EE loc_4013EE: ; CODE XREF: sub_4013D2+12j 004013EE EB 0B jmp short loc_4013FB 004013F0 ; ------------------------------------------------------------------ 004013F0 004013F0 loc_4013F0: ; CODE XREF: sub_4013D2+2Bj 004013F0 2C 30 sub al, 30h 004013F2 8D 0C 89 lea ecx, [ecx+ecx*4] 004013F5 8D 0C 48 lea ecx, [eax+ecx*2] 004013F8 8A 06 mov al, [esi] 004013FA 46 inc esi 004013FB 004013FB loc_4013FB: ; CODE XREF: sub_4013D2+1Cj 004013FB 0A C0 or al, al 004013FD 75 F1 jnz short loc_4013F0 004013FF 8D 04 0A lea eax, [edx+ecx] 00401402 33 C2 xor eax, edx 00401404 5E pop esi 00401405 81 F6 53 75 7A 79 xor esi, 797A7553h 0040140B C3 retn 0040140B sub_4013D2 endp |
Well, it moves the address of the user's serial into ESI and then compares byte by byte to 2Dh or '-'. If it finds one then it jumps to 4013EE which skips moving a new byte of the user serial into AL and the moving of a value into EDX. No matter what it jumps to 4013FB. At 4013FB we see some code that checks if AL is zero. If not, it jumps to 4013F0 which does some multiplication. If so, it adds EDX and ECX into EAX, XORs eax with EDX, and then XORs ESI with that weird number. Then it returns. But what's in ESI after the POP?
Time to look back a bit. Return from the procedure and just before
the GetWindowTextA call, we see this:
.text:00401310 8B 35 9C 33 40 00 mov esi, dword_40339C |
What's in 40339C? Well, go to it and check the cross references...
r .text:00401310
mov esi, dword_40339C
o .text:00401425 push offset dword_40339C w .text:0040144E mov dword_40339C, edi |
Number three seems to be the one we're interested in because that is
where it is being written to. Go to the location and you land in
a procedure. Here is the procedure:
0040140C
sub_40140C proc near
; CODE XREF: start+11p
0040140C 60 pusha 0040140D 6A 00 push 0 0040140F E8 B4 00 00 00 call j_GetDriveTypeA 00401414 A2 EC 33 40 00 mov byte_4033EC, al |
Lets take a look at the API for GetDriveTypeA:
The GetDriveType function determines whether
a disk drive is a removable,
fixed, CD-ROM, RAM disk, or network drive. UINT GetDriveType( LPCTSTR lpRootPathName
// address of root path
lpRootPathName Points to a null-terminated string that specifies
the root directory of the
|
Well, it gets the drive that the crackme is on and then moves the type
into 4033EC. Then it does some stuff with GetVolumeInformationA.
00401419 6A 00
push 0
0040141B 6A 00 push 0 0040141D 6A 00 push 0 0040141F 6A 00 push 0 00401421 6A 00 push 0 00401423 6A 0B push 0Bh 00401425 68 9C 33 40 00 push offset dword_40339C 0040142A 6A 00 push 0 0040142C E8 A3 00 00 00 call j_GetVolumeInformationA |
BOOL GetVolumeInformation(
LPCTSTR lpRootPathName,
// address of root directory of the file system
|
Well, it seems that he only wants the first 11 characters of the name
into 40339C.
00401431 8D 35 9C 33 40 00
lea esi, ds:40339Ch
00401437 0F B6 0D EC 33 40 00 movzx ecx, byte_4033EC 0040143E 33 FF xor edi, edi 00401440 00401440 loc_401440: ; CODE XREF: sub_40140C+40j 00401440 8B C1 mov eax, ecx 00401442 8B 1E mov ebx, [esi] 00401444 F7 E3 mul ebx 00401446 03 F8 add edi, eax 00401448 49 dec ecx 00401449 83 F9 00 cmp ecx, 0 0040144C 75 F2 jnz short loc_401440 0040144E 89 3D 9C 33 40 00 mov dword_40339C, edi 00401454 61 popa 00401455 C3 retn 00401455 sub_40140C endp |
Next, it starts manipluating the data of the volume name with the type
of drive doing multiplications, additions, and uses the number retrieved
with GetDriveTypeA as the counter. Well, now that we've got the code,
we can make a keygen. Remember that we have to XOR the result with
797A7553h because of the check.
.386
.model flat,stdcall option casemap:none include \masm32\include\windows.inc
includelib \masm32\lib\kernel32.lib
.data decspec db "%lu",0
.data? drivename db 0Ch dup(?)
.code
end main |
There you have it. The keygen. Easy enough, right? Well, this was an interesting crackme (I like HD serial stuff, very interesting :) but I'd only rate it about 2/10 for difficulty. The complete newbie couldn't do it beacause the generation spawns in two different locations (kind of) but it was very easy. Hope you enjoyed it! :)
If you have any questions mail me at muaddib(at)immortaldescendants(dot)org. Please do NOT send me crack requests or try to recruit me for any group. I will NOT fulfill the requests and the E-Mail will be forwarded to the company who made the program you requested a crack for.