Crackmes.de – josamont's j666
- December 17, 2014
- reverse engineering
- crackmes
- no comments
This crackme was published December 2nd, 2014. It is rated “3 – Getting harder. The description reads:
Find the pass
This is the main routine:
The crackme starts by calling sum_up_code
, shown next:
This code sums up opcode dwords starting from the beginning of the subroutine, until an opcode dword is less than 804819Ah. The result is stored in code_check_sum
. By doing this, the crackme can check for the presence of software breakpoints, which change the code by adding INT 3
. I don’t plan on using a debugger, so I ignore this subroutine. Next the password is read by a call to sys_read
. The value is then converted from hex to binary using the subroutine hexToInt
:
This subroutine starts with an anti patching check: the offset 80480E8
is compared to F3 A6 74 11
– this is the location and opcode for:
F3 A6 repe cmpsb 74 11 jz short loc_80480FD
If you want to patch this check, you also need to patch the check in hexToInt
. Since I don’t plan on patching the crackme, I can ignore this check. The rest of the routine is interpreting the password as hex and converting the value to binary, storing the result in password_value
. There are two interesting code sequences in hexToInt
:
4F dec edi 4B dec ebx 0A 00 or al, [eax]
and
4E dec esi 6F outsd 0A 00 or al, [eax]
The offset of these code snippets is used as the goodboy and badboy message, 4F 4B 00
and 4E 6F 00
decode to the null-terminated strings “OK” and “No” respectively.
After hexToInt
there is a call to xor_code
:
The snippet changes 9*4 bytes starting at offset 80491B8
. The routine affects neither our entered password
, nor the hidden password. I don’t know what the purpose of this routine is. Finally, we get to the password check:
LOAD:080480D9 mov ecx, 4 LOAD:080480DE mov esi, offset loc_8048096 LOAD:080480E3 mov edi, offset password_value LOAD:080480E8 LOAD:080480E8 loc_80480E8: ; DATA XREF: hexToInt+6o LOAD:080480E8 repe cmpsb LOAD:080480EA jz short loc_80480FD LOAD:080480EC mov ecx, offset loc_8048157 LOAD:080480F1 mov edx, 4 LOAD:080480F6 call sys_write LOAD:080480FB jmp short loc_804810C LOAD:080480FD ; --------------------------------------------------------------------------- LOAD:080480FD LOAD:080480FD loc_80480FD: ; CODE XREF: start+59j LOAD:080480FD mov ecx, offset loc_8048142 LOAD:08048102 mov edx, 4 LOAD:08048107 call sys_write LOAD:0804810C LOAD:0804810C loc_804810C: ; CODE XREF: start+6Aj LOAD:0804810C ; hexToInt+14j LOAD:0804810C mov eax, 1 LOAD:08048111 xor ebx, ebx ; status LOAD:08048113 int 80h ; LINUX - sys_exit LOAD:08048113 start endp
The check compares four bytes at offset 8048096
to the password that we entered, if they match, we get the “OK” string , otherwise the “No” message (both are hidden in hexToInt
. At offset 8048096
we find:
LOAD:08048096 loc_8048096: ; DATA XREF: start+4Do LOAD:08048096 B9 9A 91 04 08 mov ecx, offset aCrackme666Jose ; "Crackme 666 Josep\n"
So the entered password needs to match B9 9A 91 04
. Because it’s little endian, we need to enter the reverse:
04919AB9
This gives you the OK message:
$ ./j666 Crackme 666 Josep Password: 04919AB9 OK
You can also leave the leading zero.