Corso UIC Newbies 05 Guzura
From UIC
Corso UIC Newbies 05 Guzura
Contents |
| Infos | |
|---|---|
| Author: | Guzura |
| Email: | |
| Website: | Home page |
| Date: | 30/07/2000 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | |
Tools
- Softice oppure OllyDbg v1.10
- Una tabella dei caratteri ASCII con equivalenti in Hex
Link e Riferimenti
Questo è il Corso UIC Newbies n°05 disponibile alla pagina Corsi UIC Newbies
Introduzione
Devo proprio farla?.....Tecnicamente si, ne vale la chiarezza del tute :)))) NdQue
Notizie sul Programma
Crackme by Andreageddon
Essay
Lanciare il programma mi sembra il primo passo da fare...mmhhhhhmmmmm... Ci chiede un nome di 6 lettere e una password (non resisto devo provare un nome di 5 lettere...e becco del leim ignorante un pò la storia della mia vita) Dato che oggi sono svogliato e non ho voglia di usare solamente Sice decido di usarlo solo per individuare dove si trova lo schema di protezione e poi andare a studiarmi il disassemblato quindi digito il mio nick che è giusto di sei caratteri e una password a caso;apro Sice e imposto un bel BPX HMEMCPY esco e schiaccio Check; Sice salta fuori , F11 , F12 fino a che non vi trovate a Kernel.alloc (solitamente l' F12 successivo vi riporta al programma che ha generato il bpx, nel nostro caso il crackme), in realtà finite in una DLL del C++ (esattamente la MFC42) due F10 per uscire dalla ret e siete nel codice del crackme esattamente alla locazione :4017C0. In pratica il crackme chiama una funzione di questa DLL per prendere nome e password, ora abbiamo il punto da dove partire. Disassembliamo con IDA e andiamo a vedere la locazione per vedere quale funzione è stata utilizzata per prendere le stringhe e troviamo:
004017C0...
Bene abbiamo informazioni su cosa fà questa call e sappiamo che il secondo parametro è il buffer che riceverà i caratteri letti Un pò più sotto ci stà un'altra GetDlgItemTextA ovviamente per il seriale. La domanda da porsi è, da dove arriva il tutto (cioè questa è una call solitaria o è stata chiamata da un'altra che ha già fatto dei conti e altre pippate), possiamo aspettarci che sia solitaria perchè se guardate bene il codice sotto è chiaro che lo schema di protezione è tutto lì ma questo è un caso voluto solo dalla bontà d'animo di ANDRE' (per esempio avrebbe potuto innestarla in un'altra routine e quindi avremmo dovuto fare del backtrace, le possibilità sono infinite) In pratica ci basta risalire il codice fino a che non troviamo l'inizio della routine e iniziare l'analisi del codice, morale della favola troviamo questa roba (che vado a commentare):
00401630 push ebp
00401631 mov ebp, esp
00401633 sub esp, 0D0h // mi preparo dello spazio disponibile per metterci dei
// valori
00401639 push ebx
0040163A push esi
0040163B mov esi, ecx
0040163D push edi
0040163E mov [ebp-64h], esi
00401641 mov byte ptr [ebp-40h], 10h
... // metto nelle varie locazioni dei valori che utilizzero dopo
0040176D mov byte ptr [ebp-51h], 0DCh
00401771 mov al, 0CEh // muove in al CE
00401773 push 1Eh // nello stack 1E (max numero di caratteri che verranno
// letti)primo parametro della getdlgitemtext
00401775 mov [ebp-4Dh], al
00401778 mov [ebp-49h], al
0040177B lea eax, [ebp-88h] // carico in eax C3F79C che riceverà la stringa
// del nick
00401781 mov byte ptr [ebp-50h], 0DBh
00401785 push eax // nello stack questa locazione secondo parametro
00401786 push 3EBh terzo parametro della getdlgitemtext (dovrebbe
essere l'handle alla edit box dove si scrive il nome)
0040178B mov byte ptr [ebp-4Fh], 0DAh
... // metto nelle varie locazioni dei valori che utilizzero dopo
004017B3 mov byte ptr [ebp-43h], 0BBh
004017B7 mov byte ptr [ebp-1], 0
004017BB call j_?GetDlgItemTextA@CWnd@@QBEHHPADH@Z ; CWnd::GetDlgItemTextA(int,char *,int)
// PIGLIA IL NICK INSERITO E LO METTE NELLA LOCAZIONE INDIVIDUATA DAL SECONDO
// PARAMETRO
004017C0 lea ecx, [ebp-0D0h] ; in ecx 63F754 // ci finirà il seriale
004017C6 push 1Eh // come sopra
004017C8 push ecx // come sopra
004017C9 push 3EAh // come sopra
004017CE mov ecx, esi
004017D0 call j_?GetDlgItemTextA@CWnd@@QBEHHPADH@Z ; CWnd::GetDlgItemTextA(int,char *,int)
004017D5 xor esi, esi // azzera esi si inizzializza è ANDRE' ;)
004017D7 xor edi, edi // e due
004017D9 loc_4017D9: ; CODE XREF: .text:0040182D�j
004017D9 mov al, [ebp+esi-88h] ebp-88 contiene la locazione che punta
al nick in pratica ciclerò fra tutti i char del
nick perchè esi verrà incrementato di volta in
volta di volta in volta in eax c'è 'equivalente
in byte dle char in esame
004017E0 cmp al, 0
004017E2 jz short loc_40184A salta se è uguale a zero il carattere in
esame in pretica salto quando ho esaurito i char
del nick e incontro 00 che funge da terminatore
della stringa del nick
004017E4 mov cl, [ebp+esi-40h] // muovo in cl un valore che avevamo inizzializzato sopra
004017EB xor al, cl ; xoro al con questo
004017ED mov cl, [ebp+esi-20h] // come due righe sopra
004017F4 xor al, cl ; come due righe sopra
004017F6 mov cl, [ebp+esi-60h]
004017FD xor al, cl // terzo xor
004017FF mov bl, [ebp+edi-0D0h] muovo in bl il primo valore ASCII del
seriale alla prima ciclata poi il terzo alla
seconda poi il quinto e così via
00401806 sub bl, 30h // sottraggo un 30h
00401809 cmp bl, 9
0040180C jle short loc_401811 // se è superiore a 9h il valore in bl salto
0040180E sub bl, 7 // se non salto tolgo ancora un 7h
00401811 loc_401811: ; CODE XREF: .text:0040180C�j
00401811 mov dl, [ebp+edi-0CFh] muovo in dl il secondo valore ASCII
del seriale alla prima ciclata poi il quarto alla seconda poi il sesto e così
via
00401818 sub dl, 30h // come sopra
0040181B cmp dl, 9
0040181E jle short loc_401823
00401820 sub dl, 7
00401823 loc_401823: ; CODE XREF: .text:0040181E�j
00401823 shl bl, 4 shifta a sinistra bl di 4 aggiungendo degli zeri
esempio se prima in bl c'è 0Ah dopo l'istruzione c'è A0h;
se prima c'era B3h dopo c'è 30h (vale solo shiftando di 4
altrimenti avrei altri valori) in pratica aggiungo uno zero
alla fine occhio che se bl è B3h, dopo averlo shiftato di 4
non è B30h ma solo gli ultimi due byte quindi 30h
00401826 add dl, bl // aggiungo a dl il valore di bl
00401828 inc esi incremento esi solo una volta perchè del nick valuto
un carattere alla volta
00401829 inc edi
0040182A inc edi incremento edi in totale due volte perchè voglio
valutare terzo e quarto valore del seriale al secondo giro e
quinto e sesto al terzo ciclo di valutazione
0040182B cmp al, dl se il valore contenuto in al (che di volta in
volta è il valore hex del carattere del nick xorato) è
uguale a dl salto sopra e ricomincio con il char del nick
seguente
0040182D jz short loc_4017D9 // io qua voglio sempre saltare
0040182F mov byte ptr [ebp-1], 0FFh ; muovo in ebp-1 FF // se scazzo il serial
00401833 loc_401833: ; CODE XREF: .text:0040183D�j
00401833 mov al, [ebp+esi-88h] questo pezzo di codice serve a contare
il numero dei caratteri del nick quando scazzo
il seriale
0040183A inc esi
0040183B cmp al, 0
0040183D jnz short loc_401833
0040183F cmp esi, 6
00401842 jge short loc_401857 se non supero i 6 char col nik sono
fuori a beccare del leim
00401844 mov byte ptr [ebp-1], 0DDh se supero i 6 vado a beccare
serial errato
00401848 jmp short loc_401857
0040184A loc_40184A: ; CODE XREF: .text:004017E2�j
0040184A mov byte ptr [ebp-1], 0CCh qua ci arrivo se tutti i check
sono giusti
0040184E cmp esi, 6 // questa mi è piaciuta e la spiego dopo
E' ora del riassuntino: in pretica si prende il primo carattere del nick, lo si xora con tre valori diversi, e si tiene il valore in al, si prendono il primo e il secondo val del seriale li si manipolano e si mette il tutto in dl, si compara al con dl se tutto è ok si ricomincia con il secondo char del nick e il terzo e quarto valore del seriale (per i char del nick bisogna ricordarsi che cambiano i tre valori con cui si xora di volta in volta), se tutto va bene si controlla se il nick era lungo almeno 6 char (all'istruzione :0040184E) e qui sta una cosa che non mi aspettavo, si fa prima tutto l'algoritmo e poi si controlla se il nick era abbastanza lungo (dovreste aver capito che le verifiche si fanno in base ai valori in ebp-1 che possono essere CC,FF,DD e che vi indirizzano alle tre possibile MBoxA : giusto, sbagliato, corto), per inciso potreste mettere un nick lungo tre char, la password corrispondente, azzeccare tutti i controlli e alla fine cmq essere sbattuti fuori... Si vede bene che la password deve essere lunga il doppio del nick
Bien ora ci resta solo da trovare un algoritmo che dal nick ci permetta di risalire alla password Prima cosa, a ben guardare l'elaborazione fatta sui caratteri del nome è totalmente indipendente da quella fatta sul seriale quindi se il nostro scopo è trovare una password adeguata per il nostro nick possiamo sbattercene dei vari xor e segnarci soltanto il valore che via via sta in al prima del cmp della locazione :40182B (basta un bpx con Sice...) Con il mio nick "GuZuRa" vengono generati i seguenti valori :
per la G in al ho B9
per la u in al ho 8A
per la Z in al ho A6
per la u in al ho 88
per la R in al ho A8
per la a in al ho 9A
Bene, ora devo fare in modo che le elaborazioni sui primi due numeri del seriale diano in dl B9 e così via Per comodità riporto il pezzo di codice che manipola il seriale
sub bl, 30h
cmp bl, 9
jle short loc_401811
sub bl, 7
loc_401811:
mov dl, HexSecondoCharSeriale
sub dl, 30h
cmp dl, 9
jle short loc_401823
sub dl, 7
loc_401823:
shl bl, 4
add dl, bl
cmp al, dl
Dobbiamo subito notare una cosa la shl bl,4 impone che dopo l'istruzione bl sia uno dei seguenti valori : 00 (nel caso bl fosse 10),10 (nel caso bl fosse 01), 20, 30, 40, 50, 60, 70, 80, 90 e basta quindi siamo per forza obbligati ad avere dl uguale a 09; come lo otteniamo? Dl è ottenuto sottraendo al valore ASCII del secondo char del seriale il valore 30 quindi il char che mi interessa sarà caratterizzato dal rispettivo hex 39h che guardacaso è il carattere 9 ma c'è un piccolo inghippo che non ci permette di usare il carattere 9 come secondo nel seriale; una volta sottratto 30 viene fatto un cmp con 09 (nostro caso) quindi non saltiamo e di conseguenza togliamo ancora un 7 al valore: tenendo presente questo il char che ci interessa sarà caratterizzato da 09+30+07=40h che corrisponde al carattere "@" (carino no?) e così abbiamo risolto il secondo carattere ma anche tutti i 9 che sono presenti tra i vari valori di al Vediamo ora il primo char del seriale, ricordando la shl bl,4 possiamo optare per uno tra i seguenti valori da avere prima dell'istruzione stessa: 0B, 1B, 2B, 3B, ...,9B teorici ma se guardate bene il programma non vi permette di usare le minuscole nel seriale quindi solo alcuni delle possibili scelte sono utilizzabili ma noi cerchiamo la strada più breve da percorrere... E' ora abbastanza chiaro che il char che mi serve come primo ha equivalente hex uguale a 0B+30+07=42h (lo 07 ci va ancora perchè se avete capito cosa succede sapete che nell'algoritmo non viene tolto 07 solo se il char è 0,1,..., 8 ; da 9 in su tolgo 7); a 42h corrisponde nella tavola ASCII proprio il carattere "B" maiuscolo (tutto torna); quindi i miei primi due caratteri del seriale saranno B@ Analogamente i secondi due saranno 8A il primo generato da 08+30 (07 non viene tolto nell'algoritmo) che corrisponde al char "8" e il secondo da 0A+30+07 che corrisponde proprio ad "A" maiuscolo In questa maniera il gioco è fatto perchè
Il primo al = B9h a cui corrispondono i due char B@
Il secondo al = 8Ah a cui corrispondono i due char 8A
Il terzo al = A6h a cui corrispondono i due char A6
Il quarto al = 88h a cui corrispondono i due char 8
Il quinto al = A8h a cui corrispondono i due char A8
Il sesto al = 9Ah a cui corrispondono i due char @A
Be il giochino è chiaro quindi a GuZuRa corrisponde la password B@8AA688A8@A
Vale la pena (almeno per me) di fare un'ulteriore nota, password e nick sono elaborati in parti di codice separate che non interferiscono tra loro (nel senso che non xoro un valore coi valori dell'altro o cose simili) quindi il crackme è attaccabile anche in un altra maniera partendo dalla password per risalire poi ad un nick che genera proprio quella password (anche perchè i valori con cui xorate i char del nick sono noti) Per far questo bisogna tenere presente alcune accortezze: 1) password di partenza lunga almeno 12 char e pari (per avere un nick di sei caratteri almeno), 2) tenere presente che non è detto che il char a cui si risale sia un carattere alfanumerico (potrebbe essere un * o un ? o qualsiasi altro char ASCII), 3)se prima potevo sbattermene degli xor (mi segnavo solo il valore di al finale) ora devo xorare 3 volte, 4) è molto più facile se la password contiene solo questi char 1,2,3,4,5,6,7,8,@,A,B,C,D,E,F perchè in al troveremo sempre dei numeri Hex (anche se questa non è una limitazione effettiva)
Vediamo un esempio per chiarire; scelgo la password C@D1CEC@D1CE:
in al dovremo avere al primo giro C9 (al posto della @ l'algoritmo mette 9), al secondo giro D1, al terzo CE e così via
Diamo un'occhiata al codice e segnamoci i valori con cui viene xorato ogni char del nick e vediamo che
il primo char del serialeè xorato con 10h poi con 11h e poi con FFh
il secondo char invece con 12h,13h,FEh
il terzo con 14h,15h,FDh
il quarto con 16h,17h,FCh
il quinto con 18h,19h,FBh
il sesto con 20h,21h,FAh
(per password più lunghe dovreste segnarvi anche i valori seguenti...)
Eravamo rimasti a volere al = C9: questo valore viene ottenuto nell'algoritmo dopo tre xor con i rispettivi valori (sopra) e come ci insegna il buon Que per ottenere il valore originale ci basta rixorare per gli stessi valori quindi prendiamo C9 e lo xoriamo per 10h poi 11h poi FFh ottenendo il valore 37h a cui corrisponde il carattere ASCII "7" che sarà il primo char del nick (al contrario infatti 37 xorato con 10, 11, FF da C9 ce farà il paio con C@ del seriale...) Alla stessa maniera ottenete gli altri 5 char del nick e quindi ottenete il seguente nick 7.24+5 a cui corrisponde la password C@D1CEC@D1CE Con questo vi saluto Byez GuZuRa
Ultima cosa il KeyGenerator: può essere compilato con il tasm5 e funziona in questa maniera: intanto va bene solo per nick lunghi 6 caratteri (ma se guardate è facilmente estendibile a patto che vi cerchiate i valori con cui si xorano i char dopo il sesto...); prende un singolo carattere alla volta e vi da fuori i rispettivi due caratteri del seriale però al posto dei 9 del seriale dovrete inserire @; l'output di uscita è questo:
Nick (di 6 caratteri)
G B9 u 8A Z A6 u 88 R A8 a 9A quindi dopo ogni lettera vi appaiono i due caratteri del seriale corrispondenti
Non vi spaventate della lunghezza del programma perchè sono solo istruzioni ripetute 6 volte cambiando i valori di xor
- KeyGen5Newbies (Non lo commento perchè se avete letto questo tut e quelli di BONU$ sul tasm è una cazzata)
.STACK 100h
.DATA
messaggio DB "Nick (di 6 caratteri)",13,10,'$'
variabile DB 5
.CODE
inizio:
mov ax,SEG messaggio
mov ds,ax
mov dx,OFFSET messaggio
mov ah,09h
int 21h
// elaborazione primo char
mov ah,01h // legge un car dalla tastiera
int 21h
xor al,10h
xor al,11h
xor al,-1h
mov dl,al
shr dl,4h
cmp dl,9h
jle a1
add dl,7h
a1: add dl,30h
mov variabile[0],' '
mov variabile[1],dl
mov dl,al
shl dl,4h
shr dl,4h
cmp dl,9h
jle a2
add dl,7h
a2: add dl,30h
mov variabile[2],dl
mov variabile[3],' '
mov variabile[4],'$'
mov ax,SEG variabile
mov ds,ax
mov dx,OFFSET variabile
mov ah,09h
int 21h
// elaborazione secondo char
mov ah,01h // legge un car dalla tastiera
int 21h
xor al,12h
xor al,13h
xor al,-2h
mov dl,al
shr dl,4h
cmp dl,9h
jle b1
add dl,7h
b1: add dl,30h
mov variabile[0],' '
mov variabile[1],dl
mov dl,al
shl dl,4h
shr dl,4h
cmp dl,9h
jle b2
add dl,7h
b2: add dl,30h
mov variabile[2],dl
mov variabile[3],' '
mov variabile[4],'$'
mov ax,SEG variabile
mov ds,ax
mov dx,OFFSET variabile
mov ah,09h
int 21h
// elaborazione terzo char
mov ah,01h // legge un car dalla tastiera
int 21h
xor al,14h
xor al,15h
xor al,-3h
mov dl,al
shr dl,4h
cmp dl,9h
jle c1
add dl,7h
c1: add dl,30h
mov variabile[0],' '
mov variabile[1],dl
mov dl,al
shl dl,4h
shr dl,4h
cmp dl,9h
jle c2
add dl,7h
c2: add dl,30h
mov variabile[2],dl
mov variabile[3],' '
mov variabile[4],'$'
mov ax,SEG variabile
mov ds,ax
mov dx,OFFSET variabile
mov ah,09h
int 21h
// elaborazione quarto char
mov ah,01h // legge un car dalla tastiera
int 21h
xor al,16h
xor al,17h
xor al,-4h
mov dl,al
shr dl,4h
cmp dl,9h
jle d1
add dl,7h
d1: add dl,30h
mov variabile[0],' '
mov variabile[1],dl
mov dl,al
shl dl,4h
shr dl,4h
cmp dl,9h
jle d2
add dl,7h
d2: add dl,30h
mov variabile[2],dl
mov variabile[3],' '
mov variabile[4],'$'
mov ax,SEG variabile
mov ds,ax
mov dx,OFFSET variabile
mov ah,09h
int 21h
// elaborazione quinto char
mov ah,01h // legge un car dalla tastiera
int 21h
xor al,18h
xor al,19h
xor al,-5h
mov dl,al
shr dl,4h
cmp dl,9h
jle e1
add dl,7h
e1: add dl,30h
mov variabile[0],' '
mov variabile[1],dl
mov dl,al
shl dl,4h
shr dl,4h
cmp dl,9h
jle e2
add dl,7h
e2: add dl,30h
mov variabile[2],dl
mov variabile[3],' '
mov variabile[4],'$'
mov ax,SEG variabile
mov ds,ax
mov dx,OFFSET variabile
mov ah,09h
int 21h
// elaborazione sesto char
mov ah,01h // legge un car dalla tastiera
int 21h
xor al,20h
xor al,21h
xor al,-6h
mov dl,al
shr dl,4h
cmp dl,9h
jle f1
add dl,7h
f1: add dl,30h
mov variabile[0],' '
mov variabile[1],dl
mov dl,al
shl dl,4h
shr dl,4h
cmp dl,9h
jle f2
add dl,7h
f2: add dl,30h
mov variabile[2],dl
mov variabile[3],' '
mov variabile[4],'$'
mov ax,SEG variabile
mov ds,ax
mov dx,OFFSET variabile
mov ah,09h
int 21h
fine:
mov ah,4Ch
int 21h
END inizio
Note Finali
La morale è sempre quella fai merenda con i tarallucci che sono sempre i più buoni...
Ringraziamenti particolari vanno a tutti quelli che su #crack-it rispondono alle mie domande (un pò leim certe volte, scusatemi cercherò di migliorare)
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.
Categories: Guzura | 2000