Artificial truth

The more you see, the less you believe.

[archives] [latest] | [homepage] | [atom/rss]

Defeating qcrk5
Thu 02 August 2012 — download

IOLI's crackme are now boring, let's try something else : qcrk5 from Qnix.

Getting infos

$ file qcrk5
qcrk5: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.4.1, stripped

Okay, stripped.

$ strings qcrk5
[...]
Usage : %s <password> Using %s
Correct, Cracked !!
Wrong!
[...]

Okay, a shitload of strings, definitively not in asm, maybe gcc ? Let's try : GCC writes a .comment section that contains the GCC version string (the same string you get if you run gcc --version);

$ readelf -p .comment qcrk5

String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (Gentoo 3.4.4-r1, ssp-3.4.4-1.0, pie-8.7.8)
[...]

Yep, gcc.

$ readelf -a qcrk5 | grep Entry
Entry point address: 0x8048110

start

Let's see what is at 0x8048110:

xor ebp, ebp
pop esi
mov ecx, esp
and esp, 0xFFFFFFF0h
push eax
push esp
push edx
push offset sub_80486E0
push offset sub_8048680
push ecx
push esi
push offset sub_8048208
call sub_8048340

Looks like a standard start function. Our main should be at 0x8048208

main

/ function: main (306)
[...] ;prologue
| 0x08048224 c745fca03d7f4b mov dword [ebp-0x4], 0x4b7f3da0
| 0x0804822b c744240c00000000 mov dword [esp+0xc], 0x0
| 0x08048233 c744240801000000 mov dword [esp+0x8], 0x1
| 0x0804823b c744240400000000 mov dword [esp+0x4], 0x0
| 0x08048243 c7042400000000 mov dword [esp], 0x0
| 0x0804824a e801680000 call dword fcn.0804ea50 ; a function with 0, 0, 1, 0 in parameters, seems familiar...
| 0x0804824f 85c0 test eax, eax
| ,=< 0x08048251 790d jns loc.08048260
| | 0x08048253 b801000000 mov eax, 0x1
| | 0x08048258 8945ec mov [ebp-0x14], eax
| ,==< 0x0804825b e9d5000000 jmp dword loc.08048335 ; jump to the end of the main
| |`-> 0x08048260 837d0802 cmp dword [ebp+0x8], 0x2 ; ebp+0x8 is argc, so: argc != 2 ?
| ,===< 0x08048264 742b jz loc.08048291
| || 0x08048266 8b450c mov eax, [ebp+0xc]
| || 0x08048269 8b00 mov eax, [eax]
| || 0x0804826b 8b15b4f30a08 mov edx, [0x80af3b4]
| || 0x08048271 89442408 mov [esp+0x8], eax
| || 0x08048275 c744240488820908 mov dword [esp+0x4], str.Usagespassword ; tells you how to us the crackme
| || 0x0804827d 891424 mov [esp], edx
| || 0x08048280 e8ab120000 call dword fcn.08049530
| || 0x08048285 c7042400000000 mov dword [esp], 0x0
| || 0x0804828c e87f090000 call dword fcn.08048c10 ; go to some spagetti code, and exit
| `---> 0x08048291 8b450c mov eax, [ebp+0xc]
| | 0x08048294 83c004 add eax, 0x4
| | 0x08048297 8b00 mov eax, [eax]
| | 0x08048299 890424 mov [esp], eax
| | 0x080482a1 8945f8 mov [ebp-0x8], eax ; ebp-0x8 = our_key
| | 0x080482a4 8d45f8 lea eax, [ebp-0x8]
| | 0x080482a7 830005 add dword [eax], 0x5 ; ebp+0x8 += 5
| | 0x080482aa 8d45f8 lea eax, [ebp-0x8]
| | 0x080482ad 830060 add dword [eax], 0x60 ; ebp-0x8 += 0x60
| | 0x080482b0 8b55f8 mov edx, [ebp-0x8] ; edx = ebp-0x8
| | 0x080482b3 89d0 mov eax, edx
| | 0x080482b5 c1e008 shl eax, 0x8 ; ebp-0x8 <<= ebp-0x8
| | 0x080482b8 29d0 sub eax, edx ; ebp-0x8 -= edx
| | 0x080482ba 8945f8 mov [ebp-0x8], eax
| | 0x080482bd 8b45f8 mov eax, [ebp-0x8]
| | 0x080482c0 69c090909000 imul eax, eax, 0x909090 ; ebp-0x8 *= 0x909090
| | 0x080482c6 8945f8 mov [ebp-0x8], eax
| | 0x080482c9 8b450c mov eax, [ebp+0xc]
| | 0x080482cc 83c004 add eax, 0x4
| | 0x080482cf 8b00 mov eax, [eax]
| | 0x080482d1 8b15b4f30a08 mov edx, [0x80af3b4] ; edx = 0x80af3b4
| | 0x080482d7 89442408 mov [esp+0x8], eax
| | 0x080482db c74424049f820908 mov dword [esp+0x4], str.Usings
| | 0x080482e3 891424 mov [esp], edx
| | 0x080482e6 e845120000 call dword fcn.08049530 ; print the ("Using %s", our_key) message
| | 0x080482eb 8b45fc mov eax, [ebp-0x4]
| | 0x080482ee 3b45f8 cmp eax, [ebp-0x8] ; ebp-0x8 == 0x4b7f3da0 ?
| ,====< 0x080482f1 7521 jnz loc.08048314 ; jumps to the end of the main
| | | 0x080482f3 a1b4f30a08 mov eax, [0x80af3b4]
| | | 0x080482f8 c7442404a9820908 mov dword [esp+0x4], str.Correct,Cracked!!
| | | 0x08048300 890424 mov [esp], eax
| | | 0x08048303 e828120000 call dword fcn.08049530 ; Great success !
| | | 0x08048308 c7042400000000 mov dword [esp], 0x0
| | | 0x0804830f e8fc080000 call dword fcn.08048c10
| `----> 0x08048314 a1b4f30a08 mov eax, [0x80af3b4]
| | 0x08048319 c7442404be820908 mov dword [esp+0x4], str.Wrong!
| | 0x08048321 890424 mov [esp], eax
| | 0x08048324 e807120000 call dword fcn.08049530
| | 0x08048329 c7042400000000 mov dword [esp], 0x0
| | 0x08048330 e8db080000 call dword fcn.08048c10
| `--> 0x08048335 8b45ec mov eax, [ebp-0x14]
| 0x08048338 c9 leave
 0x08048339 c3 ret

Nothing hardcore.

Keygen

Here is a dead simple keygen:

#include <stdio.h>

int main(int argc, char* argv[]) {
    unsigned int var_8, tmp, i;

    printf("qcrk5 crackmen");
    printf("[*] Computing...n");

    for(i=1; i<0xffffffff; ++i){
        var_8 = 5 + 0x60 + i;
        tmp = var_8;
        var_8 = var_8 << 8;
        var_8 -= tmp;
        var_8 *= 0x0909090;

        if(var_8 == 0x4b7f3da0){
            printf("[*] Key found: %d\n", i);
            break;
        }
    }
    return 0;
}

Result:

$ a.out
qcrk5 crackme
[*] Computing...
[*] Key found: 91867153

$ qcrk5 91867153
Using 91867153
Correct, Cracked !!

fcn.0804ea50

/ function: fcn.0804ea50 (87)
[...]
| 0x0804ea67 8b7514 mov esi, [ebp+0x14]
| ,=< 0x0804ea6a 7703 ja loc.0804ea6f
| | 0x0804ea6c 8d75f4 lea esi, [ebp-0xc]
| `-> 0x0804ea6f b81a000000 mov eax, 0x1a ; this is a call to ptrace
!
| 0x0804ea74 cd80 int 0x80
| ; ptrace ()
| 0x0804ea76 3d00f0ffff cmp eax, 0xfffff000
| 0x0804ea7b 89c6 mov esi, eax
| 0x0804ea7d 772f ja loc.0804eaae
[...]

As you may know (or not), if you try to call ptrace(PTRACE_TRACEME, ...) on a binary that is already traced (with something like gdb, strace, ...), this will return -1. This is a dead simple anti-debugging method.

Example

#include <stdio.h>
#include <sys ptrace.h>

int main(){
    printf("%ld\n", ptrace(PTRACE_TRACEME, 0, 1, 0));
    return 0;
}

Result:

$ gcc ptace.c && ./a.out
0
$ gdb a.out
Reading symbols from /home/jvoisin/a.out...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/jvoisin/a.out
-1
[Inferior 1 (process 13632) exited normally]
(gdb)

Conclusion

Nothing funky nor complex, just an occasion to introduce the (classic) ptrace trick.