The deadlisting of crackme 7 is very simular with the one from crackme5.1.
So again let's start with the DialogMessageLoop :
00401189 enter 0, 0 0040118D push ebx 0040118E push edi 0040118F push esi 00401190 cmp [ebp+arg_4], 111h ; WM_COMMAND 00401197 jz short loc_4011BB 00401199 cmp [ebp+arg_4], 2 ; WM_DESTROY 0040119D jz loc_40125C 004011A3 push [ebp+arg_C] 004011A6 push [ebp+arg_8] 004011A9 push [ebp+arg_4] 004011AC push [ebp+arg_0] 004011AF call j_DefWindowProcA ; Pass on Message to next thread 004011B4 pop esi 004011B5 pop edi 004011B6 pop ebx 004011B7 leave 004011B8 retn 10h 004011BB ; --------------------------------------------------------------------------- 004011BB 004011BB loc_4011BB: ; CODE XREF: sub_401189+Ej 004011BB cmp [ebp+arg_8], 20h ; Button pressed ? 004011BF jnz loc_401253 004011C5 push ds:EditHandle 004011CB call j_GetWindowTextLengthA ; Get Serial Length 004011D0 cmp eax, 0 ; If not zero 004011D3 jnz short loc_401235 ; jump badguy 004011D5 xor eax, eax ; zero out 004011D7 push 28h ; Max length 004011D9 push offset unk_40209C ; pointer 2 Serial Buffer 004011DE push ds:HiddenEditHandle 004011E4 call j_GetWindowTextA ; Get Serial 004011E9 push ds:hInstance 004011EF call sub_40126F ; Make and Check Hash 004011F4 cmp eax, 1 ; Check return flag 004011F7 jnz short loc_401217 004011F9 push 30h 004011FB push offset aBeaten ; "*BEATEN*" 00401200 push offset aMumble ; "*mumble*" 00401205 push ds:hWndDialogBox 0040120B call j_MessageBoxA ; Goodguy Message 00401210 pop esi 00401211 pop edi 00401212 pop ebx 00401213 leave 00401214 retn 10h 00401217 ; --------------------------------------------------------------------------- 00401217 00401217 loc_401217: ; CODE XREF: sub_401189+6Ej 00401217 push 30h 00401219 push offset a8i ; ">8I" 0040121E push offset aHaha___wrongSN ; "*HAHA*...Wrong S/N#" 00401223 push ds:hWndDialogBox 00401229 call j_MessageBoxA ; BadGuy Message 0040122E pop esi 0040122F pop edi 00401230 pop ebx 00401231 leave 00401232 retn 10h 00401235 ; --------------------------------------------------------------------------- 00401235 00401235 loc_401235: ; CODE XREF: sub_401189+4Aj 00401235 push 30h 00401237 push offset aEdit___ ; "Edit..." 0040123C push offset aHeySonnyBoy___ ; "Hey sonny boy...not even close" 00401241 push ds:hWndDialogBox 00401247 call j_MessageBoxA ; You filled in the wrong EditBox Message 0040124C pop esi 0040124D pop edi 0040124E pop ebx 0040124F leave 00401250 retn 10h 00401253 ; ---------------------------------------------------------------------------
What happens in the main Dialog messageloop? :
If we press the 'check' button, the proggy first checks if we entered
nothing in the EditBox. If we have entered someting, we jump to the 'Hey
sonny boy...' MessageBox. So it's clear we cannot enter something there.
Next the Serial is moved to a buffer. If you look closely, you should
notice that the EditBox which the serial is read from is another one than
the previous checked one! How can this be? There is only one EditBox in
the crackme... We'll check this out in a minute ;-)
When the serial is read, a call is executed where the hash is calculated
and checked. EAX is set to 1 when equal.
Ok, now let's check out the missing EditBox first! As there are now resources
present in the crackme, they have to be build at runtime. Let's check
the beginning of our deadlisting :
00401000 public start 00401000 start proc near 00401000 push 0 00401002 call j_GetModuleHandleA 00401007 mov ds:hInstance, eax 0040100C mov ds:dword_402000, 4003h 00401016 mov ds:dword_402004, offset sub_401189 00401020 mov ds:dword_402008, 0 0040102A mov ds:dword_40200C, 0 00401034 mov eax, ds:hInstance 00401039 mov ds:dword_402010, eax 0040103E push 7F04h 00401043 push 0 00401045 call j_LoadIconA ; Load Icon 0040104A mov ds:dword_402014, eax 0040104F push 7F00h 00401054 push 0 00401056 call j_LoadCursorA ; Load Cursor 0040105B mov ds:dword_402018, eax 00401060 mov ds:dword_40201C, 0Bh 0040106A mov ds:dword_402020, 0 00401074 mov ds:dword_402024, offset aAsmclass ; "ASMClass" 0040107E push offset dword_402000 00401083 call j_RegisterClassA ; Register Class to Windows 00401088 push 0 0040108A push ds:hInstance 00401090 push 0 00401092 push 0 00401094 push 69h ; height 00401096 push 0D2h 0040109B push 8000h 004010A0 push 8000h 004010A5 push 104B0000h 004010AA push offset aPhoxSeventhCra ; "PhoX Seventh CrackMe!" 004010AF push offset aAsmclass ; "ASMClass" 004010B4 push 0 004010B6 call j_CreateWindowExA ; Create DialogBox 004010BB mov ds:hWndDialogBox, eax 004010C0 push 0 004010C2 push ds:hInstance 004010C8 push 10h 004010CA push ds:hWndDialogBox 004010D0 push 0 ; Editbox with heigth 004010D0 ; and width 0 ?? 004010D2 push 0 004010D4 push 19h ; y 004010D6 push 0Fh ; x 004010D8 push 50800000h 004010DD push 0 004010DF push offset aEdit ; "Edit" 004010E4 push 0 004010E6 call j_CreateWindowExA ; Create hidden EditBox 004010EB mov ds:HiddenEditHandle, eax 004010F0 push 0 004010F2 push ds:hInstance 004010F8 push 10h 004010FA push ds:hWndDialogBox 00401100 push 12h ; height 00401102 push 0A0h ; width 00401107 push 5 ; y 00401109 push 0Fh ; x 0040110B push 50800000h ; dwStyle 00401110 push 0 00401112 push offset aEdit ; ClassName 00401117 push 0 00401119 call j_CreateWindowExA ; Create EditBox 0040111E mov ds:EditHandle, eax 00401123 push 0 00401125 push ds:hInstance 0040112B push 20h 0040112D push ds:hWndDialogBox 00401133 push 14h 00401135 push 2Eh 00401137 push 2Dh 00401139 push 41h 0040113B push 50800001h 00401140 push offset aOk ; "Ok" 00401145 push offset aButton ; "Button" 0040114A push 0 0040114C call j_CreateWindowExA ; Create OK-Button 00401151 mov ds:dword_402054, eax
Indeed, as you can see after the DialogBox setting up, we have 2 editboxes...but
the first one has nohight/width! (in blue)
Which makes it invisible of course.
But as we already saw in the messageLoop, it's the invisible editbox that
is used to read the serial. So, first step : Patch the width and heigth.
push 0 -> push 12h (height)
Opcode : 6A00 ->6A12
push 0 -> push 50h (width)
Opcode : 6A00 -> 6A50
If you restart the crackme, it should have 2 editboxes now :-)
Let's continue and have a look at the hashing Call :
0040126F ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ 0040126F 0040126F ; Attributes: bp-based frame 0040126F 0040126F sub_40126F proc near ; CODE XREF: sub_401189+66p 0040126F enter 0, 0 00401273 push ebx 00401274 push edx 00401275 push ds:HiddenEditHandle 0040127B call j_GetWindowTextLengthA ; Get Serial Length 00401280 mov ecx, eax ; move SLen to ecx 00401282 xor eax, eax ; zero out 00401284 mov eax, offset unk_40209C ; pointer to Serial Buffer 00401289 cmp byte ptr [eax], 0 ; End of Serial String ? 0040128C jz short loc_4012F8 ; If so, jump 0040128E xor ebx, ebx ; zero out 00401290 xor edx, edx ; zero out 00401292 00401292 loc_401292: ; CODE XREF: sub_40126F+36j 00401292 mov bl, [eax] ; Current Char to bl 00401294 push ecx ; push SLen 00401295 xor cl, bl ; SLen ^ Char 00401297 ror ebx, cl ; ROR ebx, SLen 00401299 rol ecx, 3 ; ROL SLen, 3 0040129C shl ebx, cl ; SHL ebx, SLen 0040129E pop ecx ; pop SLen 0040129F add edx, ebx ; EDX += EBX 004012A1 inc eax ; pointer ++ 004012A2 cmp byte ptr [eax], 0 ; End of Serial String ? 004012A5 jnz short loc_401292 ; If not, loop on... 004012A7 push edx ; push Hash 004012A8 push offset unk_402058 004012AD push offset unk_4020B5 004012B2 call j_wsprintfA ; Convert serial to ascii 004012B7 xor ebx, ebx 004012B9 mov ebx, offset unk_4020B5 ; Move ascii string of Hash in ebx 004012BE cmp byte ptr [ebx], 44h 004012C1 jnz short loc_4012F8 004012C3 cmp byte ptr [ebx+1], 33h 004012C7 jnz short loc_4012F8 004012C9 cmp byte ptr [ebx+2], 46h 004012CD jnz short loc_4012F8 004012CF cmp byte ptr [ebx+3], 38h 004012D3 jnz short loc_4012F8 004012D5 cmp byte ptr [ebx+4], 42h 004012D9 jnz short loc_4012F8 004012DB cmp byte ptr [ebx+5], 31h 004012DF jnz short loc_4012F8 004012E1 cmp byte ptr [ebx+6], 30h 004012E5 jnz short loc_4012F8 004012E7 cmp byte ptr [ebx+7], 43h 004012EB jnz short loc_4012F8 ; Serial hash = 'D3F8B10C' ? 004012ED mov eax, 1 ; if yes, set return flag to TRUE 004012F2 pop edx 004012F3 pop ebx 004012F4 leave 004012F5 retn 4 004012F8 ; ---------------------------------------------------------------------------
I think this Call is pretty straightforward. The small algo that is used
here, needs bruting to be solved.
We don't know the keylength too, but that's no problem. If we look closely
to the hash value, we can 'calculate' that
the serial should be a least 6 chars.
Another thing I prefer to know is the Char Range, but we don't know it...let's
assume 30h - 7Ah
The hash value should be 'D3F8B10C', so we have everything we need.
The only 2 vars used in the algo are Serial = TestString and Serial Length
= SLen
This is my bruting algo :
.WHILE byte ptr [TestString] < 7Bh .WHILE byte ptr [TestString+1] < 7Bh .WHILE byte ptr [TestString+2] < 7Bh .WHILE byte ptr [TestString+3] < 7Bh .WHILE byte ptr [TestString+4] < 7Bh .WHILE byte ptr [TestString+5] < 7Bh
mov ecx, [SLen]
mov eax, offset TestString
xor ebx, ebx
xor edx, edx
loop_on :
mov bl, [eax]
push ecx
xor cl, bl
ror ebx, cl
rol ecx, 3
shl ebx, cl
pop ecx
add edx, ebx
inc eax
cmp byte ptr [eax], 00h
jnz loop_on
cmp edx, 0D3F8B10Ch
jz found_it
inc byte ptr [TestString+5]
.ENDW
inc byte ptr [TestString+4]
mov byte ptr [TestString+5],30h
.ENDW
inc byte ptr [TestString+3]
mov byte ptr [TestString+4],30h
.ENDW
inc byte ptr [TestString+2]
mov byte ptr [TestString+3],30h
.ENDW
inc byte ptr [TestString+1]
mov byte ptr [TestString+2],30h
.ENDW
inc byte ptr [TestString]
mov byte ptr [TestString+1],30h
.ENDW
found_it :
invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString
After a couple of minutes we find the following serial = "2XDrvB"
Enter it in the second EditBox, and we get the goodguy message :-)
|