This is a math crackme...but we don't know what it expects from us. So
let's disassemble this crackme first.
We can quickly find the goodguy message, and the code we want to examine
:
00401313 cmp [ebp+arg_4], 111h ; WM_COMMAND 0040131A jnz loc_4014F6 00401320 mov edx, [ebp+arg_8] 00401323 shl edx, 10h 00401326 or dx, dx 00401329 jnz short loc_401340 0040132B mov eax, [ebp+arg_8] 0040132E cmp ax, 64h ; TRY-button? 00401332 jnz loc_4013E8 00401338 xor edi, edi 0040133A lea esi, ds:4031D4h 00401340 00401340 loc_401340: ; CODE XREF: sub_4010F9+230j 00401340 ; sub_4010F9+283j 00401340 mov eax, dword_403180[edi*4] 00401347 push offset byte_40304A 0040134C push 2 0040134E push 0Dh 00401350 push eax 00401351 call j_SendMessageA 00401356 inc edi ; counter ++ 00401357 mov al, byte_40304A 0040135C cmp al, 41h ; Test for A-F 0040135E jb short loc_40136A 00401360 cmp al, 46h 00401362 ja short loc_40136A 00401364 sub al, 36h ; convert input 00401366 mov [esi], al ; Store at Matrix[counter] 00401368 jmp short loc_401376 0040136A ; --------------------------------------------------------------------------- 0040136A 0040136A loc_40136A: ; CODE XREF: sub_4010F9+265j 0040136A ; sub_4010F9+269j 0040136A cmp al, 30h ; test for 0-9 0040136C jb short loc_401376 0040136E cmp al, 39h 00401370 ja short loc_401376 00401372 sub al, 2Fh ; convert input 00401374 mov [esi], al ; Store at Matrix[counter] 00401376 00401376 loc_401376: ; CODE XREF: sub_4010F9+26Fj 00401376 ; sub_4010F9+273j ... 00401376 cmp edi, 10h ; All elements inserted? 00401379 jnb short loc_40137E ; if yes, take jump 0040137B inc esi ; next element in matrix 0040137C jmp short loc_401340 ; Continue loop 0040137E ; --------------------------------------------------------------------------- 0040137E 0040137E loc_40137E: ; CODE XREF: sub_4010F9+280j 0040137E call sub_4017BA ; Check if every value is only used once 00401383 cmp eax, 1 ; all different values? 00401386 jnz loc_401527 ; if no, jump badguy 0040138C call sub_40193B ; Make sum of all rows, columns, and diagonals 00401391 call sub_401A5C ; Check if sums are equal 00401396 cmp eax, 1 00401399 jnz short loc_4013E3 ; Badguy jump 0040139B jmp short loc_4013CF ; Goodguy jump :-) 0040139B sub_4010F9 endp 0040139B 0040139B ; --------------------------------------------------------------------------- 0040139D aSuccessYouFoun db 'Success! You found one of',0Dh,0Ah ; DATA XREF: .text:004013D6o 0040139D db 'the correct solutions!',0 004013CF ; --------------------------------------------------------------------------- 004013CF 004013CF loc_4013CF: ; CODE XREF: sub_4010F9+2A2j 004013CF push 40h 004013D1 push offset aMagicNumbers ; "Magic numbers" 004013D6 push offset aSuccessYouFoun ; "Success! You found one of\r\nthe correct "... 004013DB push dword ptr [ebp+8] 004013DE call j_MessageBoxA 004013E3 004013E3 loc_4013E3: ; CODE XREF: sub_4010F9+2A0j 004013E3 jmp loc_401527 004013E8 ; ---------------------------------------------------------------------------
I think the code above is very easy to understand. In short, the values
that are entered in the matrix are converted from their ascii value to
their real value + 1.
So eg. when you enter a 'F' it will be converted to '10h', a '1' to '2h',
and so on...
When this is done, we have 3 calls followed by the goodguy/badguy jump.
Let's check the 3 calls so we can figure out what to do :
CALL 1 :
004017BA sub_4017BA proc near ; CODE XREF: sub_4010F9+285p 004017BA xor ebx, ebx ; init ebx to 0 004017BC lea esi, ds:4031D4h ; esi= address matrix[] 004017C2 mov ecx, 10h ; init counter to 16 004017C7 004017C7 loc_4017C7: ; CODE XREF: sub_4017BA+16Fj 004017C7 mov al, [esi] ; move matrix[counter] to AL 004017C9 cmp al, 1 ; matrix[counter]==1 ? 004017CB jnz short loc_4017E1 ; Jump to next if not 004017CD test bx, 1 ; digit used before? 004017D2 jnz loc_401935 ; If yes, jump badguy 004017D8 or bx, 1 ; If not, put the bit flag 004017D8 ; (16 bits in bx, 16 different values) 004017DC jmp loc_401927 ; jump continue loop 004017E1 ; --------------------------------------------------------------------------- 004017E1 004017E1 loc_4017E1: ; CODE XREF: sub_4017BA+11j 004017E1 cmp al, 2 004017E3 jnz short loc_4017F9 004017E5 test bx, 2 004017EA jnz loc_401935 004017F0 or bx, 2 004017F4 jmp loc_401927 004017F9 ; --------------------------------------------------------------------------- 004017F9 004017F9 loc_4017F9: ; CODE XREF: sub_4017BA+29j 004017F9 cmp al, 3 004017FB jnz short loc_401811 004017FD test bx, 4 00401802 jnz loc_401935 00401808 or bx, 4 0040180C jmp loc_401927 00401811 ; --------------------------------------------------------------------------- ...
00401927 ; --------------------------------------------------------------------------- 00401927 00401927 loc_401927: ; CODE XREF: sub_4017BA+22j 00401927 ; sub_4017BA+3Aj ... 00401927 inc esi ; point matrix to next value 00401928 dec ecx ; counter -- 00401929 jnz loc_4017C7 ; continue loop if not done 0040192F mov eax, 1 ; move 1 to eax and return 00401934 retn 00401935 ; --------------------------------------------------------------------------- 00401935 00401935 loc_401935: ; CODE XREF: sub_4017BA+18j 00401935 ; sub_4017BA+30j ... 00401935 mov eax, 0 ; move 0 to eax and return 0040193A retn 0040193A sub_4017BA endp
In the first call the entire matrix is checked. Every value should only
appear once. To check that the author used register BX.
This is a 16-bit register, and the matrix has also 16 elements... indeed,
every value is represented with one bit.
If a values is found more than once in the matrix, we return with badguy
flag.
CALL 2 :
0040193B sub_40193B proc near ; CODE XREF: sub_4010F9+293p 0040193B mov ecx, 4 00401940 mov byte_4031E4, 0 00401947 lea esi, ds:4031D4h 0040194D 0040194D loc_40194D: ; CODE XREF: sub_40193B+19j 0040194D lodsb 0040194E add byte_4031E4, al ; Sum of first row 00401954 loop loc_40194D 00401956 mov ecx, 4 0040195B mov byte_4031E5, 0 00401962 lea esi, ds:4031D8h 00401968 00401968 loc_401968: ; CODE XREF: sub_40193B+34j 00401968 lodsb 00401969 add byte_4031E5, al ; Sum of second row 0040196F loop loc_401968 00401971 mov ecx, 4 00401976 mov byte_4031E6, 0 0040197D lea esi, ds:4031DCh 00401983 00401983 loc_401983: ; CODE XREF: sub_40193B+4Fj 00401983 lodsb 00401984 add byte_4031E6, al ; Sum of third row 0040198A loop loc_401983 0040198C mov ecx, 4 00401991 mov byte_4031E7, 0 00401998 lea esi, ds:4031E0h 0040199E 0040199E loc_40199E: ; CODE XREF: sub_40193B+6Aj 0040199E lodsb 0040199F add byte_4031E7, al ; Sum of 4th row 004019A5 loop loc_40199E 004019A7 mov ecx, 4 004019AC mov byte_4031E8, 0 004019B3 lea esi, ds:4031D4h 004019B9 004019B9 loc_4019B9: ; CODE XREF: sub_40193B+88j 004019B9 lodsb 004019BA add esi, 3 004019BD add byte_4031E8, al ; Sum of first column 004019C3 loop loc_4019B9 004019C5 mov ecx, 4 004019CA mov byte_4031E9, 0 004019D1 lea esi, ds:4031D5h 004019D7 004019D7 loc_4019D7: ; CODE XREF: sub_40193B+A6j 004019D7 lodsb 004019D8 add esi, 3 004019DB add byte_4031E9, al ; Sum of 2nd column 004019E1 loop loc_4019D7 ...
The second call, makes the sum of all rows, columns, and diagonals. They
are stored in a byte array starting at address 4031E4.
CALL 3 :
00401A5C sub_401A5C proc near ; CODE XREF: sub_4010F9+298p 00401A5C lea esi, ds:4031E4h ; pointer to array with sums 00401A62 lodsb 00401A63 mov ecx, 9 ; init counter = 9 00401A68 push offset loc_401A72 00401A6D call sub_401B70 ; Check if all sums are equal 00401A72 00401A72 loc_401A72: ; DATA XREF: sub_401A5C+Co 00401A72 or eax, eax 00401A74 jnz short loc_401A7B ; Jump to do more checks 00401A76 jmp loc_401B6A ; Badguy jump 00401A7B ; --------------------------------------------------------------------------- 00401A7B ...
The Third and last call check if all these sums (that are stored in the
array), are equal.
|