Corso UIC Avanzato 02 Syscalo
From UIC
Corso UIC Avanzato 02 Syscalo
Contents |
| Infos | |
|---|---|
| Author: | Syscalo |
| Email: | syscalo@tiscalinet.it |
| Website: | Home page |
| Date: | 16/09/1999 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | |
Tools
- Softice: è sufficiente questo.
- wdasm: solo per stampare parte del listato per avere qualcosa da leggere al ..... ;))
Link e Riferimenti
Questo è il Corsi UIC Avanzati n°02 disponibile alla pagina Corsi per Studenti
Introduzione
Ho pensato di impostare il tutorial nel seguente modo:
- spiegazione della generazione del seriale mantenendo solo le istruzioni necessarie.
- spiegazione del perché sono state eliminate certe istruzioni.
Questo programma richiede nome e seriale: il seriale giusto viene generato dal nome e viene confrontato direttamente con il seriale inserito che non viene modificato in alcun modo (meno lavoro per noi ;) Ma allora siete dei lavativi???? :)
Essay
Cominciamo: come anticipato ora spiegherò l'algoritmo di generazione del seriale. Alcune osservazioni:
- quando scrivo "salta alla label loc_xxxxxx" il valore xxxxxx è lo stesso che viene visualizzato in softice come indirizzo dell'istruzione a cui salterà.
- le istruzioni jg e jl sono salti condizionati per numeri con segno. È importante ricordarselo quando si eseguono i confronti.
- chr sta per carattere :)
Ecco il codice:
valore è esagerato (credo volontariamente) visto che il max di chr inseribili nel
campo nome del programma è 4
push 0040219F // locazione in cui verrà salvato il nome inserito
push dword ptr [004020D7]
call GetWindowTextA // chiamata alla funzione per acquisire il nome
xor ecx,ecx // azzera il registro ecx
loc_401215: mov al, byte ptr [ecx+0040219F] carica in al il
cod. ASCII dal 1° chr del nome
test eax, eax |
jz short loc_401279 // se il nome è terminato salta alla label loc_401279
xor al, cl // xora al con cl (che mantiene il conteggio dei chr)
mov edi, ecx // copia ecx in edi
mul edi moltiplicazione senza segno: esegue eax×edi e
salva il risultato in eax (da qui si capisce perché tutti i seriali generati
iniziano per 9: infatti edi al primo ciclo è uguale a 0 quindi "annulla"
l'effetto dell'acquisizione del 1° chr del nome azzerando eax)...quindi per Que e
Due verrà generato lo stesso codice ;))
sub al, 25h // sottrae 25h ad al
add al, cl // somma cl ad al
xor al, byte ptr [ecx+00402000] xora al con il byte
all'indirizzo 00402000+ecx: in questo modo il valore con cui vengono xorati i chr
varia per ognuno di essi. Per trovare i valori usati come maschera è sufficiente
dare in softice il comando "d 00402000" e leggere i primi 4 byte
visualizzati.(ovviamente in softice deve essere in esecuzione il file due.exe :)
add al, byte ptr [ecx+00402000] // somma ad al lo stesso valore con
cui è stato xorato
shl al, 2 // esegue 2 shift a sinistra su al
ror al, 4 esegue 4 rotazioni a destra su al (queste sono
operazioni logiche che servono a modificare un po' il valore di al, usate per
variegare un po' le istruzioni invece di avere solo add e xor ;)
sub al, 5 // sottrae 5h ad al
mov byte ptr [ecx+0040218F], al salva al alla locazione
0040218F+ecx (serve per riprendere il codice per le modifiche successive) A
inc ecx // incrementa ecx di 1 (conteggio # chr)
jmp short loc_401215 salta alla label loc_401215 (in
pratica riesegue le istruzioni precedenti fino alla terminazione del nome)
loc_401279: xor ecx, ecx // azzera ecx
loc_40127B: mov al, byte ptr [ecx+0040218F] carica in al il
valore modificato nel ciclo precedente (vedere A )
test al, al
jz loc_401331 se il nome (modificato) è terminato salta
alla label loc_401331. Alla label loc_401331 ci sono parte delle istruzioni
inutili. Queste fanno delle elaborazioni sul codice ma salvano il risultato in
locazioni di memoria che non vengono cagate per niente nel controllo finale: in
sostanza il codice generato dal nome rimane invariato! Dopo queste istruzioni si
passerà all'acquisizione del seriale da noi inserito e al controllo con il codice
generato dal nome. ( vedere X )
cmp al, 66h
jg loc_40131B confronta al con 66h e se è maggiore salta
alla label loc_40131B ( B )
loc_401291: cmp al, 30h |
jl loc_401326 confronta al con 30h e se è minore salta
alla label loc_401326 ( C )
loc_401299: inc ecx // incrementa di 1 ecx (conteggio chr)
mov byte ptr [ecx+004021A7], al salva al (eventualmente
modificato) alla locazione 004021A7+ecx (avendo incrementato ecx prima di questa
istruzione il codice generato dal nome avrà inizio dalla locazione 004021A8 che è
quella che poi viene letta al momento del confronto con il seriale inserito)
jmp short loc_40127B salta alla label loc_40217B (ripete
le istruzioni precedenti fino alla fine del nome)
loc_40131B: sub al, 12h // sottrae 12h ad al
cmp al, 66h
jg short loc_40131B se al è maggiore di 66h salta alla
label loc_40131B (in pratica continua a sottrarre 12h ad al fino a quando
diventa minore di 66h)
jmp loc_401291 riprende l'esecuzione dall'istruzione
successiva a quella che ha generato il salto a loc_40131B ( vedere B )
loc_401326: add al, 18h // somma 18h ad al
cmp al, 30h
jl short loc_401326 se al è minore di 30h salta alla
label loc_401326 (in pratica continua a sommare 18h ad al fino a quando diventa
maggiore di 30h)
jmp loc_401299 riprende l'esecuzione dall'istruzione
successiva a quella che ha generato il salto a loc_401326 ( vedere C )
Ok, la generazione del seriale è terminata. Ora spiegherò perché certe istruzioni sono state eliminate. Dovete avere sott'occhio il listato completo. Consideriamo il primo ciclo di istruzioni di elaborazione del seriale, cioè quello che inizia con la label loc_401215 e termina con l'istruzione jmp short loc_401215: in questo ciclo ci sono diverse istruzioni che modificano il registro bl (o ebx); bhe queste sono tutte inutili perché al termine del ciclo il risultato non viene salvato da nessuna parte (mentre il registro al si) ed inoltre nessuna di queste operazioni influenza il valore di al o condiziona in qualche modo il flusso del programma (per intenderci non ci sono istruzioni di controllo sul valore del registro bl che vadano ad esempio a condizionare dei salti). Dimenticavo: appena dopo la chiamata a GetWindowTextA viene effettuato un controllo sul primo chr; se questo è nullo viene visualizzato il messaggio "Wè son mica scemo!!! :)" che Que ha simpaticamente inserito per scoraggiare chiunque pensasse che il programma funzionasse anche senza codici :) (in realtà serve anche ad evitare che venga elaborato il nome se premiamo il tasto register senza inserire alcun valore nel campo nome) Per quanto riguarda il secondo ciclo (da loc_401279 a jmp short loc_40127B) questo è tutto da tenere, nessuna istruzione per confonderci ;) Il terzo ciclo invece è proprio stato creato SOLO per premere un po' di F8 in softice! Infatti, come accennato durante la spiegazione della generazione del seriale, è vero che qui vengono effettuate delle elaborazioni sul nome modificato e che vengono salvati i risultati, ma è anche vero che le locazioni di memoria dove vengono salvati, oltre a sovrascriversi a vicenda, non vengono considerate per niente dal programma quando deve effettuare il controllo per decidere se il nostro codice è buono o se siamo solo dei fannulloni che inseriscono numeri a caso sperando che funzioni ;)) Siamo arrivati al momento della verità: il superprogramma verifica la bontà del nostro seriale.
push 004021A3
push dword ptr [004020DB]
call GetWindowTextA acquisisce il seriale da noi inserito;
per vederne il cod. ASCII in softice: d 004021A3
xor ecx, ecx // azzera ecx
mov eax, dword ptr [ecx+004021A3] carica in eax il seriale
da noi inserito
mov ebx, dword ptr [ecx+004021A8] carica in ebx il seriale
generato dal nostro nome (quindi se vi interessa solo trovare il vostro seriale
arrivate fino qui e leggete il contenuto di ebx oppure usate il mio key generator
:)
inc ecx // incrementa di 1 ecx
cmp eax, ebx // confronta seriale inserito e seriale calcolato dal nome
jnz short loc_4012A2 se sono diversi salta a loc_4012A2
(visualizza "Serial sbagliato :(" )
mov al, byte ptr [ecx+004021A3] // altrimenti carica in al il 2° chr del seriale inserito
mov bl, byte ptr [ecx+004021A8] // carica in bl il 2° chr del seriale calcolato dal nome
test al, al |
jz short loc_401303 se al è uguale a 0 salta a loc_401303
(visualizza "Chiave indovinata...Complimenti!!!") (in realtà questa condizione
si verifica solo se il nome inserito è di una sola lettera (qualsiasi) e se il
seriale inserito è 9; se non capite perché proprio 9 rileggete la descrizione
della generazione del seriale)
cmp al, bl // altrimenti confronta al e bl
jnz short loc_4012A2 e se sono diversi salta a loc_4012A2
(visualizza "Serial sbagliato :(" ) (questa condizione invece non si verificherà
mai perché se arriviamo ad eseguirla vuol dire che seriale inserito e seriale
calcolato sono uguali quindi è impossibile che i secondi chr siano diversi;
credo sia stata inserita per fare in modo di fregare il cracker poco attento (e
un po' stantito...battutaccia :) che pensi di risolvere il tutto noppando i jump
precedenti :)
jmp short loc_401303 salta all'istruzione successiva
(visualizza "Chiave indovinata...Complimenti!!!")
loc_401303:// qui ci sono le istruzioni che visualizzano il messaggio "Chiave indovinata...Complimenti!!!
Ci siamo! Potete rilassarvi, è tutto finito :)
Ciao a tutti
Syscalo
Note Finali
Spero che vada tutto bene e che sia comprensibile ciò che ho scritto.
Un saluto a tutta la UIC...
...e un fuck a Tiscali che nel momento in cui scrivo non mi permette di spedire la posta e di aggiornare i ng salutandomi con un messaggio di errore originale come "You have no permission to talk. Goodbye" (almeno più innovativo di quelli di windows )
Un ringraziamento va a Int19 che si è reso disponibile per un confronto su questa lezione! Poi ti spiegherò quale era il mio problema :-{
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.