💾 Archived View for 0x80.org › gemlog › 2016-02-19-practice-tiny-crackme.gmi captured on 2022-04-28 at 17:40:39. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2021-12-03)

-=-=-=-=-=-=-

tiny-crackme

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

1: http://crackmes.de/users/yanisto/tiny_crackme/

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.