Ceci est une ancienne révision du document !
$ file crackme crackme: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=0xfe11128a5dd83a7776ad2f978b1ab64ba5b7ddba, not stripped
Pour une raison que je ne sais pas expliquer, il est impossible de l'ouvrir avec IDA. C'est parti pour du full gdb !
gdb$ disas main Dump of assembler code for function main: 0x08048f98 <+0>: push ebp 0x08048f99 <+1>: mov ebp,esp 0x08048f9b <+3>: and esp,0xfffffff0 0x08048f9e <+6>: sub esp,0x10 0x08048fa1 <+9>: cmp DWORD PTR [ebp+0x8],0x1 ; check le nombre d'argument 0x08048fa5 <+13>: jg 0x8048fbf <main+39> ; il doit être >1 0x08048fa7 <+15>: mov DWORD PTR [esp],0x80c254d ; "Please enter password ?" 0x08048fae <+22>: call 0x8049990 <puts> 0x08048fb3 <+27>: mov DWORD PTR [esp],0x0 ; push 0 0x08048fba <+34>: call 0x8049770 <exit> ; exit(0) 0x08048fbf <+39>: mov eax,DWORD PTR [ebp+0xc] ; continue ici si au moins un argument est donné 0x08048fc2 <+42>: add eax,0x4 0x08048fc5 <+45>: mov eax,DWORD PTR [eax] ; eax contient notre premier argument (son adresse) 0x08048fc7 <+47>: mov DWORD PTR [esp],eax ; push eax 0x08048fca <+50>: call 0x8048ea2 <check> ; check(argv[1]); 0x08048fcf <+55>: leave 0x08048fd0 <+56>: ret End of assembler dump.
De façon basique, le programme regarde s'il a au moins un argument en entrée. Si ce n'est pas le cas, il retourne un message d'erreur. Dans le cas contraire, il appel la fonction check
avec argv[1]
en argument.
gdb$ disas check Dump of assembler code for function check: 0x08048ea2 <+0>: push ebp 0x08048ea3 <+1>: mov ebp,esp 0x08048ea5 <+3>: push ebx 0x08048ea6 <+4>: sub esp,0x54 0x08048ea9 <+7>: call 0x8048bcc <__x86.get_pc_thunk.bx> 0x08048eae <+12>: add ebx,0x9d1ae 0x08048eb4 <+18>: mov BYTE PTR [ebp-0x28],0x3 0x08048eb8 <+22>: mov BYTE PTR [ebp-0x27],0x23 0x08048ebc <+26>: mov BYTE PTR [ebp-0x26],0x1f 0x08048ec0 <+30>: mov BYTE PTR [ebp-0x25],0x23 0x08048ec4 <+34>: mov BYTE PTR [ebp-0x24],0x5 0x08048ec8 <+38>: mov BYTE PTR [ebp-0x23],0x3 0x08048ecc <+42>: mov BYTE PTR [ebp-0x22],0x8 0x08048ed0 <+46>: mov BYTE PTR [ebp-0x21],0x7 0x08048ed4 <+50>: mov BYTE PTR [ebp-0x20],0x1f 0x08048ed8 <+54>: mov BYTE PTR [ebp-0x1f],0x4 0x08048edc <+58>: mov BYTE PTR [ebp-0x1e],0x5 0x08048ee0 <+62>: mov BYTE PTR [ebp-0x1d],0x20 0x08048ee4 <+66>: mov BYTE PTR [ebp-0x1c],0x21 0x08048ee8 <+70>: mov BYTE PTR [ebp-0x1b],0x7 0x08048eec <+74>: mov BYTE PTR [ebp-0x1a],0x1f 0x08048ef0 <+78>: mov BYTE PTR [ebp-0x19],0x5 0x08048ef4 <+82>: mov BYTE PTR [ebp-0x18],0x21 0x08048ef8 <+86>: mov BYTE PTR [ebp-0x17],0x5 0x08048efc <+90>: mov BYTE PTR [ebp-0x16],0x4 0x08048f00 <+94>: mov BYTE PTR [ebp-0x15],0x1d 0x08048f04 <+98>: mov BYTE PTR [ebp-0x14],0x22 0x08048f08 <+102>: mov BYTE PTR [ebp-0x13],0x1e 0x08048f0c <+106>: mov BYTE PTR [ebp-0x12],0x1f 0x08048f10 <+110>: mov BYTE PTR [ebp-0x11],0x26 0x08048f14 <+114>: mov BYTE PTR [ebp-0x10],0x25 0x08048f18 <+118>: mov BYTE PTR [ebp-0xf],0x1f 0x08048f1c <+122>: mov BYTE PTR [ebp-0xe],0x1e 0x08048f20 <+126>: mov BYTE PTR [ebp-0xd],0x21 0x08048f24 <+130>: mov BYTE PTR [ebp-0xc],0x24 0x08048f28 <+134>: mov BYTE PTR [ebp-0xb],0x6 0x08048f2c <+138>: mov BYTE PTR [ebp-0xa],0x24 0x08048f30 <+142>: mov BYTE PTR [ebp-0x9],0x25 0x08048f34 <+146>: mov DWORD PTR [esp+0x8],0x20 0x08048f3c <+154>: mov eax,DWORD PTR [ebp+0x8] 0x08048f3f <+157>: mov DWORD PTR [esp+0x4],eax ; push notre serial passé en argument 0x08048f43 <+161>: lea eax,[ebp-0x48] 0x08048f46 <+164>: mov DWORD PTR [esp],eax ; push l'adresse de ebp-0x48 0x08048f49 <+167>: call 0x8048cf5 <WhatisIt> ; WhatisIt([ebp-0x48], argv[1]); 0x08048f4e <+172>: lea eax,[ebp-0x28] 0x08048f51 <+175>: mov DWORD PTR [esp+0x4],eax ; push l'adresse de ebp-0x28 0x08048f55 <+179>: lea eax,[ebp-0x48] 0x08048f58 <+182>: mov DWORD PTR [esp],eax ; psuh l'adresse de ebp-0x48 0x08048f5b <+185>: call 0x8048cb4 <ccc> ; ccc([ebp-0x48], [ebp-0x28]); 0x08048f60 <+190>: test eax,eax ; eax = 0 ? 0x08048f62 <+192>: je 0x8048f7b <check+217> ; si oui, jmp en check+217 0x08048f64 <+194>: mov eax,DWORD PTR [ebp+0x8] 0x08048f67 <+197>: mov DWORD PTR [esp+0x4],eax ; push argv[1] 0x08048f6b <+201>: lea eax,[ebx-0x23b30] 0x08048f71 <+207>: mov DWORD PTR [esp],eax ; push "The hash is %s\n" 0x08048f74 <+210>: call 0x8049960 <printf> ; printf("The hash is %s\n",argv[1]); 0x08048f79 <+215>: jmp 0x8048f89 <check+231> ; jmp après le "Wrong password" 0x08048f7b <+217>: lea eax,[ebx-0x23b20] ; jmp ici si ccc renvois 0 0x08048f81 <+223>: mov DWORD PTR [esp],eax 0x08048f84 <+226>: call 0x8049990 <puts> ; printf("Wrong password !\n") 0x08048f89 <+231>: mov DWORD PTR [esp],0x1 0x08048f90 <+238>: call 0x8049770 <exit> ; exit(1); End of assembler dump.
Bon, on voit un certains nombre de mov [ebp-xx],0xyy
, je décide de ne pas y prêter attention pour le moment. On remarque surtout l'appel à la fonction WhatisIt
avec laquelle notre serial est passé en argument, ainsi que l'appel à ccc
qui passe en argument quelque chose stocké en ebp-0x28
ainsi que ebp-0x48
. Ceci parait louche, d'autant qu'il y a un certain nombre de mov
sur l'ebp
. La suite du programme dépend de ce que renvois ccc
dans eax
. Si c'est un 0, le serial n'est pas le bon, si c'est autre chose, le mot de passe est le bon.
Il ne nous reste plus qu'à regarder ce que font WhatisIt
et ccc
.
Il est probable que la fonction WhatisIt
soit là pour chiffrer notre serial et calculer celui d'origine. Je décide d'essayer de résoudre le challenge en regardant uniquement la fonction ccc
.