Reversing del corso 4
tecnica usata: la magia del Druido


18/11/1999

by "BlackDruiD"

 

 

UIC's Home Page

Published by Quequero

No escape the end is near, too late, die in fear

Sto tutorial � 'na figata!!!

Give respect, 'cos the rule is blood for blood
UIC's form
Web site: http://blackdruid.cjb.net
E-mail: [email protected]
BlackDruiD, UIN 41339898, canale IRC/EFnet frequentato: #crack-it #uic
UIC's form

Difficolt�

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

 

Allegato

Il programma che mi appresto a reversare richiede la creazione di un keyfile per la registrazione


Reversing del corso #4
come usare la magia del Druido
Written by BlackDruiD

Introduzione

Allora ragazzi, il programma target � richiede la creazione di un keyfile per la registrazione. L'algoritmo di calcolo del keyfile � semplice anche se l'autore ha messo un piccolo trucco(ma molto bastardo) nel finale.

Tools usati

SoftIce 3.23

URL o FTP del programma

http://quequero.cjb.net

Essay

Allora raga, partiamo subito col reversing!!!

Eseguite il programma, entrate in softice e settate un bpx sulla funzione CreateFile.
Dal Menu Help selezionate il menu Register e vi troverete in sice. Premete F11 per uscire dalla funzione e scorrete verso l'alto la code window per dare un'occhiata ai parametri passati alla funzione CreateFile.
Come vedete sotto, la funzione CreateFile ha come primo parametro il nome del file da aprire

HANDLE CreateFile(
         LPCTSTR lpFileName, <-'Nome del file da aprire'

        // pointer to name of the file
        DWORD dwDesiredAccess,
        // access (read-write) mode
        DWORD dwShareMode,
        // share mode
        LPSECURITY_ATTRIBUTES lpSecurityAttributes,
        // pointer to security attributes
        DWORD dwCreationDistribution,
        // how to create
        DWORD dwFlagsAndAttributes,
        // file attributes
        HANDLE hTemplateFile
        // handle to file with attributes to copy
);

perci�, dato che i parametri sono passati da destra verso sinistra, l'ultimo push prima della call CreateFile sar� il nome del keyfile.

.004194AE     push ecx                  ;nome del file
.004194AF     call CreateFileA

Settate un bpx 4194AE, uscite da softice e ripetete la procedura di registrazione; se avete fatto tutto correttamente vi trovate all'indirizzo 4194AE.
Digitate 'd ecx' e vedrete il nome del keyfile (tin.key). Ora cancellate tutti i breackpoint (bc*), uscite dal sice, create un file di nome 'tin.key' nella stessa directory del programma 'quattro.exe' e scriveteci il vostro nick.
Rientrate in sice e settate un bpx ReadFile. Ripetete la procedura di registrazione e vi troverete di nuovo in sice.
F11 per uscire dalla funzione e date ancora una volta un'occhiata ai parametri passati

BOOL ReadFile(
        HANDLE hFile,
        // handle del file da leggere
        LPVOID lpBuffer,
        // indirizzo del buffer che riceve i dati
        DWORD nNumberOfBytesToRead,
        // numero dei byte da leggere
        LPDWORD lpNumberOfBytesRead,
        LPOVERLAPPED lpOverlapped
);

Ricordando che i parametri sono passati da destra verso sinistra, scoprirete che viene letto un carattere alla volta e viene copiato all'indirizzo :57F8AD.
Ora disabilitate il breakpoint e steppate(F10) fino all'indirizzo :0040130B.

.0040130B     xor ebx,ebx           ;azzera il contatore dei byte letti (max 30)
.0040130D     jmp 00401340    
;salta all'indirizzo :401340
......
......
......
.00401340     movsx eax,bl
.00401343     cmp eax,1E       
;controlla che non vengano letti pi� di 30 char
.00401346     jl 0040130F      
;salta all'inizio della routine di lettura

Se siete stati attenti vi sarete accorti che il primo carattere letto non viene salvato da nessuna parte, perci�, se ad esempio nel vostro keyfile avete inserito il nick 'BlackDruiD', il prog considerer� soltanto 'lackDruiD'.
Quindi, a meno che non volete farvi amputare il nome, editate il keyfile e come primo carattere inseritene uno a caso diverso da NULL(0x00) (io ho usato '~') in questo modo: ~BlackDruiD.
Ora analizziamo la routine di lettura del keyfile:

.0040130F      push 001
.00401311      push edi
.00401312      push dword ptr,[esi]
.00401314      call 00419048                    
;call ReadFile
.00401319      add esp,0C
.0040131C     movsx eax,bl
.0040131F      mov dl,[edi]
.00401321      mov [eax+ebp-00A0],dl    
;salva il byte letto in un buffer
.00401328      cmp byte ptr[edi],00        
   ;confronta il char letto con '00'(NULL)
.0040132B      jne 00401332                   
;salta se il char letto � diverso da NULL
.0040132D      inc byte ptr[ebp-002E]       
;incrementa il contatore dei caratteri NULL
.00401330      jmp 00401336
.00401332      mov byte ptr[ebp-002E],00        
;azzera il contatore dei caratteri NULL
.00401336      movsx ecx,byte ptr[ebp-002E]  
;sposta in ecx il valore del contatore dei NULL
.0040133A     cmp ecx,002
.0040133D     jg 00401348                                
;se ecx > 2 salta a 401348
.0040133F      inc ebx                                        
;incrementa il contatore dei caratteri letti
.00401340      movsx eax,bl
.00401343      cmp eax,1E
.00401346      jl 0040130F                                
;salta se sono stati letti meno di 30 char
.00401348      mov byte ptr[ebp-002E],00
.0040134C     xor ebx,ebx
.0040134E     jmp 00401381


Analizziamo in profondit� la routine:
la procedura si comporta in questo modo:

-Legge un byte alla volta

.0040130F push 001
.00401311 push edi
.00401312 push dword ptr,[esi]
.00401314 call 00419048
     ;call ReadFile

-salva i caratteri in un buffer

.00401321 mov [eax+ebp-00A0],dl
se digitate '? eax+ebp-A0' scoprirete che l'indirizzo del buffer � 57F88C

-controlla se il carattere letto � NULL; in caso affermativo, incrementa un contatore che si trova in [ebp-002E] altrimenti azzera il contatore.

.00401328 cmp byte ptr[edi],00
.0040132B jne 00401332
.0040132D inc byte ptr[ebp-002E]
.00401330 jmp 00401336
.00401332 mov byte ptr[ebp-002E],00


-controlla il numero di NULL letti e se � uguale a tre termina la procedura

.00401336 movsx ecx,byte ptr[ebp-002E]
.0040133A cmp ecx,002
.0040133D jg 00401348

se riguardate il passo precedente, vi renderete conto che i tre NULL devono essere consecutivi, altrimenti la routine continuer� finch� non sono stati letti 30 caratteri e il buffer conterr� (nel mio caso) 'BlackDruiDDDDDDDDDDDDDDDDDDDDD' anzich� 'BlackDruiD'

-controlla che il nick non sia pi� lungo di 30 caratteri

.0040133F inc ebx
.00401340 movsx eax,bl
.00401343 cmp eax,1E
.00401346 jl 0040130F


-salta alla seconda routine di lettura

.0040134C xor ebx,ebx
.0040134E jmp 00401381


Tutto chiaro no? avrete capito che per avere un nick valido dovete inserire tre caratteri NULL subito dopo il nick stesso, nel vostro keyfile(fatelo con un hex editor).
Ora dovreste trovarvi all'indirizzo :00401381,steppate fino a :401350, all'inizio della seconda routine di lettura del keyfile; Questa procedura si comporta esattamete come la prima,(tranne per il fatto che salva i byte letti in un buffer all'indirizzo 57F86C) e perci� non la commento.
Questa routine legge il keyfile a partire dal byte successivo ai tre NULL, dove cio� si trova il nick crittato.
Editate quindi il vostro keyfile ed inserite un numero di caratteri pari al vostro nick(per ora inserite valori casuali, poi vi spiegher� come calcolare quelli giusti), seguiti da tre NULL finali.

.00401350 push 001
.00401352 push edi
.00401353 push dwort ptr,[esi]
.00401355 call 00419048
.0040135A add esp,0C
.0040135D movsx eax,bl
.00401360 mov dl,[edi]
.00401362 mov [eax+ebp-00C0],dl
.00401369 cmp byte ptr[edi],00
.0040136C jne 00401373
.0040136E inc byte ptr,[ebp-002E]
.00401371 jmp 00401377
.00401373 mov byte ptr[ebp-002E],00
.00401377 movsx ecx,byte ptr[ebp-002E]
.0040137B cmp ecx,002
.0040137E jg 00401389
.00401380 inc ebx
.00401381 movsx eax,bl
.00401384 cmp eax,1E
.00401387 jl 00401350


Finita la seconda routine vi trovate qui:
Come potete vedere c'� una funzione alla quale viene passato l'indirizzo del buffer contenente il nick.
Se osservate il valore di ritorno noterete che restituisce la lunghezza del vostro nickname

.00401389 lea edx,[ebp-00A0]
.0040138F push edx
.00401390 call 004146D4


Ora vi trovate all'inizio della routine di verifica del keyfile

.00401395 pop ecx
.00401396 mov edx,eax       
;edx = lunghezza del nick
.00401398 xor ebx,ebx         
;azzera il contatore
.0040139A cmp dl,bl
.0040139C jle 004013C9    
;salta � stata raggiunta la fine del nick
.0040139E mov eax,ebx
.004013A0 inc eax               
;incrementa il contatore
.004013A1 movsx ecx,al
.004013A4 mov al,[ecx+ebp-00A0]       
;mette in al un carattere del nick
.004013AB movsx ecx,bl
.004013AE xor al,[ecx+ebp-00A0]       
;XORa al col carattere del nick precedente
.004013B5 movsx ecx,bl
.004013B8 cmp al,[ecx+ebp-00C0]       
;confronta al col carattere del nick crittato
.004013BF jne 004013C4                      
; salta se sono diversi
.004013C1 inc byte ptr,[ebp-002D]      
  ;incrementa il contatore dei 'confronti con successo'
.004013C4 inc ebx                              
     ;incrmenta ebx
.004013C5 cmp dl,bl
.004013C7 jg 0040139E                          
;salta all'inizio della routine
.004013C9 cmp dl,[ebp-002D]                
;verifica il numero di 'successi'
.004013CC jne 004013FE                      
;salta se sono diversi
.004013CE xor eax,eax
.004013D0 mov [000420140],eax
.004013D5 mov eax,000000001

-Analisi approfondita
- La routine di verifica del keyfile svolge le seguenti funzioni:

-Prende un carattere alla volta dal buffer del nick a partire dal secondo carattere

.004013A4 mov al,[ecx+ebp-00A0]

-esegue uno XOR tra il carattere del nick e il suo precedente

.004013AE xor al,[ecx+ebp-00A0]

-confronta il risultato dello XOR col byte del nick crittato

.004013B8 cmp al,[ecx+ebp-00C0]
se scrivete '? al' vedrete il valore del nick-crittato corretto

-incrementa un contatore se il carattere del nick crittato � corretto

.004013C1 inc byte ptr,[ebp-002D]

-esegue la routine finch� non � stata raggiunta la fine del nick

.004013C5 cmp dl,bl
.004013C7 jg 0040139E


-verifica che tutti i caratteri del nick crittato siano corretti

.004013C9 cmp dl,[ebp-002D]

-salta se il nick non � valido

.004013CC jne 004013FE

ok, 'sniffate' ogni carattere del nick-crittato facendo come vi ho detto sopra e poi editate il keyfile inserendo i valori del nick-crittato corretti;(usate un hex editor per editare il keyfile).
N.B. Notate che l'ultimo byte del nick-crittato corrisponde all'ultimo byte del nick non crittato il keyfile ha la seguente struttura:

[1 char a piacere][nickname][3 NULL][nick-crittato][3 NULL]

Ora che avete il vostro keyfile, lanciate nuovamente il programma, registratevi, clikkate sul menu 'about' e vi comparir� una messagebox che vi dir� che il prog � registrato.
A questo punto voi direte: Evvivaaaaa ce l'ho fattaaaaaa sono un master crakker!!!!!
Premete il tasto ok e troverete una brutta sorpresa..... Un'altra messagebox appare dicendo 'chiave pirata'... ma non � tutto, il peggio deve ancora venire...clikkate su ok e il pc esploder� in mille pezzi....oppure si spegner� semplicemente.

Ma cosa no ha funzionato? probabilmente, anzi, sicuramente ci deve essere un'altra routine di verifica del keyfile che viene eseguita dopo la prima messagebox. Quindi entrate in sice, disabilitate tutti i bpx e settatene uno su messageboxa Registratevi e andate a vedere nel menu about;
Ora siete in sice, premete F11 e vi comparir� la messagebox 'registrato';
premete ok e sarete di nuovo in sice, subito dopo la 'call 'MessageBoxExA' all'indirizzo :40B294.
Ora, dato che la routine che ci aspettiamo deve controllare di nuovo il keyfile, settiamo un bel bpx su 'ReadFile' e premiamo F5.
Premete F11 per uscire dalla funzione ReadFile, cancellate il bpx readfile e iniziate a steppare fino all'indirizzo :401830.
Notate niente di strano? Ebbene si, il programma rilegge tutto il keyfile eseguendo 2 routine pressoch� identiche alle prime che vi ho spiegato(differiscono nell'indirizzo in cui salvano i byte letti dal file: 57F888 per la prima routine e 57F868 per la seconda).

Ora dovreste essere all'indirizzo :401879.

.00401879 push 001
.0040187B lea edx,[ebp-007F]
     ;buffer per ReadFile
.0040187E push edx
.0040187F push dword ptr[edi]
.00401881 call 00419048
             ;call ReadFile
.00401886 add esp,0C
.00401889 mov al,[ebp-007F]
     ;carica in al il byte letto da ReadFile
.0040188C mov dl,[ebp-000A0] ;carica in dl il primo byte del nick
.00401892 xor dl,[ebp-000C0]    ;primo byte del nick XOR primo byte del nick-crypted
.00401898 cmp dl,al
.0040189A je 004018AE
             ;salta se sono uguali
.0040189C push dword ptr,[ebp+00008]
.0040189F call 004018D9
            ;call MessageBox 'chiave pirata'
.004018A4 pop ecx
.004018A5 push 000
.004018A7 push 005
.004018A9 call ExitWindowsEx
     ;esce da windows

Analisi del codice:
il codice svolge le seguenti funzioni:

-legge l'ultimo carattere del keyfile e lo salva in [ebp-007F]

.00401879 push 001
.0040187B lea edx,[ebp-007F]
.0040187E push edx
.0040187F push dword ptr[edi]
.00401881 call 00419048


-carica in al il byte letto da ReadFile

.00401889 mov al,[ebp-007F]

-carica in dl il primo byte del nick

.0040188C mov dl,[ebp-000A0]

-esegue uno XOR tra il primo byte del nick e il primo byte del nick crittato e mette il risultato in dl

.00401892 xor dl,[ebp-000C0]

-verifica l'esattezza del byte calcolato col byte del keyfile

.00401898 cmp dl,al

-visualizza la messagebox di errore se il byte non � esatto ed esce da windows

.0040189C push dword ptr,[ebp+00008]
.0040189F call 004018D9
.004018A5 push 000
.004018A7 push 005
.004018A9 call ExitWindowsEx


Avete capito bene cosa fa? Verifica che l'ultimo byte del keyfile sia uguale a:

primo-byte-nick XOR primo-byte-crypted_nick

es:
nel mio caso sar�:
        primo byte del nick: B (42 hex)
        primo byte del nick-crittato: '.'  (2E hex)
       
        42 XOR 2E = 6C ('l') -> 2� carattere del nick

il byte calcolato sar� sempre il secondo carattere del nick(o meglio,il terzo del keyfile) dato che:

        primo_crypted_nick = primo_nick XOR secondo_nick

quindi facendo l'operazione inversa:

        secondo_nick = primo_nick XOR primo_crypted_nick

esempio:

        Nick = BlackDruiD
        Crypted_nick = 2E 0D 02 08 2F 36 07 1C 2D 44
       
        ('B' XOR 'l') 42 xor 6C = 2E

quindi

        2E xor 42 = 6C

facile no?
Ora andate a completare il vostro keyfile con l'ultimo byte calcolato e provate a registrarvi
FUNZIONAAAAA!!!! W il Druido Nero!!!!

Ora vi spiegher� come realizzare un semplice keymaker in c

Per i pochi sfortunati che non avessero un compilatore c, allego il file eseguibile.

____________________________________CUT HERE___________________________________________

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void main(void){

        FILE *pFile;
        char nick[31], key[31];
        char nul[3] = {'\0','\0','\0'};
        char length,i;

        printf("Inserisci il nome\n");
        gets(nick);

        length=strlen(nick);

         //calcolo sul nick
        for(i=0; i<=length; i++){
                key[i] = nick[i] ^ nick[i+1];
        }

        //creazione del file
        if((pFile = fopen("tin.key","w+b"))== NULL) {
                printf("File error\n");
                exit(1);
        }

        //scrittura del primo carattere
        fputc('~', pFile);

        //scrittura del nick   
        fputs(nick, pFile);

        //scrittura dei 3 null
        fwrite(&nul, sizeof(nul), 1, pFile);

        //scrittura dela key
        for(i=0; i<length; i++){
                fputc(key[i],pFile);
        }

        //scrittura dei 3 null
        fwrite(&nul, sizeof(nul), 1, pFile);

        //scrittura del carattere di controllo
        fputc(nick[1],pFile);

        //chiusura del file
        fclose(pFile);

        printf("\nFile creato dal Druido Nero!!!\n");
}

Finalmente ho finito questo tutorial!!!!!
                                                                                                                 BlackDruiD

Note finali


Saluto prima di tutto TiN_MaN che ha realizzato questo crackme,
Quequero(e Gozzzilla), Ritz(che prima o poi dovr� pagarmi per tutte le magie che gli faccio), attila_hk, d4emon, sPEZIO, xOANNON(gran bel sito), [aLT255], [SandMan], baron_sam, Baneold, Nobody88, neural_noise, Insanity, AzaZ3l, Furb3t, ZeroByte, war_lock, Kill3xx, Brigante(il mio avvocato ;)), Yado, Xinner, Alor, along3x, away, BlackArrow(l'unico che � venuto a trovarmi allo smau), [H3ll], Anub|s, il mio cane, il figlio della madre di mia sorella(sei un grande), mio padre mia madre e tutti quelli che mi conoscono ;)
tutti gli amici di #crack-it e #uic
tutti i membri della UIC e della sua mailing list
tutti i membri di ringzer0

cazzo, quasi quasi i saluti son pi� lunghi del tutorial...

Disclaimer

Vorrei ricordare che il software va comprato e  non rubato(comprate il prog di TiN_Man), 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.

 
UIC's page of reverse engineering, scegli dove andare:

Home   Assembly   ContactMe   CrackMe   Links   
NewBies   News   Forum   Lezioni  
Tools   Tutorial 

UIC