Reversing [TUTORIAL] Tameo Crackme1 in C

Stato
Discussione chiusa ad ulteriori risposte.

Predator

Utente Storico
11 Giugno 2007
3,203
47
1,268
900
Ultima modifica da un moderatore:
Ciao a tutti, vi propongo questo semplicissimo crackme scritto ad un amico (tameo). Ho pensato di risolverlo ed usarlo come tutorial.
Linguaggio C
Regole: trovare la password giusta. Patching non consentito
DOWNLOAD

provate da soli se non riuscite leggete il tutorial:
TUTORIAL:
Se non avete OllyDgb scaricatelo dal sito ufficilale, ricordo che per ora la versione 1.10 è migliore della 2.0
www.ollydbg.de
Buttatelo in pasto ad Olly. Se ricerchiamo le stringhe
tasto destro Search for-> All referenced text strings
sta volta non troveremo una beata fava pertanto le stringhe devono per forza essere generate in qualche altro modo, vediamo di andare oltre con l'analisi del codice.
La prima domanda che ci poniamo è: come facciamo a sapere dove andar guardare? NO!
la prima domanda è: con che linguaggio è scritto? per conoscere la risposta ci sono essenzialmente due modi
1) riconoscere al volo il codice debuggato
2) avvalersi di un analizzatore. A fronte di questo vi rimando a RDG Packer Detector
RDGMax - RDGSoFT
se non è presente il link di download intanto vi propongo la versione 6.6 2k8 RDG DOWNLOAD

proseguiamo
giusto per curiosità analizziamolo e vediamo cosa ci dice RDG: compilatore Dev-C++ :)
proseguiamo:
La logica suggerisce di vedere come la domanda e la risposta vengono mostrate e da li proseguire:
in C++ che cosa mostra nella finestra dos un stringa? la funzione printf pertanto se noi mettessimo un breakpoint su tutti i printf arriveremo vicino a cioò che ci interessa.
Ci sono 3 modi per trovare una CALL (una funzione):
-cercarle a mano sfogliando il codice :D
-mettere un breakpoint su tutte le CALL tramite commandline
-mettere uno o piu' breakpoint scegliendo le CALL da un elenco... in questo caso opto per questa
***
apro una parentesi: notate in basso a sinistra nel dump cosa vediamo? tho c'è scritto "abcdefghijklmnopqrstuvwxyz :", chissà a che serve? :D
chiusa parentesi, la riprendiamo dopo
***
dunque siamo nella finestra del codice premete tasto destro e scegliete: Scearch for-> All intermodulars call
cioè tutte le chiamate intermodulari, ovvero CALL personali e chiamate alle API di sistema operativo,
questa è la lista di questo crackme:
Codice:
Found intermodular calls
Address             Disassembly                                 Destination
00401220 crackme.<ModuleEn  PUSH    EBP                                 (Initial CPU selection)
00401900            CALL    <JMP.&msvcrt.abort>                         msvcrt.abort
00401982            CALL    <JMP.&msvcrt.abort>                         msvcrt.abort
0040189F            CALL    NEAR DWORD PTR DS:[<&KERNEL32.AddAtomA>]                kernel32.AddAtomA
004011E9            CALL    <JMP.&msvcrt._cexit>                        msvcrt._cexit
004011F1            CALL    <JMP.&KERNEL32.ExitProcess>                     kernel32.ExitProcess
0040197D            CALL    <JMP.&msvcrt.fflush>                        msvcrt.fflush
00401777            CALL    NEAR DWORD PTR DS:[<&KERNEL32.FindAtomA>]               kernel32.FindAtomA
004018C0            CALL    NEAR DWORD PTR DS:[<&KERNEL32.FindAtomA>]               kernel32.FindAtomA
0040196D            CALL    <JMP.&msvcrt.fprintf>                           msvcrt.fprintf
004018B8            CALL    <JMP.&msvcrt.free>                          msvcrt.free
0040164F            CALL    NEAR DWORD PTR DS:[<&KERNEL32.GetAtomNameA>]            kernel32.GetAtomNameA
00401452            CALL    <JMP.&msvcrt._getch>                        msvcrt._getch
004014B2            CALL    <JMP.&msvcrt._getch>                        msvcrt._getch
0040114A            CALL    <JMP.&msvcrt.__getmainargs>                     msvcrt.__getmainargs
00401798            CALL    <JMP.&msvcrt.malloc>                        msvcrt.malloc
004012DD            CALL    <JMP.&msvcrt.memcpy>                        msvcrt.memcpy
0040139F            CALL    <JMP.&msvcrt.printf>                        msvcrt.printf
004013B5            CALL    <JMP.&msvcrt.printf>                        msvcrt.printf
00401443            CALL    <JMP.&msvcrt.printf>                        msvcrt.printf
004014A3            CALL    <JMP.&msvcrt.printf>                        msvcrt.printf
004011C5            CALL    <JMP.&msvcrt.__p__environ>                      msvcrt.__p__environ
004011B0            CALL    <JMP.&msvcrt.__p__fmode>                        msvcrt.__p__fmode
004013CB            CALL    <JMP.&msvcrt.scanf>                         msvcrt.scanf
00401185            CALL    <JMP.&msvcrt._setmode>                          msvcrt._setmode
004011AB            CALL    <JMP.&msvcrt._setmode>                          msvcrt._setmode
00401206            CALL    <JMP.&msvcrt._setmode>                          msvcrt._setmode
00401111            CALL    <JMP.&KERNEL32.SetUnhandledExceptionFilter>             kernel32.SetUnhandledExceptionFilter
0040122D            CALL    NEAR DWORD PTR DS:[<&msvcrt.__set_app_type>]            msvcrt.__set_app_type
0040124D            CALL    NEAR DWORD PTR DS:[<&msvcrt.__set_app_type>]            msvcrt.__set_app_type
00401037            CALL    <JMP.&msvcrt.signal>                        msvcrt.signal
00401094            CALL    <JMP.&msvcrt.signal>                        msvcrt.signal
004010BD            CALL    <JMP.&msvcrt.signal>                        msvcrt.signal
004010E7            CALL    <JMP.&msvcrt.signal>                        msvcrt.signal
le mie non sono ordinate per offset perchè prima di incollare ho semplicemente premuto sulla colonna Destination, in questo modo le call dello stesso tipo sono tutte vicine.
vedete queste?:
Codice:
0040139F            CALL    <JMP.&msvcrt.printf>                        msvcrt.printf
004013B5            CALL    <JMP.&msvcrt.printf>                        msvcrt.printf
00401443            CALL    <JMP.&msvcrt.printf>                        msvcrt.printf
004014A3            CALL    <JMP.&msvcrt.printf>                        msvcrt.printf
premete F2 su ognuna di esse in modo da settare un breakpoint, ora runniamo con F9
Olly breka subito sull'offset 0040139F

0040139F CALL <jmp.&msvcrt.printf> ; printf
salite qualche riga piu' su, vedete che il comando è come "racchiuso" in un ciclo, mi riferisco a questa porzione di codice:
Codice:
00401379   CMP     DWORD PTR SS:[EBP-20C], 11                 ; |
00401380   JG      SHORT 004013AE                     ; |
00401382   MOV     EAX, DWORD PTR SS:[EBP-20C]                ; |
00401388   MOV     EAX, DWORD PTR SS:[EBP+EAX*4-58]               ; |
0040138C   ADD     EAX, 00402000                      ; |
00401391   MOVSX   EAX, BYTE PTR DS:[EAX]                 ; |
00401394   MOV     DWORD PTR SS:[ESP+4], EAX                  ; |
00401398   MOV     DWORD PTR SS:[ESP], 00403000               ; |%c\n%*s
0040139F   CALL    <JMP.&msvcrt.printf>                   ; \printf
004013A4   LEA     EAX, DWORD PTR SS:[EBP-20C]
004013AA   INC     DWORD PTR DS:[EAX]
004013AC   JMP     SHORT 00401379
ovviamente questo codice fa qualcos che permette alla printf di mostrare a video la prima frase, cioè "dammi la password:"
Per seguire al meglio tutta l'operazione dall'inizio mettete un bp (breakpoint) sulla prima istruzione: 00401379 CMP DWORD PTR SS:[EBP-20C], 11
Premiamo CTRL+F2 per ricaricare il progetto e runniamo ancora con F9
questa volta siamo fermi prima... Dato che siete all'inizio vi spiegherò bene cosa fa il codice C++ disassemblato leggendovi l'asm ritornato per bene. Perchè un reverser è proporzionalmente bravo al suo grado di capire il codice.
ora proseguite premendo F8, cosi procediamo per step
00401379 CMP DWORD PTR SS:[EBP-20C], 11 <--- (CMP significa confrontare è come un IF) esegue un confronto con cio' che trovera' nello stack all'indirizzo EBP - 20C (ricordate che tutto cio' che vedete è esadecimale e non decimale percio' 20C = 524 ma non ve ne importa di questo, mentre EBP è il valore di uno dei registri)
riprendo, esegue un contro tra l'indirzzo e il valore 11 (esadecimale cioè 18 in decimale), per farla semplce praticamente siamo all'interno di un ciclo for che va da 0 a 18 :)
proseguo
00401380 JG SHORT 004013AE <--- Salto condizionato: "Salta se è maggiore di" cioè esegui il salto se EAX è maggiore di 11 (18 in decimale)

00401382 MOV EAX, DWORD PTR SS:[EBP-20C] <---(MOV mette dei valori dal secondo operando nel primo) Mette in EAX il valore dello stack presente all'offset EBP-20C, in questo caso è 0
pratiamente inizializza a zero EAX

00401388 MOV EAX, DWORD PTR SS:[EBP+EAX*4-58] <--- come sopra ma questa volta in EBP+EAX*4-58 c'è un valore che cosa?
semplice lo vediamo nel riquadro subito sotto il codide:
Stack SS:[0022FF20]=00000003
EAX=00000000
significa che ora in EAX c'è 00000000 e andra' a metterci 3

0040138C ADD EAX, 00402000 <--- (ADD esegue una somma) aggiunge al valore contenuto in EAX, il valore esadecimale 402000
attenzione :D cosa ci sarà mai la? non dobbiamo nemmeno fare la fatica di cercare nel dump, basta abbassare gli occhi che è ancora li
Codice:
00402000  61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70  abcdefghijklmnop
00402010  71 72 73 74 75 76 77 78 79 7A 20 3A 03 00 00 00  qrstuvwxyz :....
402000+3= 402003 che corrisponde alla posizione della lettera "d". I piu' svegli avranno già capito che il ciclo passa un array di valori che puntano alle lettere che compongono le frasi :)

00401391 MOVSX EAX, BYTE PTR DS:[EAX] <--- (MOVSX mette un dato a 8 o 16 bit in una destinazione a 16 o 32 bit) prende il valore AL QUALE PUNTA EAX e lo mette in EAX stesso cioè mette in eax 64h che in decimale è 100 che corrisponde alla lettera "d" in ascii, poi lo vediamo subito
Codice:
DS:[00402003]=64 ('d')
EAX=00402003 (crackme.00402003)

ora attenzione ci sono 3 righe da analizzare assieme perchè compongono la funzione printf che funziona per esempio cosi:
printf("%c",carattere);
percio' dobbiamo passare alla funzione 2 valori e poi richiamarla, ecco cosa succede

00401394 MOV DWORD PTR SS:[ESP+4], EAX <---mette nello sposta avanti lo stack di 4 (cioè una DWORD) e ci mette il valore di EAX (cioè 64h). prima di premere F8 guardate lo stack (finestra in basso a destra), guardate la seconda riga. ora premete F8. come vedete è apparso 64
perchè come vi ho detto ha spostato lo stack di 4 e ha messo il valore in esso.

00401398 MOV DWORD PTR SS:[ESP], 00403000 <--- come prima, ma senza spostarsi nello stack, mette il valore che trova a 403000h, cioè "%c"
0040139F CALL <jmp.&msvcrt.printf> <--- esegue la printf :D
per venire al lato pratico la printf sta stampando a video il carattere 'd'

004013A4 LEA EAX, DWORD PTR SS:[EBP-20C] <---muove in eax il valore dello stack al momento è 1
004013AA INC DWORD PTR DS:[EAX] <--- incrementa eax di 1
004013AC JMP SHORT 00401379 <--- salta in su all'offset 401379h dove c'è la riga con il CMP
il ciclo si ripete!!!
ora potete scendere con F8 da soli :)
noterete che:
il salto JG non verra' effettuato fino a quando il contatore sarà 11
il ciclo prelevera' dall'array tutti i valori che poi printf manderà a video
poi quando il contatore arrivera' a 12 allora sara' maggiore di 11 (ma va?) e il JG eseguira' il salto uscendo dal ciclo
tutto questo comporra' la frase "dammi la password :"

poco piu' giu' la funzione scanf ci mettera' in attesa della password
mettete un bp su 004013D0 subito dopo la scanf, scrivete "pippo" come password e premete invio
ora scendete con F8 e vediamo l'inizio di un altro ciclo piu' grande... anzi a guardare bene sono due cicli for uno dentro l'altro.
simile a prima vediamo cosa fa:
004013DA CMP DWORD PTR SS:[EBP-20C], 6 <--- va da 0 a 6, cioè controlla 7 caratteri
004013E1 JG 00401470 <--- se è il 7 salta altrimenti prosegue
004013E7 LEA EAX, DWORD PTR SS:[EBP-8] <--- (LEA da lo stesso risultato di MOV ma si usa un po diversamente, lo vedremo)
004013EA ADD EAX, DWORD PTR SS:[EBP-20C]
004013F0 LEA ECX, DWORD PTR DS:[EAX-200] <--- mette in ECX l'indirizzo nel quale risiede la pass inserita "pippo"
004013F6 MOV EAX, DWORD PTR SS:[EBP-20C]
004013FC MOV EDX, DWORD PTR SS:[EBP+EAX*4-D8]
00401403 ADD EDX, 00402000
in pratica fino a qui fa la stessa cosa di prima, sposta mette valori nei registri EAX, ECX e EDX prendendoli dallo stack

00401409 MOVZX EAX, BYTE PTR DS:[ECX] <--- prepara l'analisi con la prima lettera
0040140C CMP AL, BYTE PTR DS:[EDX] <--- confronta i valori, nel nostro caso sono questi:
DS:[00402006]=67 ('g')
AL=70 ('p')
0040140E JE SHORT 00401463 <--- se i valori sono uguali non esegue il salto, altrimenti si ed uscira' dal ciclo. Ovviamente avendo messo "pippo" uscirà entrando nel ciclo che scrive "password errata" (sempre attraverso un ciclo).
per non uscire dal ciclo possiamo forzarlo modificando il salto condizionale JE con un salto forzato JMP, percio andiamo su

0040140E JE SHORT 00401463
premiamo la barra spaziatrice e modifichiamo JE in JMP
0040140E JMP SHORT 00401463
in questo modo il ciclo continuera' fino la sua fine e all'ffset 0040140C
0040140C CMP AL, BYTE PTR DS:[EDX]
possiamo leggere tutte le lettere che vengono confrontate, una ad una, cioè goodjob.
ovviamente avendo messo JMP al posto di JE il programma continuera' la sua esecuzione credendo di aver ricevuto la password giusta. Ma ora la conosciamo :)
I ragionamenti potrebbero sembrare difficili, ma in realtà un reverser alle prime armi, già dopo un po di tempo arriva a questa soluzione quasi subito, l'importante è non voler mai fare il passo piu' lungo della gamba e procedere per livelli.
ah io ho capito subito che la pass era qui

Codice:
00401329   MOV     DWORD PTR SS:[EBP-D8], 6
00401333   MOV     DWORD PTR SS:[EBP-D4], 0E
0040133D   MOV     DWORD PTR SS:[EBP-D0], 0E
00401347   MOV     DWORD PTR SS:[EBP-CC], 3
00401351   MOV     DWORD PTR SS:[EBP-C8], 9
0040135B   MOV     DWORD PTR SS:[EBP-C4], 0E
00401365   MOV     DWORD PTR SS:[EBP-C0], 1
0040136F   MOV     DWORD PTR SS:[EBP-20C], 0
è solo questione di apprendimento e confidenza :)
spero di aver spiegato il codice asm in modo sufficentemente comprensibile, se avete dubbi o domande non esitate a chiedere.

Predator
 
ti ringrazio Speed è come l'avessi ricevuto :)
l'importante è dare i punti reputazione per meriti :)

Giusto!
Comunque mi spieghi solo una cosa xD
L'RDG Packer Detector lo conosco da tempo...ho provato tempo fa (e anche ora) per ore a cercare un link di download nella home page (quella a cui manda il link che hai messo nella guida) ma non lo trovo.
Quindi:
1-Sono io che sono stupido e non riesco a trovarlo, o proprio non c'è??? (se c'è dove?)
2-Ho provato tempo fa anche a scaricarlo da altri siti (non l'ultima versione ma quella precedente perchè l'ultima non la trovavo), ne avrò trovati almeno 6 o 7 ognuno da siti diversi ma quando lo apro la finestra rimane attiva e funzionante per 10-15 secondi e poi smette di rispondere e crasha. Sai risolvermi il problema??? (Inoltre l'antivirus (Nod32) me lo rileva come virus ma mi basta disabilitarlo o escluderlo dalla scansione).
 
@Colonello Casey grazie :)
SpeedJack: penso che stia aggiornando, perchè il link manca. scarica da qui RDG DOWNLOAD
quando si reversa bisogna sempre disabilitare l'antivirus perchè interferisce troppo, e rallenta l'analisi. Fammi sapere se questo linkato da me ti funziona.
 
Se provo ad avviarlo normalmente si apre e dopo 20 secondi (o quando apro un crackme) crasha come sempre.

Mentre se provo ad avviarlo in modalità compatibilità per qualsiasi versione di Win ecco il risultato:

RDG Packer Detector v0.6.6 2k8.exe - Errore di applicazione ha detto:
Impossibile avviare correttamente l'applicazione (0xc0000005). Fare clic su OK per chiudere l'applicazione.
 
Niente non funziona.
Con quel programma poi ci capisco poco o_O
Ho anche provato a avviarlo in modalità di debug in Visual Studio 2010 ecco cosa dice:

Microsoft Visual Studio ha detto:
Windows ha generato un punto di interruzione in RDG Packer Detector v0.6.6 2k8.exe.

Ciò può essere dovuto a un danneggiamento dell'heap che indica un bug in RDG Packer Detector v0.6.6 2k8.exe o in una qualunque delle DLL che ha caricato.

È anche possibile che l'utente abbia premuto F12 mentre RDG Packer Detector v0.6.6 2k8.exe era attivo.

Controllare la finestra di output per ulteriori informazioni diagnostiche.

mentre quel programma mi da semplicemente questo (ma il problema è che non capisco come usarlo):

Protection ID v0.6.4.0 JULY has crashed...
Build 07/08/10-17:57:05

Welcome to the scene of the crash.... take me to the hospital

EAX = 000000030h, EBX = 00000000Ah, ECX = 000000030h, EDX = 000000000h
ESI = 0004F8510h, EDI = 000000031h, ESP = 00022BFCCh, EBP = 00022C014h

DS = 00023h, ES = 00023h, FS = 0003Bh, GS = 00000h, SS = 00023h
DR0 = 000000000h, DR1 = 000000000h, DR2 = 000000000h, DR3 = 000000000h
DR6 = 000000000h, DR7 = 000000000h

CCW = 00000037Fh, CSW = 000004020h, CTW = 00000FFFFh, CEO = 074773D5Fh
CES = 0005D001Bh, CDO = 00022CFE8h, CDS = 000000023h, CR0NPX = 000000000h

Crash @ CS:EIP -> 0001Bh:076006155h, EFlags : 000010206h
Stack @ SS:ESP -> 00023h:00022BFCCh

Crash Code : 0C0000005h
Crash Report : In Page Error

ThreadID : 01428h / 05160
ThreadName : PiD Core Thread (thread 1)
Crash Happened in Scan File -> Unknown :(
Procedure Name : N/A
Crash File Line Range (low) -> 00
Crash File Line Range (high) -> 00
ProtectionID was scanning ->
Last Scan was -> Crash did NOT happen in scan thread
Scan was N/A
Next Scan is -> Crash did NOT happen in scan thread

Thread Start Va / Tag : 0x00409241

Pid executable range 0x00400000 -> 0x0057B000 (0x0017B000 bytes)

Crash address is NOT within pid's image
 
SpeedJack, è davvero tanto strano o_O
mi documento, perchè è la prima volta che sento un problema del genere. Che sia preferibile reversare su XP si, ma che seven dia quei problemi non era mai successo.
 
SpeedJack, è davvero tanto strano o_O
mi documento, perchè è la prima volta che sento un problema del genere. Che sia preferibile reversare su XP si, ma che seven dia quei problemi non era mai successo.

Già anche perchè 7 dovrebbe mantenere la compatibilità con XP e Vista e anche se così non fosse con la modalità compatibilità normalmente si risolve tutto... Vabbè comunque è la Microsoft e ci si può aspettare di tutto proprio di tutto :asd: .
Comunque aggiungimi su skype se vuoi (ho già provato ad aggiungere l'unico italiano con predator nel nome skype ma se sei te non mi hai ancora accettato xD).

--- Aggiornamento Post ---

LOL mi sono intanto divertito a patchare il crackme (anche se non dovevo xD).

MEGAUPLOAD - The leading online storage and file delivery service

Comunque vado a letto :\ Preddy aggiungimi su skype <.< a domani :omfg:
 
Stato
Discussione chiusa ad ulteriori risposte.