ROMPIAMO IL CODICE (LEONARDO v1.2) DA VINCI |
||
Data |
by DaGoN |
|
23/04/2005 |
Published by Quequero |
|
"Se
in un primo momento l'idea non è assurda, Albert Einstein |
Grazie tante dago! |
Ogni drago genera un S. Giorgio che lo uccide Kahlil Gibran |
... |
|
.... |
Difficolt� |
( )NewBies ()Intermedio (X)Avanzato ( )Master |
Introduzione |
Cosa dicono gli autori:
Leonardo è un programma per computer che offre la possibilità di effettuare ricerche statistiche avanzate, e consente di ricavare dati preziosi per la formulazione di pronostici ad alta attendibilità. E' uno strumento versatile e potente, indispensabile al ricercatore che desidera analizzare e valutare tutti quei dati che la statistica rende disponibili.
Insomma, un comunissimo programma per il Lotto. Ma...
Tools usati |
W32Dasm v8.93 (un buon disassemblatore)
PEid (solo per prassi)
WinHex (non necessario.. ma l'ho usato)
Borland C++ (Usato per trovare la chiave di decrypting e per il keygen)
Masm 8.2 (usato per fare il keygen)
URL o FTP del programma |
Essay |
Per prassi diamo un'occhiata a cosa stiamo cercando di reversare:
Bene, niente packers o crypters in giro :D. Ora usiamo il vecchio ma sempre utile w32Dasm per disassemblare il leonardino. Qui la fortuna ci ha provato ancora, bella topona! Intuito o culo, c'è da dire che ho trovato quasi subito il codice che controlla la chiusura della form.
Mi sono detto: "Se il programma si chiude, da qualche parte dovrà pur chiamare il metodo close della Form."
Premendo sul pulsante [imp fn] (Import function) notiamo il metodo vcl40::Form::TCustomForm:Close(void()), cioè il metodo che viene richiamato quando si chiude una form. Ma quale sarà il nostro? Quello buono? Io ho puntato su quello della Form1, nonchè la form principale. Questo è il codice disassemblato:
* Reference To: Vcl40.Forms::TCustomForm::Close(void()), Ord:0000h |
Sembrerebbe che tutto dipenda dal flag all'indirizzo 0046D4AC, apriamo Ollydbg e carichiamo Leonardo.exe; nella finestra Hex dump (quella sotto la finestra codice) premiamo Ctrl+g (Go to) e digitiamo 0046D4AC nella form di Olly:
Andremo a finire proprio all'indirizzo del flag, qui metteremo un bel breakpoint memory, on write. Quando qualsiasi istruzione cerca di scrivere al nostro indirizzo olly breakerà. Selezioniamo il primo byte e con il tasto destro applichiamo il breakpoint memory, on write come in figura:
Premiamo F9 e ridigitiamo nel nome "DaGoN", nel cognome "DgN" e nel seriale "11223344". Premiamo il pulsante "Registrami" e questa volta olly breakerà nel punto dove leonardo cercherà di settare a 1 il flag, come in figura:
Mucho interessante:
0040E30C /$ 55 PUSH EBP 0040E30D |. 8BEC MOV EBP,ESP 0040E30F |. 68 F1E84600 PUSH Leonardo.0046E8F1 ; /s2 = "LEONARDO" 0040E314 |. 68 7C7E4800 PUSH Leonardo.00487E7C ; |s1 = "_+]/W!@‚B..... " // ho tagliato... 0040E319 |. E8 1AE50500 CALL <JMP.&cp3245mt._strcmp> ; \_strcmp 0040E31E |. 83C4 08 ADD ESP,8 0040E321 |. 85C0 TEST EAX,EAX //sono uguali(EAX=0)? se si salta... 0040E323 |. 74 07 JE SHORT Leonardo.0040E32C 0040E325 |. C605 ACD44600 >MOV BYTE PTR DS:[46D4AC],1 0040E32C |> 68 FAE84600 PUSH Leonardo.0046E8FA ; /s2 = "1.0" 0040E331 |. 68 9A7E4800 PUSH Leonardo.00487E9A ; |s1 = ""@p9 ... " // ho tagliato 0040E336 |. E8 FDE40500 CALL <JMP.&cp3245mt._strcmp> ; \_strcmp 0040E33B |. 83C4 08 ADD ESP,8 0040E33E |. 85C0 TEST EAX,EAX //sono uguali(EAX=0)? se si salta... 0040E340 |. 74 07 JE SHORT Leonardo.0040E349 0040E342 |. C605 ACD44600 >MOV BYTE PTR DS:[46D4AC],1 0040E349 |> 68 FEE84600 PUSH Leonardo.0046E8FE ; /s2 = "WIZARD 1999" 0040E34E |. 68 9E7E4800 PUSH Leonardo.00487E9E ; |s1 = "9 I/....." // ho tagliato 0040E353 |. E8 E0E40500 CALL <JMP.&cp3245mt._strcmp> ; \_strcmp 0040E358 |. 83C4 08 ADD ESP,8 0040E35B |. 85C0 TEST EAX,EAX //sono uguali(EAX=0)? se si salta... 0040E35D |. 74 07 JE SHORT Leonardo.0040E366 0040E35F |. C605 ACD44600 >MOV BYTE PTR DS:[46D4AC],1 0040E366 |> D905 BC7E4800 FLD DWORD PTR DS:[487EBC] //prende la dword all'indirizzo 487EBC e la confronta 0040E36C |. D81D 80E34000 FCOMP DWORD PTR DS:[40E380] //con la dword 0000803F all'indirizzo 40E380 0040E372 |. DFE0 FSTSW AX // http://webster.cs.ucr.edu/AoA/DOS/ch14/CH14-5.html 0040E374 |. 9E SAHF // per chi volesse approffondire queste istruzioni 0040E375 |. 74 07 JE SHORT Leonardo.0040E37E // se sono uguali salta... 0040E377 |. C605 ACD44600 >MOV BYTE PTR DS:[46D4AC],1 0040E37E |> 5D POP EBP 0040E37F \. C3 RETN |
La _strcmp non fa altro che confrontare 2 stringhe, s2 =LEONARDO con la s1, s2 =1.0 con s1 e s2 = WIZARD 1999 con s1. Voi direte: "Chi se ne frega? Ormai è fatta! Basta invertire i je in jne e il prog funziona". Questo è il risultato che ho raggiunto 2 anni fa, è un grande flop... apparentemente tutto fila liscio, finchè non apriamo
Statistiche->Estratto->Tabellone Estratti: qui i dati sono completamente sballati! Niente donne e champagne, per noi solo seghe e gazzosa! Vediamo di guadagnarci almeno un bichierino di tevernello... L'analisi è tutto, ricordatelo sempre! Cosa abbiamo in mano finora?(una gazzosa?) Sappiamo che alla riga 0040E314, il push 00487E7C (controllate quale indirizzo di memoria c'è nella vostra macchina) deve essere uguale a LEONARDO, altrimenti il prog si chiude; mmm... usiamo la stessa tecnica del flag! Riavviamo il debug per leonardo, nella finestra Hex dump (quella sotto la finestra codice) premiamo Ctrl+g (Go to) e digitiamo 00487E7C nella form di Olly. Mettiamoci un bel breakpoint memory, on write e vediamo chi va a scrivere quella serie di byte che dovrebbero essere uguali a LEONARDO. Premete f9 e vi ritroverete nel modulo cp3245mt, steppate con f8 fino a ritornare su Leonardo.
|
Dovremmo spuntare alla 401CB9. Verifichiamo che i primi byte del file tabelcinq.lot siano uguali a quello che vediamo su olly.
Parliamo dei byte alla 00487E7C -> DD 69 06 DF e così via... bene se aprite il file .\indirect\tabelcinq.lot con winhex vi accorgerete che i byte sono uguali. Già dovreste sapere che cosa succederà se premiamo f9. Vi ricordate? Noi dovremmo aspettarci la stringa "LEONARDO", ma nel file non c'è, questo significa che il file è criptato. Allora, se premiamo f9 finiremo nel punto dove il programma cercherà di decriptarlo (questo ve lo anticipo hehehe). Questa è la chiave di tutto, il punto dove le mura di Jerico crolleranno al nostro passo...
Premete F9:
2. Il Cryptex
Ecco la routine di decrypting:
55 PUSH EBP |
Tutto il decrypting è gestito dal valore in DL (XOR BYTE PTR DS:[ECX+EAX],DL). Qui mi scuso con LittleLuk e con tutti quelli che hanno letto il mio post. Ho teorizzato sul crypting/decrypting a base di XOR e poi l'ho escluso, sostenedo che era solo un esempio, che la routine di crypting/decrypting non era a base di XOR, ma realizzata con un'altro algoritmo. Ebbene, dopo averlo reversato per benino sono arrivato a questo: avevo teorizzato bene e praticato MALE!
LEA EAX,DWORD PTR DS:[ECX+488690] a questo indirizzo troviamo i byte [01 05 06, 07 03 05, 02 06 08]. Questi byte dipendono dal seriale e dal codice utente(lo dico in anticipo... poi ci arriveremo), quindi non state a controllare se sono uguali ai quelli che avete sulla vostra macchina. Noterete che il ciclo prende i primi 3 byte della chiave, elabora i byte e mette in DL il risultato, poi xora.
index = 0 -> Byte(01) , index = 1 -> Byte(05) , index = 2 -> Byte(06) , elabora con lo shl 1,CL == (CL * 2), esce dal ciclo e valorizza DL, poi decrypta il primo byte del file tabelcinq.lot con il valore in DL. Questi sono i byte che dobbiamo xorare, vi ricordate? Sono i primi byte del file tabelcinq.lot -> DD 69 06 DF 6D 1B D5 63.
XOR DD,DL = L
XOR 69,DL = E
XOR 06,DL = O
XOR DF,DL = N
XOR 6D,DL = A
XOR 1B,DL = R
XOR D5,DL = D
XOR 63,DL = O
Quale valore dovrà assumere DL perchè il byte DD xorato diventi 4C (L in esadecimale) e così via? Io ho risolto così: ho aperto Visual C++ 6 e ho dato inizio a un progetto Console. Voglio fare le cose semplici, quindi niente codice da professionista! L è uguale a 4C in esadecimale.
Quindi ho scritto questo codice:
int main(int argc, char* argv[]) for(int DL=0; DL < brutalNumber; DL++ )
|
In allegato trovate il codice ottimizzato in Visual C++ che fa un brutalforce su i primi 8 byte (LEONARDO). Si nota immediatamente una cosa molto curiosa:
XOR DD, DL = L <----- DL = 91
XOR 69,DL = E <----- DL = 2C
XOR 06,DL = O <----- DL = 49
XOR DF,DL = N <----- DL = 91
XOR 6D,DL = A <----- DL = 2C
XOR 1B,DL = R <----- DL = 49
XOR D5,DL = D <----- DL = 91
XOR 63,DL = O <----- DL = 2C
Noterete che abbiamo a che fare con una tabellina di XOR: I byte 91,2C,49 si ripetono fino alla fine del file. La routine di decrypting non fa altro che prendere i primi tre byte della chiave, giocarci un po', ottenendo così il primo valore di DL = 91 e decriptare, prendere gli altri tre, giocarci un po' e decriptare con DL = 2C e poi prendere gli ultimi 3 byte, giocarci un po' e decryptare con DL = 49, fino alla fine del file. Ricordate il LEA EAX,DWORD PTR DS:[ECX+489A7C], a questo indirizzo troviamo questi byte, [01 05 06, 07 03 05, 02 06 08].
Ora sappiamo che combina il primo cicletto: | 01 05 06 | 07 03 05 | 02 06 08 |
DL=91 | DL=2C | DL=49 |
|
La domanda è questa: Quale valore dovranno avere i primi tre byte(01, 05, 06) della chiave perchè DL sia uguale a 91?
All'uscita di questo ciclo noi SAPPIAMO che in [EBP-D],AL (andrà poi a finire in DL) ci deve essere 91. Bene, qui io non ho assolutamente reversato , ho semplicemente cambiato i valori dei primi tre byte 01,05,06 fino a che non ho ottenuto 91 in DL. Non è una cosa complessa, ricordate gli enigmi di Resident Evil? Poi l'ho fatto fino ad ottenere 2C e poi fino ad ottenere 49. Alla fine ecco la famigerata chiave: (91 = 00,07,04) (2C = 02,03,05) (49 = 00,03,06). Questa è la chiave di decrypting che dovrebbe essere scritta all'indirizzo [ECX+488690] .
Qui ragazzi ci meritiamo una serata con Eva Henger... o con Rocco Siffredi, dipende dai gusti hehehe. Le cose buttano bene, ma siamo solo alla fine della prima parte!
Capitolo 2
Ora sappiamo che abbiamo a che fare con una tabellina Xor con valori 91,2C,49. A loro volta questi tre valori vengono ottenuti da una chiave a nove cifre all'indirizzo [ECX+488690] [01 05 06, 07 03 05, 02 06 08]. Ma chi diavolo andrà mai a scrivere questi nove bytes? Squadra vincente non si cambia... Mettiamo un breakpoint memory, on write all'indirizzo 489A7C. Ricarichiamo Leonardo su Olly, nella finestra hex dump premiamo Ctrl+g(Go to) e inseriamo nella form di Olly l'indirizzo della nostra chiave tricolore(489A7C). Mettiamonici un bel breakpoint memory, on write e facciamo partire Leonardo con F9.
Dovremmo vedere questo:
Usciamo dal ciclo cliccando sul RETN e premiamo f4 e poi f8. Dovremo vedere questo:
Osservate bene dove siamo atterrati: questo è il cuore della battaglia, l'occhio del ciclone. Ho colorato le Call con il colore delle frecce.
Analizziamo un po' di codice:
|
Per non rendere molto complesso, e di lunghezza biblica questo tutorial, commenterò sono le funzioni necessarie alla realizzazione del keygen. Le call CALL Leonardo.0040DA84 e CALL Leonardo.0040D780 saranno sostituite da una semplice editbox dove noi andremo a inserire il codice utente che leggeremo dalla form di Leonardo, quella di registrazione insomma. In Pratica il Codice Utente lo lasceremo calcolare a leonardo, il mio è abc7c(Vedi immagine inizio tutorial).
Ora non ci resta che analizzare la Call CALL Leonardo.0040D630; questa call creerà la nostra chiave tricolore. Voglio ricordarvi che la chiave per cui l'algoritmo genera i valori giusti di decrypting è 00,07,04, 02,03,05, 00,03,06. Verde per 91, bianca per 2C e rossa per 49
Ecco la famigerata Call:
|
Vi fuma il cervello? Perchè non ho più commentato il secondo Ciclo? Perchè non ho capito un cavolo, oppure perchè ho gia scoperto chi è l'assassino? So chi è l'assassino naturalmente...
Il primo ciclo non fa altro che scrivere alla locazione di memoria EBP+EAX-410 (+1 ad ogni ciclo) una serie di 11111000111101010100000000000001 che saranno poi uzilizzati dal ciclo numero 2(Giallo). Qui io mi sono rotto e mi sono posizionato su MOV BYTE PTR DS:[ECX+EDX],AL e ho premuto F4 per ogni numero del seriale(11223344) e ho notato questo: prende il primo numero del seriale, lo elabora e mette il risultato in AL, che è il primo byte della chiave tricolore. Ecco i vari valori in AL ad ogni ciclo:
Seriale = 11223344
Valori in AL = 77116633
La nostra chiave tricolore |
00,07,04 | 02,03,05 | 00,03,06 |
la chiave generata con il seriale 11223344 |
07,07,01 | 01,06,06 | 03,03 |
1, 1, 2 | 2, 3, 3 | 4, 4 |
Ora anche voi SAPETE chi è l'assassino... abbiamo reversato abbastanza, è ora di aprire il Cryptex. Ma come?
Ci manca un numero, quindi il seriale è di 9 lettere, ho notato però che con le lettere non genera valori validi, ma solo numeri pari a 0! Quindi il seriale è di soli numeri.
Cancelliamo il file tabelr.lot e reinseriamo il seriale così: 112233445
Ecco la chiave generata: |
07,07,01 | 01,06,06 | 03,03,06 |
Qui mi sono fermato e ho ascoltato Welcome to Dying dei Blind Guardian, solo per riflettere un po'...
Il nostro Obiettivo è trovare quei numeri che elaborati dai 2 cicli diano la chiave tricolore... facciamo un tentativo per capire meglio l'enigma:
Chiave di decrypting |
00,07,04 | 02,03,05 | 00,03,06 |
Valori ottenuti con il seriale 112233445 |
07,07,01 | 01,06,06 | 03,03,05 |
1, 1, 2 | 2, 3, 3 | 4, 4, 5 |
Seguite i colori e lo spostamento delle cifre della chiave ottenuta dal seriale 112233445 |
00 07 04, 02 03 05, 00 03 06 |
Dannazione, ci mancano i numeri 00, 04, 02, e 06! |
X, 1, X, X, 4, 5 , X , 4 ,X |
Quali saranno? Qui la soluzione è banalissima... cancelliamo nuovamente il file tabelr.lot e lanciamo ancora leonardo.exe, inseriamo al posto del seriale 112233445 il seriale 012345678 e segnamoci i valori in AL:
Valori ottenuti con il seriale 012345678 |
04 07 01, 06 03 05, 02 00 00 |
|
0, 1, 2, 3, 4, 5, 6, 7, 8 |
Chiave di decrypting |
00 07 04, 02 03 05, 00 03 06 |
Seriale Valido per il decrypting con codice utente abc7c |
7, 1, 0, 6, 4, 5, 7, 4, 3 |
E' incredibile... proprio quando stavo per scrivere: "E' ora di donne e champagne!", mi ha fatto uno squillo una ragazza che non sentivo da mesi... So che non ci crederete mai! Sono le 20 e 10 del 3 marzo 2005, sono in pigiama e vorrei giocare a Call of Duty, per quale stramaledetta ragione dovrei scrivere che mi ha chiamato LEI?
Se mi avete seguito fin qui siete sbroccati come la Regina di Cuori in Alice nel Paese delle Meraviglie! E una volta arrivati fin qui, perchè non dare un'occhiata a come assemblare un keygen... in assembly?
Aprite il masm e caricateci dentro il sorgente keygen.asm... io vi aspetto lì.
Grazie per aver scelto Leonardo ed "in bocca al lupo".
Lo Staff di Leonardo
Un saluto a Valentino EUGENI e Mauro DONATI... siete stati originali!
DaGoN
Note finali |
Ringrazio mio padre, che all'età di 8 anni mi comprò il mio primo computer: un mitico Commodore 64! Ringrazio mia madre, che ascoltò il mio pianto e all'età di 16 anni mi comprò l'Amiga 500. Ringrazio entrambi, che all'età di 20 anni esaudirono il mio desiderio comprandomi un PC. Ringrazio me stesso, che all'età di 28 anni ascoltai i miei capricci e mi comprai un altro PC. Ringrazio Eleonora per aver letto la prima stesura del tutorial correggendo errori di ortografia e di punteggiatura. Ringrazio TUTTA la UIC e Quequero per avermi dato modo di arrivare un giorno a scrivere questo tutorial. Spero inoltre di non avervi annoiato. Alla Prossima,
DaGoN
Disclaimer |
Vorrei ricordare che il software va comprato e non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento � stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo che ogni sviluppatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.
Reversiamo al solo scopo informativo e per migliorare la nostra conoscenza del linguaggio Assembly.