crackme_huskies – josamont's j666

Table of Contents

    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] 


    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 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 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 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:


    This gives you the OK message:

    $ ./j666
    Crackme 666 Josep
    Password: 04919AB9

    You can also leave the leading zero.