Yado Crypton v1.0
Reversing generico

Data

by active85k

 

09/11/2002

UIC's Home Page

Published by Quequero


Morireteee! Moriretee!!! Morirete tutti!!!!!! :)

 

Active sei un inno all'ottimismo oggi :PPPP cmq bravo anche questo tute e' ben fatto complimenti

Morireteee! Moriretee!!! Morirete tutti!!!!!! :)

 
E-mail: [email protected]
active85k, #crack-it
 

Difficoltà

( )NewBies (X)Intermedio ( )Avanzato ( )Master

 

Conoscete tutti Yado, no? Bene... reversiamo il suo Krypton 1.0! Reversiamo quello per due motivi: 1) perché il 2.0, per me, è davvero impossibile; 2) perché ci cercavo un tutorial sulla U.I.C. ma non ne ho trovati :D


Yado Krypton v1.0
Reversing generico
Written by active85k

Introduzione

Eccocci arrivati! Dopo un bel paio d'ore passate a reversare 'sto crackme... devo togliermi lo sfizio di scriverci un bel tutorial dettagliato! :D

Tools usati

SoftICE v4.5
FrogSICE (beh... anche se il cm è facilino... stiamo sempre parlando di Yado ;)
FileMon
Due palle cubiche con gli angoli smussati ;)

URL o FTP del programma

http://www.quequero.cjb.net

Notizie sul programma

E' un CrackMe che non richiede di inserire nessun nome o nessun serial... o almeno... non nel classico modo! Non tentate di disassemblarlo perché è polimorfe (l'ho constatato a mie spese ;). L'unica cosa che dovete fare è avete taaaaaaaaaaaaaaanta pazienza! ;) 

Essay

Si parte! Inizio col dire che non credo che nessuno abbia mai fatto un reversing simile a quello che ho fatto io! Ho usato deduzioni assurde e provenienti da mente sicuramente perversa... ma l'importante è riuscirci! Per farvi capire meglio... vi dirò quali sono tutti i passaggi che ho fatto, spiegandoli nel dettaglio! ;)
Iniziamo come sappiamo tutti: apriamo il CrackMe. Come siamo soliti, critichiamo (in bene o in male) l'interfaccia grafica e procediamo con il nostro compito! ;) Non ci sono campi! Da questo possiamo dedurre qualcosa: che per registrarlo serve o un KeyFile oppure una chiave nel registro di configurazione. Ad un certo punto, dovete essere attirati dal pulsante 'Info', altrimenti avrete delle difficoltà a registrarlo ;) Quindi, dopo aver premuto il tasto, potete rendervi conto che è inutile disasmare il proggy (anche se non ne spiega il motivo) e che c'è un piccolo 'Joke' (ahò... così lo chiama :) che serve per dirottarci e che dobbiamo evitare (anche se secondo me... ne ha messi più di uno! :). Allora, attivate il SoftICE (se non lo avete già fatto) e clicchiamo sul pulsante 'Register'. Ecco che compare il bel messaggio di errore! Quindi, le possibilità sono 2: o brekiamo su CreateFile oppure su una chiamata di registro. Ma torniamo un attimo indietro: il tasto 'Info' ci ha detto che è inutile disasmare il proggy perché c'è un piccolo trucchetto... ma, a me è venuto spontaneo e l'ho passato sotto il W32Dasm :D. Ho notato che, nella String Reference, ci sono un po' di scritte incomprensibili, mentre due si leggono perfettamente: una è "12345" e l'altra è "Software\Cripton\v1.0". Mi ha colpito una cosa: come mai solo queste si leggono? E' chiaro che questa è una chiave di registro, quindi mi son detto: << sicuramente non legge nulla dalla registry >> e sono andato direttamente sulla CreateFileA (in effetti nel registro ha creato qualcosa, ma noi non abbiamo fatto niente, quindi è veramente inutile... era questo il joke di cui parlava Yado). Apriamo il FileMon e includiamo solo il Krypton. Poi clickiamo su 'Register' e vediamo quali sono i risultati! Urrrk! Oltre al suono del messaggio... non viene letto nessun file! E allora? Se non va sul registro e non va sull'hdd... dove diamine va? Niente panico! Insistete ancora: breakate su CreateFileA e premete di nuovo il tasto di registrazione. Effettivamente il Sice poppa... e vediamo che dopo ci porta ad una MessageBox di errore! Quindi... senza dubbio... va sull'hdd! Arrivato a questo punto... ero davvero disperato, quando mi è venuto in mente il nick di Yado che mi ha fatto insospettire: e se fosse perché c'è attivato il SoftICE? E' una buona possibilità che non abbiamo preso in considerazione! Attiviamo il FrogSICE e il FileMon e clickiamo di nuovo su 'Register'. Eccolo qua! il nostro file! Si chiama YA.DO (che nome! :) Benissimo! Ci tocca creare un file con questo nome nella directory del Krypton! Se adesso cliccate su 'Register', nel FileMon, la richiesta ritorna SUCCESS, ma, nonostante questo... il crackme continua imperterrito a mandarci a cagare! ^_^ Adesso è arrivato il momento di scervellarci con un po' di assembly! Breakiamo sulla CreateFileA e analizziamo un po' di codice:

    ...
    0177:0040114E    PUSH        00
    0177:00401150    PUSH        01
    0177:00401152    PUSH        03
    0177:00401154    PUSH        00
    0177:00401156    PUSH        00
    0177:00401158    PUSH        80000000
    0177:0040115D    PUSH        00402372  Indirizzo del nome del file
    0177:00401162    CALL        KERNEL32!CreateFileA  Cahiamata
    0177:00401167    CMP         EAX, -1  Il file esiste?
    0177:0040116A    JZ          004011B3  No (salto a errore)
    0177:0040116C    MOV         [0040248B], EAX Si, file trovato
    ...

Ecco. Se il file viene trovato, il suo handle viene salvato all'indirizzo 0040248B, altrimenti, si salta ad errore (ricordate, quindi, che 004011B3 è un salto ad errore!). Una volta che l'handle del file viene messo al sicuro, vediamo come procede il programma!
 
    ...
    0177:00401171    PUSH        00
    0177:00401173    PUSH        DWORD PTR [0040248B]  Viene pushato l'handle del file
    0177:00401179    CALL        KERNEL32!GetFileSize  E ne viene calcolata la lunghezza.
    0177:0040117E    CMP         EAX, 15  Il file è grande 15h byte?
    0177:00401181    JNZ         004011B3 No (salto a errore, lo stesso errore di prima)
    ...

Arrivati a questo punto, potete tranquillamente lasciare andare il SoftICE perché il file che abbiamo creato noi non è di 15h bytes! Ecco, adesso sappiamo un'altra cosa: che il programma vuole un file che sia lungo 15h byte (15h = 21). Quindi, apriamo questo file, con qualsiasi editor, e scriviamoci dentro 21 lettere a casaccio. Ribreakiamo col SICE fino ad arrivare nuovamente al punto di prima. Adesso il programma non salterà più ad errore perché il nostro file è di 21 byte. Analizziamo quindi che cosa avviene dopo:

    ...
    0177:00401183    PUSH        00
    0177:00401185    PUSH        004023BA
    0177:0040118A    PUSH        15  Prende i primi 15h caratteri del contenuto del file
    0177:0040118C    PUSH        00402378
    0177:00401191    PUSH        DWORD PTR [0040248B]
    0177:00401197    CALL        KERNEL32!ReadFile  e li mette in 00402378
    0177:0040119C    PUSH        DWORD PTR [0040248B]
    0177:004011A2    CALL        KERNEL32!CloseHandle  Chiude l'handle del file
    ...

Da quanto abbiamo visto, possiamo capire che dobbiamo inserire un codice valido all'interno del file YA.DO e che deve essere lungo 21 caratteri. Adesso non dobbiamo fare altro che intercettare il codice finale. Per fare questo, ci vuole un po' di pazienza in quanto il nostro Yado, quel giorno, non aveva proprio niente di più divertente da fare, quindi, si è divertito (come spiegherò di seguito) con un po' di xoring! :D Prima di analizzare il codice successivo, devo chiarire qualcosina in più sullo xoring. Mettiamo in caso di dover fare uno xoring tra la lettera A (65) e la lettera C (67). Lo xoring è un'operazione logica con due parametri: restituisce 0 se i due parametri sono uguali, mentre, restituisce 1 se i due parametri sono differenti tra loro. Vediamo quindi cosa esce xorando la A con la C. La A è uguale al valore 65, mentre la C è uguale al valore 67. Quindi deriva:

    A xor C = ?
    65 xor 67 = ?

    A     1000001 xor
   
C     1000011 =
        --------------
   
?     0000010

Quindi, A xor C è uguale al binario 0000010 che è uguale a 2. Questo risultato lo chiamiamo R (da qui R = 2). Tutta 'sta storia a che serve? Beh... a livello pratico, non serve a niente, ma a livello teorico, ci permetterà di risalire al nostro codice. Non capite? Beh... è normale... ancora non abbiamo finito (voi dite, ma questo è pazzo! Sta dando i numeri! :)! Da questo, possiamo facilmente capire che lo xoring è un'operazione simmetrica. Questo significa che se A xor C = R allora A xor R = C. In poche parole, ottenuta la terza cifra, con una formula inversa, posso riottenere la prima! Infatti abbiamo:

    A     1000001 xor
   
R     0000010 =
        --------------
    ?     1000011

Come vedete, xorando la precedente A con il valore R precedentemente ottenuto, ci siamo ricavati C, il secondo parametro precedentemente utilizzato. Dopo questo spezzone di matematica, ritorniamo al nostro Krypton. Nel file che abbiamo creato, dobbiamo scrivere un codice di 21 caratteri che ci servirà per essere identificato durante l'operazione di debugging. Il codice che ci inserisco io è "La fine del krypton!!", esattamente 21 caratteri! Salvo il file e ritorno al proggyno. L'ultima istruzione che abbiamo visto è la CloseHandle, quindi, per riprendere da dove eravamo rimasti, breakiamo su CloseHandle e premiamo F11 per entrare nella procedura pricipale. Adesso dovete fare un lavoro di ricerca: steppando sempre col SiftICE, dovete andare a vedere dove viene messo il codice che abbiamo inserito nel file. Dovete steppare fino a quando, il nostro codice, non viene usato per qualcosa. Steppa qua e steppa là, arriviamo in un punto in cui, il codice, viene puntato da EAX (ci troviamo esattamente in 00401414). A questo punto ci tocca analizzare il codice assembly:

    ...
    0177:00401414    MOV         EAX, 00402378  EAX punta al nostro codice
    0177:00401419    MOV         EBX, 004023CE  EBX punta ad una stringa sconosciuta
    0177:0040141E    MOV         ECX, 0040234C  ECX punta ad un'altra stringa sconosciuta
   
...

Fin qua è chiaro! Abbiamo EAX che punta proprio al nostro codice, mentre EBX ed ECX che puntano ad altre stringhe. In pratica noi dobbiamo stare attenti ai movimenti di EAX (e derivati) e dell'offset 00402378. Una volta chiarito questo, andiamo a vedere che succede dopo (commento solo le prime due parti perché le successive sono identiche e si ripetono per tutti i caratteri del codice, quini per 21 volte :):

    ...
    0177:00401423    MOV         CL, [ECX-01]  CL assume un valore
    0177:00401426    SUB         CL, 10  CL = CL - 10h
    0177:00401429    MOV         CH, [EBX]  CH assume un altro valore
    0177:0040142B    XOR         CH, CL  CH = CH xor CL
    0177:0040142D    MOV         DH, [EAX]  DH assume l'EAXesimo carattere del nostro codice
    0177:0040142F    ADD         CL, 0D  CL assume un altro valore
    0177:00401432    XOR         DH, CL  DH = DH xor CL
    0177:00401434    CMP         CH, DH  Il carattere è valido?
    0177:00401436    JNZ         00401797  No (salta ad errore)
 
    0177:0040143C    MOV         DL, [004022B1]  Si (continua)
    0177:00401442    XOR         DL, DH
    0177:00401444    MOV         [004022E8], DL
    0177:0040144A    ADD         EAX, 01  Incrementa i puntatori al codice
    0177:0040144D    ADD         EBX, 01  e alla stringa sconosciuta

    Continua per 21 volte
    ...

Vediamo che cosa abbiamo fatto. Se osserviamo bene col debugger, arriviamo a 0040142F in cui CL assume un valore. Facendo ? CL notiamo che è uguale a 96. Andando avanti, possiamo notare che CL è sempre uguale a 96. Arriviamo poi in 00401432, dove DH (cioè uno dei caratteri del nostro codice) viene xorato con CL (sarebbe 96). In poche parole, il carattere valido dovrebbe essere DH xor 96, e questo, nel passaggio successivo, dovrebbe essere uguale a CH. In poche parole noi abbiamo:
CL = 96
CH cambia sempre (ma abbiamo anche quello)
I caratteri del nostro codice.

Quindi, per ottenere il codice finale, non dobbiamo fare altro che applicare la formula inversa dello xoring, di cui abbiamo parlato prima: Chiamiamo CV il carattere valido, CS il carattere sbagliato e CL rimane CL. Abbiamo quindi:

    CV = CS xor CL
    CV = CS xor 96

In poche parole, non dobbiamo far altro che prendere tutti e 21 i valori che CH assume man mano che passa l'algoritmo e xorarli con 96 per ottenere il carattere valido. Per ottenere tutti i valori senza saltare ad errore, basta usare il comando r per modificare il flag Zero del jump (digitare r fl z ogni volta che si incontra un salto ad errore) In questo modo, in circa 45 secondi, possiamo ricavarci il codice valido in assembly in questo modo:

    MyCode db 21 dup (?)    è il mio codice
   
Values db 87, 114, ecc...    sono i valori che CH assume ogni volta
   
RegCode db 21 dup (?)    la variabile che conterrà il giusto codice

   
    xor    ecx, ecx
   
    @@STARTLOOP:
        cmp    ecx, 22
        jz     @@ENDLOOP
        mov    al, byte ptr [Values+ecx]
        xor    al, 96
        mov    byte ptr [RegCode+ecx], al
        inc    ecx
        jmp    @@STARTLOOP
    @@ENDLOOP:
        push   offset RegCode
        push   hEdit1
        call   SetWindowText
        ret

Dove hEdit1 è l'handle di un componente Edit in cui verrà scritto il codice valido. I valori che CH assume sono 87, 114, 105, 116, 101, 89, 97, 100, 111, 89, 97, 100, 111, 64, 104, 111, 116, 109, 97, 105, 108, 46, 99, 111, 109. Xorando ognuno di questi valori con 96 si ottiene il codice finale ;) Forse come metodo è un po' assurdo, ma ne abbiamo approfittato per fare un po' di matematica e abbiamo reversato un crackme molto bello (almeno, io mi son divertito molto :). Ahhh se tutti i programmi fossero come questo! ;)
 
[active85k]

Note finali

Note finali? E boh! Ne approfitto per salutare tutta la U.I.C. Un saluto particolare va ad AndreaGeddon perché perde veramente i migliori anni della sua vita per far di me il suo miglior allievo! ;) ROTFL NdQue Spero di esser stato chiaro nella spiegazione! ;)

Disclaimer

Qui inserirete con questo carattere il vostro piccolo disclaimer, non è obbligatorio però è meglio per voi se c'è. Dovete scrivere qualcosa di simile a: 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 immane che ogni singolo programmatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.

Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.

Capitoooooooo????? Bhè credo di si ;))))