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
.
gdb$ disas WhatisIt Dump of assembler code for function WhatisIt: 0x08048cf5 <+0>: push ebp 0x08048cf6 <+1>: mov ebp,esp 0x08048cf8 <+3>: sub esp,0x60 0x08048cfb <+6>: mov BYTE PTR [ebp-0x34],0x5a 0x08048cff <+10>: mov BYTE PTR [ebp-0x33],0x43 0x08048d03 <+14>: mov BYTE PTR [ebp-0x32],0x58 0x08048d07 <+18>: mov BYTE PTR [ebp-0x31],0x4a 0x08048d0b <+22>: mov BYTE PTR [ebp-0x30],0x59 ; ..........................etc....................... 0x08048dff <+266>: mov BYTE PTR [ebp-0x3c],0x1d 0x08048e03 <+270>: mov BYTE PTR [ebp-0x3b],0x1e 0x08048e07 <+274>: mov BYTE PTR [ebp-0x3a],0x1f 0x08048e0b <+278>: mov BYTE PTR [ebp-0x39],0x20 0x08048e0f <+282>: mov BYTE PTR [ebp-0x38],0x21 0x08048e13 <+286>: mov BYTE PTR [ebp-0x37],0x22 0x08048e17 <+290>: mov BYTE PTR [ebp-0x36],0x23 0x08048e1b <+294>: mov BYTE PTR [ebp-0x35],0x24 0x08048e1f <+298>: mov DWORD PTR [ebp-0x10],0x0 0x08048e26 <+305>: mov DWORD PTR [ebp-0x4],0x0 0x08048e2d <+312>: jmp 0x8048e9a <WhatisIt+421> ; jump en bas --> début d'une boucle 0x08048e2f <+314>: mov DWORD PTR [ebp-0x8],0x0 ; début de la boucle 0x08048e36 <+321>: jmp 0x8048e90 <WhatisIt+411> 0x08048e38 <+323>: mov edx,DWORD PTR [ebp-0x4] ; compteur de boucle 0x08048e3b <+326>: mov eax,DWORD PTR [ebp+0xc] ; eax <- serial 0x08048e3e <+329>: add eax,edx ; 0x08048e40 <+331>: movzx edx,BYTE PTR [eax] ; récup le char N°edx du serial 0x08048e43 <+334>: lea ecx,[ebp-0x34] 0x08048e46 <+337>: mov eax,DWORD PTR [ebp-0x8] 0x08048e49 <+340>: add eax,ecx 0x08048e4b <+342>: movzx eax,BYTE PTR [eax] 0x08048e4e <+345>: cmp dl,al 0x08048e50 <+347>: jne 0x8048e8c <WhatisIt+407> 0x08048e52 <+349>: mov DWORD PTR [ebp-0xc],0x0 0x08048e59 <+356>: jmp 0x8048e86 <WhatisIt+401> 0x08048e5b <+358>: lea edx,[ebp-0x59] 0x08048e5e <+361>: mov eax,DWORD PTR [ebp-0xc] 0x08048e61 <+364>: add eax,edx 0x08048e63 <+366>: movzx eax,BYTE PTR [eax] 0x08048e66 <+369>: movzx eax,al 0x08048e69 <+372>: cmp eax,DWORD PTR [ebp-0x8] 0x08048e6c <+375>: jne 0x8048e82 <WhatisIt+397> 0x08048e6e <+377>: mov edx,DWORD PTR [ebp-0x10] 0x08048e71 <+380>: mov eax,DWORD PTR [ebp+0x8] 0x08048e74 <+383>: add eax,edx 0x08048e76 <+385>: mov edx,DWORD PTR [ebp-0xc] 0x08048e79 <+388>: add edx,0x3 0x08048e7c <+391>: mov BYTE PTR [eax],dl 0x08048e7e <+393>: add DWORD PTR [ebp-0x10],0x1 0x08048e82 <+397>: add DWORD PTR [ebp-0xc],0x1 0x08048e86 <+401>: cmp DWORD PTR [ebp-0xc],0x23 0x08048e8a <+405>: jle 0x8048e5b <WhatisIt+358> 0x08048e8c <+407>: add DWORD PTR [ebp-0x8],0x1 0x08048e90 <+411>: cmp DWORD PTR [ebp-0x8],0x23 ; le début jump ici 0x08048e94 <+415>: jle 0x8048e38 <WhatisIt+323> ; jmp si ebp-0x8 <= 0x23 0x08048e96 <+417>: add DWORD PTR [ebp-0x4],0x1 0x08048e9a <+421>: cmp DWORD PTR [ebp-0x4],0x1f ; ebp-0x4 == 0x1f ? 0x08048e9e <+425>: jle 0x8048e2f <WhatisIt+314> ; jmp si ebp-0x4 <= 0x1f ebp-0x4 vaut 0 au début, 0x1f=31, la boucle tournerais donc 32 fois (ça fait tilt ?) 0x08048ea0 <+427>: leave 0x08048ea1 <+428>: ret End of assembler dump.
J'ai raccourci un peu le code
Bon, on remarque une boucle avec beaucoup de conditions. On a surtout l'impression que ceci est fait pour nous embrouiller. On fait ça méthodiquement pour ne pas se faire berner