tiny-crackme

Found this nice and small crackme at crackmes.de. Author comment :

This is my second linux crackme.  
It has a very small size (<400 bytes of bytecode) but implements a few tricks all the same :

- Elf headers corrupted,
- &quot;Cyphered&quot; binary,
- CRC checking,
- Anti ptrace,
- Anti gdb.

Solution will be published later on nuxed.org.  
Enjoy it !  
++nisto.

Let us start solving it. We run the binary

[~/tiny-crackme]$ strace -ifx ./tiny-crackme                                               
....
[00200082] ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted)
[002002a8] write(0, "Sorry but the process seems to b"..., 52Sorry but the process seems to be traced... Bye...
) = 52
[0020031a] _exit(0)                     = ?
[????????] +++ exited with 0 +++

so a ptrace with PTRACE_TRACEME is called at 0x200082 we open in IDA and break there.

LOAD:00200084 test    eax, eax  
LOAD:00200086 jz      short check_flag  
LOAD:00200088 mov     ecx, offset str_sorry           ; "Sorry but the process seems to be trace"...  
LOAD:0020008D mov     dl, 34h  
LOAD:0020008F call    write  

We need eax=0 to bypass the ptrace, if we pass it we go to check_flag which is

LOAD:0020009C do_check_flag:                          ; CODE XREF: LOAD:check_flagj  
LOAD:0020009C push    ebx  
LOAD:0020009D mov     ecx, offset dwinput  
LOAD:002000A2 mov     edx, 4  
LOAD:002000A7 call    read  
LOAD:002000AC call    compute_answer  
LOAD:002000B1 xor     ebx, dwinput  
LOAD:002000B7 jz      short success  

this function expects an input of 4 bytes then it calls compute_answer, where ebx register is set with a value, and then xors it with our input and if ebx=0 we win. Let us see what computer_answer does.

LOAD:002002C9 compute_answer proc near                ; CODE XREF: LOAD:002000ACp  
LOAD:002002C9 jmp     do_compute_answer  
LOAD:002002C9 compute_answer endp  
LOAD:002002C9  
LOAD:002002C9 ; ---------------------------------------------------------------------------  
LOAD:002002CE dw 0C8B0h  
LOAD:002002D0 db  43h ; C  
LOAD:002002D1  
LOAD:002002D1 ; =============== S U B R O U T I N E =======================================  
LOAD:002002D1  
LOAD:002002D1  
LOAD:002002D1 do_compute_answer proc near             ; CODE XREF: compute_answerj  
LOAD:002002D1 xor     eax, eax  
LOAD:002002D3 mov     ebx, eax  
LOAD:002002D5 mov     ecx, 2DFh  
LOAD:002002DA shr     ecx, 2  
LOAD:002002DD mov     esi, offset start  
LOAD:002002E2  
LOAD:002002E2 ACC:                                    ; CODE XREF: do_compute_answer+14j  
LOAD:002002E2 lodsd  
LOAD:002002E3 add     ebx, eax  
LOAD:002002E5 loop    ACC  
LOAD:002002E7 xor     ebx, 5508046Bh  
LOAD:002002ED retn  
LOAD:002002ED do_compute_answer endp  

This function set esi=&start and enters a loop from ecx=0xb7 until ecx=0, each time it gets a dword from esi and increment it by 4. Finally after the loop it
xors ebx with 0x5508046b, and leaves, then xors it with our input. The range of esi is [0x200008,0x200008+(0xb7*4)] which our input is part of, so our input affects the final result in ebx, also patching the binary in this range affects the results.

To compute the answer we need to dump all dword in the range mentioned above, with our input set to zero or whatever. The data we need to dump is :

LOAD:00200008                         public start  
LOAD:00200008                         start proc near                         ; DATA XREF: do_compute_answer+Co  
LOAD:00200008 B3 2A                   mov     bl, 2Ah  
LOAD:0020000A E9 31 00 00 00          jmp     loc_200040  
......
......
......
LOAD:00200292 DA C0 EF BE             dword_200292 dd 0BEEFC0DAh              ; DATA XREF: LOAD:00200058r  
LOAD:00200296 00 00 00 00             dwinput dd 0x44434241h                            ; DATA XREF: LOAD:0020009Do  
LOAD:00200296                                                                 ; LOAD:002000B1r  
LOAD:0020029A                         ; =============== S U B R O U T I N E =======================================  
LOAD:0020029A  
LOAD:0020029A                         ; Attributes: thunk  
LOAD:0020029A  
LOAD:0020029A                         write proc near                         ; CODE XREF: LOAD:0020006Dp  
LOAD:0020029A                                                                 ; LOAD:0020008Fp ...  
LOAD:0020029A E9 01 00 00 00          jmp     do_write  
LOAD:0020029A                         write endp  
......
......
......
LOAD:002002E3 01 C3                   add     ebx, eax  
LOAD:002002E5 E2 ......  

We dump the above region, and we bruteforce the following dwords

....+....
+ 0xYYXXBEEF ; 4241
+ 0x01e9JJZZ ; 4443
...+..

We need to figure out what input 0xXXYYZZJJ at 0x00200296 will result in ebx being zero at the end. The following code bruteforces it.

#!/usr/bin/env python2
import string  
from struct import pack,unpack  
from itertools import permutations

def with_input(d, val):  
    r = []
    x = val&0xffff
    y = (val&0xffff0000) >> 16
    for n in d:
        if n == 0x4241beef:
            r.append(x << 16 | 0xbeef)
        elif n == 0x01e94443:
            r.append(0x01e90000 | y)
        else:
            r.append(n)
    return r

def check(d, n):  
    acc = reduce(lambda x,y: (x+y)&0xffffffff, with_input(d, n)) ^ 0x5508046b
    return True if acc^n==0 else False

d = open("export_results.txt", "rb")  
d = [unpack("<L", d.read(4))[0] for x in xrange(0xb7)]  
charset = string.ascii_lowercase + string.digits  
gen = permutations(charset, 4)  
for g in gen:  
    t = ''.join(g)
    n = unpack("<L", t)[0]
    if check(d, n):
        print "Found ", t

running this gives possible inputs

[~/tiny-crackme]$ python2 solver.py      
Found  b20o  
Found  b40i  
Found  b60k  
Found  f04m  
Found  f24o  
Found  f64k  
[~/tiny-crackme]$ ./tiny-crackme 
      Tiny_crackme - nisto's crackme #2
      ---------------------------------

This one has a particularly small size...  
Hope u'll get some fun with it.

You can join me at yanisto@nuxed.org or on #secdev@freenode.net

Enter the Password :   f64k  
-> Success !! Congratulations...
  -> You can send me your solution/comments at the above mail addr...

done.

}}