Sei sulla pagina 1di 15

Un esempio di esame per entrare in un gruppo hacker In america ladesione ad un gruppo vincolato da un esame che deve essere fatto

o inizialmente. In pratica si deve eliminare la maschera inziale di questo programma il quale possiede un sistema Shrinker complesso in quanto tre sezioni scompattano reciprocamente le porpie successive per cui per riuscire a scrivere un codice automofdificante che elimini la visualizzazione della dialog richiesta si deve eseguire un bel traffico. Cercate sulla rete CIA.EXE o prelevatelo dal mio sito : http://www.crackinguniversity2000.it/cracking/Numeri/N_2/Shrinker/c_trial1.zip In alcuni casi sufficiente un p di buona volont per riuscire ad individuare il punto in cui viene eseguita una, o pi, chiamate alle funzioni di controllo. Il problema sussiste quando qualche sezione del programma compattata o codificata con qualche sistema quale Shrinker o simili. Supponiamo di aver a che fare con un programma normale ovvero senza nessuna sezione compattata. Seguendo con SoftIce il programma potremmo giungere al punto in cui una certa call euivale alla chiamata alla funzione di controllo sulla registrazione del programma. Potremmo trovarci davanti ad una sequenza di istruzione del tipo :
.text:10004756 68 00 00 00 80 .text:1000475B E8 50 52 00 00 .text:10004760 8B 8E C4 00 00 00 push 80000000h call mov sub_0_100099B0 ; Call Procedure ecx, [esi+0C4h]

Bloccando la call eviteremmo il controllo sulla durata in tempo del programma o altre funzioni di protezione di questo tipo. Avendo capito questo potremmo sostituire la call con una serie di NOP oppure con un istruzione che occupi i 5 bytes della call stessa. I codici operativi di questa call sono : E8 50 52 00 00 Trovati i codici con cui sostituire questi potremmo editare con un editor esadecimale il programma, cercare questi codici e sostituirli con quelli nuovi. Se il programma compattato con Shrinker o simili non riusciremmo mai a fare la ricerca in quanto fino al momento in cui il programma non va in esecuzione i codici operativi sarebbero incomprensibili. In pratica attivando il programma entra in funzione il decompattatore il quale normalizza in memoria il codice che verr eseguito. Quindi fino a quando il programma non va in esecuzione noi non riusciremo a trovare la

sequenza giusta relativa al codice da modificare. Oltre a non poter trovare le istruzioni non potremmo neppure scrivere le modifiche in quanto queste verrebbero manipolate dal decompattatore. In questo caso l'esecuzione della patch pi complessa in quanto le operazioni da fare sono le seguenti. 1. Trovare una zona di memoria non usata dove scrivere il codice che va a modificare certe locazioni. 2. Trovare il punto in cui termina il decompattatore. 3. Inserire all fine di questo un chiamata al codice che abbiamo scritto nella memoria non utilizzata. Se avessimo a che fare con un programma normale potremmo trovarci nel caso in cui alla locazione : 0040:1234 E8 50 52 00 00 dovremmo inserire 0040:1234 B8 00 00 00 00 Nel caso di un programma compattato dovremo scrivere il codice che va a cambiare ogni singolo byte dentro ad una zona di memoria vuota o non usata. In pratica dovremo scrivere (scritto in forma simbolica) : inizio_memoria_vuota_non_usata mov byte ptr [00401234], B8 ; Primo codice cambiato B8 mov byte ptr [00401235], 00 ; Secondo codice 00 mov byte ptr [00401236], 00 ; Terzo codice 00 mov byte ptr [00401237], 00 ; Quarto codice 00 mov byte ptr [00401238], 00 ; Quinto codice 00 ret ; Ritorna a dove stata chiamata

A questo punto dobbiamo trovare dove inserire la chiamata a questa parte di codice che sicuramente deve essere dopo a che la funzione di decompattazione ha finito di normalizzare la memoria dove deve essere scritta la modifica. Iniziamo a vedere come fare. Diciamo subito che per fare la prova useremo un programmino che viene utilizzato come esame di ammissione ad un gruppo di hacker americano. Il programma si chiama CIA.EXE. Quando attivato questo mostra una maschera che dovremo eliminare.

Per prima cosa dobbiamo avere i seguenti strumenti installati. Per vedere le sezioni e le informazioni del file eseguibile usiamo ProcDump. Come debugger invece usiamo SoftIce e come editor esadecimale HEX Editor. Carichiamo ProcDump e richiediamo il PE Editor.

Appena premuto il tasto per evitare il PE avremo :

Lo scopo di quello che faremo e quello di trovare nel file fisico l'offset dell'entry point di questa sezione in cui andremo a modificare la prima istruzione eseguita con una chiamata all'interrupt 3 in modo da poterla intercettare. Esiste un breakpoint di SoftIce che permette di intercettare un interrupt che useremo con

l'int 3. Ci interessa fare ijn modo che SoftIce si blocchi nell'istante in cui viene eseguita la prima istruzione di questa sezione. A questo punto troviamo l'offset fisico del file e andiamo a cambiare con un editor esadecimale il codice operativo presente (in genere 0x83) sostituendolo con un INT 3 (0xCC). L'entry point 0008C3DA. Editiamo il PE e cerchiamo la sezione pi prossima a questo entry point. La pi vicina la sezione .load a 0008B000.

Prendiamo 8C3DA e sottraiamo 8B000 ricavando 13DA. L'offset segnato per questa sezione 0x2800 a cui andiamo sommare 0x13DA ottenendo 0x3BDA. Carichiamo HEXWork o un editor esadecimale e leggiamo CIA.EXE.

Richiamiamo la funzione per fare un GOTO all'offset calcolato. Infatti alla locazione a cui stato eseguito il salto troviamo il codice 0x83.

Sostituiamolo con il codice dell'int 3 (0xcc) e salviamo il tutto. Entriamo in SoftIce battendo CTRL D e inseriamo un BREAKPOINT basato sulla chiamata d'interrupt a fine di intercettare l'int 3 appena inserito. Digitiamo in SoftIce : bpint 3 A questo punto attiviamo il programma CIA.EXE. Chiaramente appena in esecuzione il programma lancier un INT 3 che il brakpoint intercetter visualizzandoci SoftIce. Chiaramente appena attivato SoftIce per poter proseguire dovremo di nuovo inserire il codice originale che avevamo sostituito. Facciamo questo mediante l'istruzione di SoftIce : e eip 83 Chiaramente il punto in cui l'int 3 si trova a 0040000 + 8C3DA ovvero a 0048C3DA. L'image base lo vediamo sempre da ProcDump.

Ora dobbiamo trovare dove si trova la call che attiva la maschera.

Chiaramente prima di trovare questa verr eseguita dal programma la routine di decompattazione. Armiamoci di pazienza e usiamo SoftIce con tanti F10 per eseguire lo step by step. Usando F10 dovremo usare la tecnica di inserire prima di una call un breakpoint in modo tale di non dover ripetere tutte le volte la stessa sequenza. F10 non entra nella call per cui ad un certo punto vedrete la finestra che compare. Se abbiamo inserito prima di tale call un breakpoint non dovremo, riattivando il programma, ripetere la sequenza di F10.F10 ecc. ma semplicemente premendo F5 arriveremo fino a prima della call. Arrivati alla call useremo F8 per entrare con il trace dentro e dopo rinizieremo con F10. Anche in questo caso la finestra comparir di colpo. Usiamo sempre i breakpoint per evitare la ripetizione tutte le volte. Ricordiamoci anche che ogni volta che lanciamo CIA.EXE dovremo sostituire l'int 3 con l'istruzione il cui codice operativo 83 (cmp dword ptr [xxxxx],0). La prima call si trova a 0048C45C. :0048C455 push [ebp+10] :0048C458 push [ebp+0C] :0048C45B push esi :0048C45C call CRACKME.0048C467 :0048C461 pop edi :0048C462 pop esi La seconda call a 0048CADF. :0048C4D6 push [ebp+10] :0048C4D9 push [ebp+0C] :0048C4DC push [ebp+08] :0048C4DF call [ebp-20] :0048C4E2 mov dword ptr [ebp-1C], eax Bisogna dire che alle istruzioni dopo a queste calls il programma non torna mentre la call che cerchiamo noi viene eseguita e il programma dopo ritorna all'istruzione successiva continuando l'esecuzione. La call che attiva la dialog all'indirizzo 00460164. Ora se noi in corrispondenza alla prima call cercassimo d vedere che cosa si trova a quell'indirizzo ci accorgeremmo che non esiste nulla di quello che vediamo quando ci arriviamo sopra. Questo perch non ancora stata attivata la funzione di decompattazione di quella zona di memoria.

Ora dovremo vedere dove di fatto inizia e finisce la routine di scompattazione. La seconda call, quella a 0048CADF, ci invia a 0047B000. Se arrivati a questo punto richiediamo di vedere la memoria a 00460164 mediante l'istruzione di SoftIce : d 00460164 Ci accorgeremo che nella finestra di visualizzazione dei dati non ci viene mostrato nulla. A questo punto, a 0047B000, inizia una parte di codice che esegue un loop e che termina a 0047B052. Arrivati a questa ultima locazione vedremo che i dati della finestra aperta con d 00460164 ci vengono visualizzati. Questo significa, trovato in questo modo in modo brutale, che il codice tra 0047B000 e 0047B052 quello che scompatta la zona in cui ci interessa cambiare i codici operativi della call alla dialog. :0047B000 push ebp :0047B001 push edi :0047B002 push esi :0047B003 push edx :0047B004 push ecx :0047B005 push ebx :0047B006 call CRACKME.0047B00B :0047B00B pop ebp :0047B00C mov edx, ebp :0047B00E sub ebp, 00402E1B :0047B014 sub edx, dword ptr [ebp+00402E7A] :0047B01A sub edx, 0000000B :0047B01D mov dword ptr [ebp+00402E83], edx :0047B023 lea esi, dword ptr [ebp+00402E82] :0047B029 movzx esi, byte ptr [esi] :0047B02C mov edi, ebp :0047B02E lea ebx, dword ptr [ebp+00402E83] :0047B034 mov ebx, dword ptr [ebx] :0047B036 lea eax, dword ptr [edi+00402E87] :0047B03C mov eax, dword ptr [eax] :0047B03E add ebx, eax

:0047B03E add ebx, eax :0047B040 lea ecx, dword ptr [edi+00402E8B] :0047B046 mov ecx, dword ptr [ecx] :0047B048 sub byte ptr [ebx], 7B :0047B04B inc ebx :0047B04C loop 0047B048 :0047B04E add edi, 00000008 :0047B051 dec esi :0047B052 jne 0047B02E :0047B054 mov eax, dword ptr [ebp+00402E7E] :0047B05A mov ebx, dword ptr [ebp+00402E83] :0047B060 add eax, ebx :0047B062 pop ebx :0047B063 pop ecx :0047B064 pop edx :0047B065 pop esi :0047B066 pop edi :0047B067 pop ebp :0047B068 jmp eax Quando stato eseguito questo codice l'ultima istruzione (jmp eax) esegue un salto a 0047A000 locazione alla quale troviamo esattamente lo stesso codice trovato a 0047B000. Anche in questo caso il codice termina con un salto (jmp eax) a 00479000 locazione alla quale per la terza volta troviamo esattamente lo stesso codice terminante con un ulteriore JMP che questa volta fa saltare alla zona in cui si trova la nostra chiamata. Il salto dell'ultima volta a 0046011C (ricordate che la calla alla dialog si trova a00460164 ovvero poco pi avanti di dove si arriva con il salto). Come mai il codice uguale tre volte ? Ogni parte di codice decompatta il suo successivo e questo ci complica la vita in quanto dal primo blocco non potremo andarea modificare il codice del terzo in quanto al tempo dell'esecuzione del primo il tezro non ancora scompattato. In questo modo dovremo scrivere 4 blocchi di codice in un zona di memoria non usata e prima del primo blocco ne dovremo richiedere l'esecuzione della prima parte, prima della seconda dovremo richidere l'esecuzione di una seconda parte e cosi via. Le sezioni compattate con Shrinker sono tre e guardate un po la finezza per settare l'indirizzo diverso . Anzi, prima di vederlo ricordatevi che la call salva nello stack l'indirizzo di ritorno che sarebbe quello successivo alla call stessa.

:0047B005 push ebx :0047B006 call CRACKME.0047B00B :0047B00B pop ebp :0047B00C mov edx, ebp La call chiama la locazione successiva (call 0047B00B) e l'istruzione dove arriva con la call estrae immediatamente l'indirizzo salvato dalla call stessa mettendolo in ebp. In pratica ebp contiene l'indirizzo stesso di dove si trova la pop ebp. Nel modulo in cui le istruzioni sono a 0047B000 l'indirizzo in EBP diventa 0047B00B. Nella parte a 0047A000 in EBP troveremo 0047A00B ed infine nella parte a 00479000 avremo in EBP 0047900B. Ritorniamo al punto in cui abbiamo stabilito che l'ultimo JMP dei tre moduli uguali salta a 0046011C. Ora potremmo cercare in CIA.EXE una zona di memoria non usata. Con l'editor esadecimale andiamo a vedere se esiste una zona vicina a quella in cui abbiamo l'entry point, a zero. Troviamo una zona all'offset in decimale 27232.

Per evitare di fare calcoli particolari editiamo, sempre con l'editor esadecimale, questa zona di memoria e scriviamoci dentro una stringa da usare con le funzioni di ricerca di SoftIce. Ad esempio scriviamoci PIPPO (che fantasia).

Attiviamo nuovamente il programma, dopo aver salvato le modifiche apportate con l'editor

esadecimale, e cerchiamo la locazione dove si trova PIPPO con : s 0 l ffffffff 'PIPPO' La ricerca ci indica che la stringa viene trovata a 0048FE70 zona di memoria in cui ora dovremo scrivere il codice che va a modificare i codici operativi della call che attiva la dialog. Per vedere i codici come devono essere modificati eseguiamo il programma fino a giungere alla locazione in cui si trova la call a 00460164. Il codice operativo a 00460164 : E8 73 9A FF FF che dovremo cambiare in 5 NOP consecutivi ovvero : 00460164 90 NOP 00460165 90 NOP 00460166 90 NOP 00460167 90 NOP 00460168 90 NOP Nella zona di memoria vuota dovremo scrivere diverse parti di codice e vediamo ora quali. Questi NOP dovranno essere scritti dentro ad una zona che viene decodificata dal terzo blocco di codice uguale quello visto. Quando si deve scrivere dentro ? Per ora ancora impossibile in quanto il primo blocco di codice, quello visto prima, decompatta il secondo mentre il secondo decompatta il terzo per cui la questione si complica ulteriormente. In pratica alla call [ebp-20] dovremo inviare il programma ad eseguire un altro codice che dovremo scrivere e che dovr andare a modificare la prima jmp eax alla fine del primo blocco. Vi chiederete per inviarlo dove ? Se dopo l'esecuzione del primo blocco il secondo scompattato dovremo prima di fare il salto inviare ad un codice che modifica la seconda jmp del secondo blocco. Questa jmp del secondo blocco infine eseguir un codice che modifica la jmp del terzo. Sono sicuro che non avete capito, non perch non siete intelligenti, ma solo per il fatto che mi sono spiegato da cane. Per farvi capire che cosa dobbiamo fare guardate il seguente diagramma.

Questo il flusso normale. La prima call (call [ebp-20]) chiama il primo blocco il quale scompatta il secondo. Una volta scompattato il secondo lo richiama e questo scompatta il terzo. Finito di scompattare il terzo lo richiama e questo scompatta la zona dove in effetti esiste la call alla dialog. A questo punto nella zona di memoria libera scriviamo il codice che va a modificare parte del codice del primo blocco. AL posto della prima call mettiamo :
:0048C4DC push [ebp+08] :0048C4DF call CRACKME2.0048FE95 ;Chiama la funzione scritta nella zona a 0 In questa zona abbiamo scritto : :0048FE95 mov byte ptr [0047B065], E9 :0048FE9C mov byte ptr [0047B066], 4F :0048FEA3 mov byte ptr [0047B067], 4E :0048FEAA mov byte ptr [0047B068], 01 :0048FEB1 mov byte ptr [0047B069], 00 :0048FEB8 ret :0048C4E4 call [ebp-20]

Questa seuqenza di istruzioni andr a scrivere a 0047B065 jmp 0048feb9. Vedete che si va ad inserire a certi indirizzi i codici operativi delle nuove istruzioni. A 047B065 c': :0047B065 pop esi :0047B066 pop edi :0047B067 pop ebp

:0047B068 jmp eax L'istruzione che dovremo mettere dovrebbe sustituire la JMP EAX la quale occupa come codici operativi solo due byte. Noi la sostituiremo con una call che invierad un'altra parte di codice scritta nella zona vuota. Jmp 0048Feb9 Questa istruzione sfortunatamente occupa 5 bytes per cui per non andare a rompere le scatole alla memoria dopo la jmp eax iniziermo a scriverla 3 bytes prima a partire da 0047B065. Le POP ESI, EDI e EBP che copriamo le metteremo nel nostro codice il quale eseguir: scrivi le nuove istruzioni in 0047A065 fai le pop esi, edi e ebp coperte esegui il jmp eax Il flusso diventa come il seguente :

Il codice scritto nella zona vuota (che corrisponde a quello nei rettangoli azzurri) ,quello che seguir. Questa parte scritta a partire da 0048FE6D per arrivare a 0048FE94. Per mantenere questo indirizzo l'offset in cui scrivere i codici operativi sul disco dovrebbe

partire da 27244 (decimale). Non vorrei essere stato impreciso ma c'da perderci gli occhi a fare questi lavori. Provate a scrivere una sola file di codici esadecimali legati ad un istruzione ad un offset del file tramite l'editor esadecimale e andate a vedere con il debugger dove stata messa con precisione.
C6056401460090 C6056501460090 C6056601460090 C6056701460090 C6056801460090 5E 5F 5D FFE0 POP POP POP JMP MOV MOV MOV MOV MOV ESI EDI EBP EAX BYTE PTR [00460164],90 BYTE PTR [00460165],90 BYTE PTR [00460166],90 BYTE PTR [00460167],90 BYTE PTR [00460168],90

La parte appena vista quella che verrrichiamato dall'ultimo blocco e che va a mettere i 5 NOP sulla call della dialog. Questa parte modifica il codice del primo blocco a 0047B065 e scritta a partire da 0048FE95 per arrivare a 0048FEB8.
C60565B04700E9 C60566B047004F C60567B047004E C60568B0470001 C60569B0470000 C3 RET MOV MOV MOV MOV MOV BYTE PTR [0047B065],E9 BYTE PTR [0047B066],4F BYTE PTR [0047B067],4E BYTE PTR [0047B068],01 BYTE PTR [0047B069],00

In questo caso, dato che la chiamata prima della call [ebp-20] non dobbiamo ripristinare i tre pop che normalmente nei blocchi di decodifica andiamo a coprire. Questa parte modifica il codice del secondo blocco a 0047A065 ed presente a partire da 0048FEB9 per arrivare a 0048FFE0
C60565A04700E9 C60566A0470077 C60567A047005E C60568A0470001 C60569A0470000 5E 5F 5D FFE0 POP POP POP JMP MOV MOV MOV MOV MOV ESI EDI EBP EAX BYTE PTR [0047A065],E9 BYTE PTR [0047A066],77 BYTE PTR [0047A067],5E BYTE PTR [0047A068],01 BYTE PTR [0047A069],00

Questa parte modifica il terzo blocco a 00479065.

Infine questo locato da 0048FEE1 a 0048FF08


0000:6AE1 C60565904700E9 0000:6AE8 C6056690470003 0000:6AEF C605679047006E 0000:6AF6 C6056890470001 0000:6AFD C6056990470000 0000:6B04 5E 0000:6B05 5F 0000:6B06 5D 0000:6B07 FFE0 POP POP POP JMP MOV MOV MOV MOV MOV ESI EDI EBP EAX BYTE PTR [00479065],E9 BYTE PTR [00479066],03 BYTE PTR [00479067],6E BYTE PTR [00479068],01 BYTE PTR [00479069],00

Queste parti di codice vanno a scrivere le nuove istruzioni. Ora dobbiamo solo modificare la prima call che da : :0048C4DF call [ebp-20] per farla diventare :0048C4DF call 0048fe95 :0048C4E5 call [ebp-20] Questo dovremo andare con l'editor esadecimale a cambiarlo. Segnatevi i codici operativi della semplice call [ebp-20]. Scrivete le due istruzioni con la funzione di assemblaggio di SoftIce (a 0048c4df) e poi segnatevi anche in questo caso i codici operativi. Cercate con l'editor esadecimale la prima sequenza di codici e sostituiteli con i secondi. Nella zona di memoria libera dovremo scrivere tutti i codici operativi visti nelle modifiche precedenti. C6056401460090C6056501460090C6056601460090 C6056701460090C60568014600905E5F5DFFE0 C60565B04700E9C60566B047004FC60567B047004E C60568B0470001C60569B0470000C3 C60565A04700E9C60566A0470077C60567A047005E C60568A0470001C60569A04700005E5F5DFFE0 C60565904700E9C6056690470003C605679047006E C6056890470001C60569904700005E5F5DFFE0 Come vi ho gi detto dovrebbe partire da 27244.

La seguente l'immagine dell'editor esadecimale dove ho scritto i codici :

Dopo tutto questo tran tran lanciando il programma non dovremmo pi vedere la maschera iniziale e arrivare subito al menu. Il compito d'esame del gruppo hacker quello di eliminare la maschera all'attivazione ma non quella con il tasto about (che la stessa all'attivazione).