Email Effects v1.06
registriamoci e scriviamo un keygen

Data

by "ZaiRoN"

 

11-03-2k+1

UIC's Home Page

Published by Quequero


Qualche mio eventuale commento sul tutorial :)))
mi stavo chiedendo: 'la perdita del titolo di founder decreta la fine della tua supremazia in questo piccolo spazio ??? :)))'
Logicamente no :))) bravo, la spiegazione è buona, magari un po' disordinata :) ma va bene :P

 

....

Home page se presente: non presente...
E-mail: [email protected]

....

Difficoltà

(Z)NewBies ( )Intermedio ( )Avanzato ( )Master

 

obiettivo? registrare il programma con un serial esatto, capire il funzionamento dell'algoritmo di generazione del seriale e infine scrivere un keygen...
scaricate qui l'allegato


email effects v1.06
registriamoci e scriviamo un keygen
 
Written by ZaiRoN

Introduzione

ho deciso di scrivere questo tute perchè penso sia un buon esercizio di reversing

Tools usati

- Windasm
- Softice
- la solita guida sulle API
- masm (o quello che più vi piace)

URL o FTP del programma

http://www.sigsoftware.com

Notizie sul programma

non ne ho la più pallida idea, anzi mi devo ricordare di disinstallarlo:P
direttamente dall'help del programma: "Email Effects is a program for getting the most out of email. With it, you can send pictures, drawings and tables with simple plain text." 

Essay

ehilà a tutti...
vista la particolarità dell'algoritmo vi consiglio di utilizzare i seriali che volta volta propongo (ovviamente è solo un consiglio;)
dopo questa piccolissima premessa possiamo iniziare.
 
parte prima: troviamo un possibile punto di attacco
 
l'impatto con il programma è stato abbastanza duro; quando ho inziato a smanettarci sopra non sapevo dove sbattere la testa, ma poi grazie ad un discreto colpo di culo (eheheh, spesso ci vuole anche questo:)) ho trovato un possibile punto d'attacco: la funzione OpenClipboard
disassembliamo il programma con windasm, apriamo la string reference e scorriamo le funzioni finchè non raggiungiamo la OPENCLIPBOARD
ma perchè proprio questa funzione? qualche volta mi è capitato di risolvere crackme che prendevano come serial il contenuto della clipboard...così mi sono detto: 'e se anche stavolta fosse così?'. vediamo insieme se è effettivamente così.
copiamo un serial qualsiasi (123456789) nella clipboard (basta evidenziare ciò che si vuole copiare e premere CTRL-C), apriamo softice (CTRL-D) e settiamo un breakpoint sulla funzione OpenClipboard (bpx openclipboard). lanciamo il proggie. sice poppa. è probabile che il sice poppi più di una volta (dipende da dove avete il collegamento al proggie), per cui vi ricordo che a noi interessa un break relativo al processo email effects quindi premiamo F5 finchè non vediamo la scritta 'Email ef' (o qualcosa di simile) in basso a destra nella finestra di softice. a questo punto premiamo F12 ed eccoci qua precisamente all'indirizzo 412E74:
 
:00412E6C   push 00000000   <-------------------- pusha l'unico parametro utile alla funzione OpenClipboard. il parametro definisce l'handle della finestra da associare alla clipboard aperta. 0 significa che l'handle è relativo al task in corso (il nostro proggie:))
:00412E6E   Call [USER32!OpenClipboard]   <------ chiamata della funzione OpenClipboard
:00412E74   test eax, eax   <-------------------- il return value della OpenClipboard viene messo in eax. eax = 1 soltanto se abbiamo copiato qualcosa nella clipboard
:00412E76   jz 00412F79   <---------------------- salta a ERRORE se la clipboard è vuota
:00412E7C   push 00000001   <-------------------- pusha l'unico parametro utile alla funzione GetClipboardData. il parametro definisce il formato del contenuto della clipboard. in questo caso il contenuto è di tipo testo
:00412E7E   Call [USER32!GetClipboardData]   <--- chiamata della funzione GetClipboardData
:00412E84   mov edi, eax   <--------------------- edi punta al contenuto della clipboard
:00412E86   test edi, edi   <-------------------- ho copiato qualcosa diverso da "" ?
:00412E88   jz 00412F73   <---------------------- si: prosegui...no: salta a ERRORE
:00412E8E   push edi   <------------------------- push dell'indirizzo che punta al contenuto della clipboard (123456789). è il parametro per la seguente chiamata alla funzione GlobalLock
:00412E8F   Call [KERNEL32!GlobalLock]   <------- locka un blocco di memoria e ritorna un puntatore al primo byte di tale blocco (il primo byte è l'1 di 123456789)
 
fin qui mi sembra tutto molto semplice. apertura della clipboard, lettura del contenuto e controllo sul contenuto della clipboard (che deve essere diverso dalla stringa vuota ""). le funzioni sono molto semplici da capire, i commenti al codice dovrebbero bastare; non sto qui a piazzarvi la loro sintassi, se volete saperne di più andate a spulciare nella API guide.
sembra proprio che siamo riusciti a trovare un possibile punto di attacco. attacchiamo:
 
parte seconda: studio dell'algoritmo
 
:00412E95   mov dword ptr [esp+04], eax   <--- eax punta al contenuto della clipboard
:00412E99   lea ecx, dword ptr [esp+14]
:00412E9D   push ecx
:00412E9E   lea eax, dword ptr [esp+0000011C]
:00412EA5   push eax
:00412EA6   push dword ptr [esp+0C]   
<------- esp+c punta ai 4 bytes che insieme formano l'indirizzo che punta al contenuto della clipboard
:00412EAA   call 00413430   <----------------- call interessante
niente da dire. entriamo (con F8) nella call 413430.
nel seguito indicherò con SRS la stringa "SIG_REG_START" e con SRE la stringa "SIG_REG_END" .
 
:0041343B   lea edi, [esp+0C]   <----------- prepara edi per le seguenti operazioni
:0041343F   mov esi, 00424C51   <----------- esi punta a SRS
:00413444   movsd   
<----------------------- sposta la double word (4 bytes, 4 caratteri:) puntata da esi ("SIG_") all'indirizzo puntato da edi; in più esegue: esi=esi+4 e edi=edi+4
:00413445   movsd   <----------------------- sposta altri 4 caratteri ("REG_") e aggiorna i registri
:00413446   movsd   <----------------------- ne sposta altri 4 ("STAR") e aggiorna
:00413447   movsw   <----------------------- sposta la word (2 bytes,"T ") e aggiorna
:00413449   lea edi, [esp+1C]   <----------- prepara edi per queste altre operazioni
:0041344D   mov esi, 00424C5F   <----------- esi punta a SRE
:00413452   movsd   
<----------------------- sposta "SIG_" nella locazione puntata da edi
:00413453   movsd   <----------------------- sposta "REG_"
:00413454   movsd   <----------------------- e infine "END "
:00413455   mov byte ptr [esp+08], 64   <--- mette da parte il valore esadecimale 64
:0041345A   jmp 0041346D   <---------------- salta:))
 
tutto ok? penso proprio di si. vengono semplicemente spostate le due stringhe SRS e SRE; è una sorta di inizializzazione in vista delle operazioni future:

:00413460   mov eax, [esp+3C]   <----------- eax punta all'i-esimo chr del serial inserito
:00413464   cmp byte ptr [eax], 53   <------ l'i-esimo chr è uguale a 'S' (0x53) ?
:00413467   jz 00413474   <----------------- si: salta...no: prosegui
:00413469   inc dword ptr [esp+3C]   <------ si sposta sul prossimo carattere
:0041346D   sub byte ptr [esp+08], 01   <--- il byte puntato da esp+08 viene decrementato di una unità
:00413472   jae 00413460   <---------------- se il valore del byte è >= 0 salta su e si passa al controllo del prossimo carattere altrimenti proseguiamo sotto
 
breve commento. a partire dal primo, ogni singolo carattere del codice viene confrontato con 'S'. se il confronto da esito positivo si salta altrove altrimenti si prosegue con i confronti che saranno al più 100 (0x64). per cui esco da questo ciclo sia nel caso in cui sia stato trovato il carattere 'S' sia nel caso in cui i primi 100 caratteri del codice sono tutti diversi da 'S'.
 
:00413474   lea ecx, [esp+0C]   <-------- ecx punta a SRS
:00413478   mov ebx, ecx   <------------- anche ebx punta a SRS
:0041347A   lea eax, [ebx+0D]   
<-------- eax punta al byte che segue l'ultimo chr della stringa SRS (0x00)
:0041347D   mov [esp+04], eax   <-------- copia eax in [esp+04]
:00413481   jmp 004134A0   <------------- salta:))
:00413483   mov edi, ebx   <------------- edi punta all'i-esimo chr di SRS
:00413485   inc ebx   <------------------ ebx punta al chr successivo (sempre di SRS)
:00413486   mov esi, [esp+3C]   <-------- esi punta al j-esimo chr del serial
:0041348A   inc dword ptr [esp+3C]   <--- si sposta sul prossimo chr del serial
:0041348E   mov dl, [esi]   <------------ dl contiene il j-esimo chr del serial
:00413490   mov al, [edi]   <------------ al contiene l'i-esimo chr di SRS
:00413492   cmp dl, al   <--------------- al = dl ?
:00413494   jz 004134A0   <-------------- si: salta giù...no: ERRORE, serial non valido
:00413496   xor eax, eax   <------------- eax=0 ci porta alla non registrazione
        ...
:0041349F   ret
:004134A0   cmp ebx, [esp+04]   <-------- ho scandito tutta la stringa SRS ? :004134A4   jb 00413483   <-------------- si: prosegui...no: salta su e controlla il prossimo carattere
 
ci siete? questo pezzo di codice ci dà le primissime basi per la costruzione del codice di registrazione. ciò che abbiamo appena visto non è altro che un ciclo la cui utilità è quella di determinare se "SIG_REG_START" è contenuto nel serial; ad ogni iterazione c'è un controllo carattere per carattere tra il generico elemento di SRS e il generico elemento del serial.
c'è di più; se integriamo questo pezzo analizzato ora con il precedente si scopre che la stringa SRS può anche essere preceduta da 100 caratteri con il vincolo però che non si presenti una cosa di questo tipo: "ukSutSIG_REG_START"
che sicuramente da errore. perchè? semplicemente perchè appena trova una 'S' parte con il confronto tra il serial e l'SRS e...ecco qua che cosa accade in questo caso specifico:
1° iterazione: confronta la 'S' di SRS con la 'S' del nostro serial. i caratteri sono uguali e si passa al prossimo.
2° iterazione: confronta la 'I' di SRS con la 'u' del nostro serial. i caratteri non sono uguali, si esce dal ciclo e
niente registrazione anche se SRS è effettivamente presente all'interno del serial.
ok, modifichiamo il serial; per comodità evito di mettere dei caratteri prima di SRS per cui il mio codice sarà semplicemente: "SIG_REG_START123A456I".
piccola annotazione: con il termine 'parte iniziale' indicherò i caratteri del nostro serial che seguono l'SRS (123A456I).
 
:004134A6   mov ebx, [esp+40]
:004134AA   lea eax, [esp+3C]   <--- eax punta ad una sequenza di 4 bytes che non è altro che l'indirizzo relativo al primo chr della parte iniziale del codice
:004134AE   push eax   <------------ lo butta in memoria
:004134AF   call 004137A0   
<------- hmmm...molto interessante
 
quest'ultima call merita un'attimo di attenzione, verrà usata spesso in quanto colonna portante di gran parte dell'algoritmo di protezione, quindi è il caso di studiarla a fondo:
 
:004137A1   sub esp, 8
:004137A4   mov ecx, [esp+10]   
<----- ecx punta ad una sequenza di 4 bytes che non è altro che l'indirizzo relativo al primo chr della parte iniziale del codice (l'1)
:004137A8   mov dl, 64   <------------ dl = 0x64 (tutti i calcoli saranno in esadecimale) :004137AA   jmp 004137BF   <---------- salta:)
:004137B0   mov eax, [ecx]   <-------- eax punta all'i-esimo chr della parte iniziale
:004137B2   mov al, [eax]   <--------- mette in al l'i-esimo chr
:004137B4   add al, BF   
<------------ al = al + 0xBF
:004137B6   mov bl, al   <------------ bl = al
:004137B8   inc dword ptr [ecx]   <--- si sposta sull'(i+1)-esimo chr della parte iniziale
:004137BA   cmp bl, 10   
<------------ bl < 0x10 ?
:004137BD   jb 004137C4   <----------- si: salta sotto...no: prosegui
:004137BF   sub dl, 01   <------------ dl = dl - 1
:004137C2   jae 004137B0   <---------- se dl >= 0 salta su, altrimenti prosegui sotto
 
prima parte di questa call. si scorre semplicemente la parte inziale del codice. ad ogni carattere viene sommato il valore esadecimale BF; se la somma è compresa tra 0xFF e 0x110 (estremi non compresi) si esce dal ciclo altrimenti se non trovo nessun carattere con questa particolarità si itera al più per 100 volte e dopo il 100° confronto l'uscita dal ciclo è forzata.
ok? speriamo di si:). finiamo la call:
 
:004137C4   mov al, bl   <------------ al = bl
:004137C6   shl al, 4   <------------- shift a sinistra di 4 bits per al
:004137C9   mov [esp+04], al   <------ muove al nella locazione puntata da [esp+04]
:004137CD   mov dl, 64   <------------ dl = 0x64
:004137CF   jmp 004137E0   <---------- salta:)
:004137D1   mov eax, [ecx]   <-------- eax punta al j-esimo chr della parte iniziale del codice
:004137D3   mov al, [eax]   <--------- al contiene il j-esimo chr della parte centrale :004137D5   add al, BF   <------------ al = al + 0xBF
:004137D7   mov bl, al   <------------ muove il contenuto di al in bl
:004137D9   inc dword ptr [ecx]   <--- si sposta sul prossimo chr
:004137DB   cmp bl, 10   <------------ bl < 0x10 ?
:004137DE   jb 004137E5   <----------- si: salta sotto...no: prosegui
:004137E0   sub dl, 01   <------------ dl = dl - 1
:004137E3   jae 004137D1   <---------- se dl >= 0 salta su, altrimenti prosegui sotto
:004137E5   or [esp+04], bl   <------- [esp+04] = [esp+04] or bl
:004137E9   mov al, [esp+04]   <------ il risultato dell'operazione or fatta sopra viene messo in al  
 
e qui si conclude la parte di codice relativa alla call 4137A0. siete riusciti a capire cosa fa? come accade nella prima parte, anche qui ad ogni carattere viene sommato il valore esadecimale BF; se la somma è compresa tra 0xFF e 0x110 (estremi non compresi) si esce dal ciclo altrimenti se non trovo nessun carattere con questa particolarità si itera al più per 100 volte e dopo il 100° confronto l'uscita dal ciclo è forzata. fin qui tutto identico a prima ma stavolta c'è dell'altro; infatti quando si esce dal ciclo viene fatta l'operazione di or tra il carattere trovato nella prima parte e quello trovato in questa seconda parte.
eccovi qua che cosa accade in dettaglio nel nostro caso:
 
- prima parte della call (4137B0/4137C9):
i primi 3 caratteri ('1', '2', '3') vengono ignorati mentre il 4° no:
'A' + 0xBF = 0x41 + 0xBF = 0x100
0x0FF < 0x100 < 0x110
per cui si esegue 'shl 0x00, 4' ottenendo 00
00 viene messo in [esp+4]
 
- seconda parte della call (4137D1/4137E9):
i caratteri '4', '5', '6' vengono ignorati mentre:
'I' + 0xBF = 0x49 + 0xBF = 0x108
0x0FF < 0x108 < 0x110 e 08 viene messo in bl
[esp+4] or bl = 0x00 or 0x08 = 0x08
 
8 è il valore esadecimale che viene messo in al e che la call ritorna indietro.
dopo l'SRS c'è quindi quello che noi abbiamo chiamato parte iniziale del serial, che non è altro che una sequenza composta da un minimo di 2 ad un massimo di 200 caratteri, su cui però non sappiamo ancora dire altro. per semplicità consideriamo la parte iniziale costituita soltanto da due caratteri.
da notare che la call esaminata prende in considerazione soltanto i caratteri compresi nel range A-P (estremi inclusi).
prima di proseguire un'altra piccola annotazione: la parte iniziale del codice è terminata, tutto quello che verrà adesso sarà identificato come 'parte centrale' (che fantasia:)). aggiungiamo quindi un pò di caratteri al nostro codice ottenendo: "SIG_REG_STARTAIFKGBGJFCGPEOGOGF" dove:
parte iniziale = "AI"
parte centrale = "FKGBGJFCGPEOGOGF"
ok, usciamo dalla call e continuiamo con l'analisi:
 
:004134B4   pop ecx   <------------- ecx punta alla parte centrale del codice
:004134B5   movzx eax, al   
<------- il contenuto di al (08) viene messo in eax (00000008)
:004134B8   add eax, ebx   <-------- eax = eax + ebx, dove ebx è un indirizzo fissato
:004134BA   mov [esp+04], eax   <--- eax viene inoltre memorizzato in [esp+04]
:004134BE   jmp 004134CE   <-------- salta:)
:004134C0   lea eax, [esp+3C]   <--- eax punta a 4 bytes che danno l'indirizzo dell'elemento corrente della parte centrale del codice
:004134C4   push eax   <------------ butta eax in memoria per la prossima call
:004134C5   call 004137A0   <------- è la call che abbiamo appena studiato
:004134CA   pop ecx   
<------------- punta al chr corrente della parte centrale
:004134CB   mov [ebx], al   
<------- il contenuto di al (che è stato modificato dalla call) viene messo nella locazione puntata da ebx
:004134CD   inc ebx   <------------- incrementa il valore di ebx (per far posto al prossimo chr)
:004134CE   cmp ebx, [esp+04]   <--- ebx < [esp+04] ?
:004134D2   jb 004134C0   <--------- si: salta su...no: prosegui
:004134D4   xor eax, eax   <-------- eax=0
:004134D6   mov [ebx], al   
<------- mette 00 nel byte puntato da ebx  
 
piccola spiegazione: questo visto ora non è altro che un ciclo che si ripete tante volte quanto è il valore di al ritornato dalla call 004137A0 all'indirizzo 4134B5 (nel nostro caso 8). tutto il succo di questo pezzetto di codice sta all'indirizzo 4134CB; ogni valore ritornato dalla call viene messo nel byte puntato da ebx. ebx contiene una sequenza di 8 caratteri generati dai caratteri della parte centrale del codice. nel nostro specifico caso la sequenza creata è: 'ZaiRoNne'.
vi riporto qua come viene ottenuto il nome 'ZaiRoNne' partendo dalla parte centrale "FKGBGJFCGPEOGOGF":
 
'F' + 0xBF = 0x105     shl 05, 4 = 0x50     'K' + 0xBF = 0x10A     0x50 or 0x0A = 0x5A = Z
'G' + 0xBF = 0x106     shl 06, 4 = 0x60     'B' + 0xBF = 0x101     0x60 or 0x01 = 0x61 = a
'G' + 0xBF = 0x106     shl 06, 4 = 0x60     'J' + 0xBF = 0x109     0x60 or 0x09 = 0x69 = i
'F' + 0xBF = 0x105     shl 05, 4 = 0x50     'C' + 0xBF = 0x102     0x50 or 0x02 = 0x52 = R
'G' + 0xBF = 0x106     shl 06, 4 = 0x60     'P' + 0xBF = 0x10F     0x60 or 0x0F = 0x6F = o
'E' + 0xBF = 0x104     shl 04, 4 = 0x40     'O' + 0xBF = 0x10E     0x40 or 0x0E = 0x4E = N
'G' + 0xBF = 0x106     shl 06, 4 = 0x60     'O' + 0xBF = 0x10E     0x60 or 0x0E = 0x6E = n
'G' + 0xBF = 0x106     shl 06, 4 = 0x60     'F' + 0xBF = 0x105     0x60 or 0x05 = 0x65 = e
 
d'ora in poi, quando ci servirà, indicherò con 'nome' la sequenza "ZaiRoNne" appena creata.
abbiamo quindi una parte centrale del codice composta da (lunghezza(nome) * n) caratteri, con 1 < n < 201. ogni carattere del nome è creato dai caratteri della parte centrale seguendo le operazioni fatte all'interno della call 4137A0. (vi ricordo che ad ogni carattere del nome corrispondono un minimo di 2 e un massimo di 200 caratteri nel codice di registrazione).
inoltre abbiamo dato un senso ai caratteri componenti la parte iniziale. infatti, se manipolati come abbiamo visto prima danno la lunghezza di nome.
come avrete già capito esiste anche una 'parte finale' del codice; ovviamente è quella che resta ancora da analizzare. ecco qua la nuova sequenza di caratteri da copiare nella clipboard: "SIG_REG_STARTAIFKGBGJFCGPEOGOGFBLPEAOEP"
dove:
parte iniziale: "AI"
parte centrale: "FKGBGJFCGPEOGOGF"
parte finale: "BLPEAOEP"
passiamo oltre che c'è ancora un bel pò di roba da guardare:

:004134D8   inc ebx   <------------- incrementa ebx
:004134D9   lea eax, [esp+3C]   <--- eax punta a 4 bytes che danno l'indirizzo dell'elemento corrente della parte finale del serial (la 'B' di "BLPEAOEP")
:004134DD   push eax   <------------ lo butta in memoria
:004134DE   call 004137A0   
<------- ancora la nostra cara call:)
:004134E3   pop ecx   <------------- ecx punta al chr corrente della parte finale (la 'P' di "PEAOEP")
:004134E4   movzx ecx, al   <------- il valore contenuto in al viene copiato in ecx
:004134E7   mov [ebp+00], ecx   <--- e copiato nella cella puntata da ebp
 
inizia l'analisi dei caratteri componenti la parte finale del codice. solita call ma stavolta il contenuto di al (1B) viene messo nella cella puntata da ebp. ecco qua come si ottiene l'esadecimale 1B partendo dalla parte finale "BLPEAOEP":
 
'B' + 0xBF = 0x101     shl 01, 4 = 0x10     'L' + 0xBF = 0x0B     0x10 or 0x0B = 0x1B
 
semplice no? bene, continuiamo:

:004134EA   lea eax, [esp+3C]   
<--- eax punta a 4 bytes che danno l'indirizzo dell'elemento non ancora visitato della parte finale (la 'P' di 'PEAOEP')
:004134EE   push eax    
:004134EF   call 004137A0   
<------- indovinate un pò? ancora lei...
:004134F4   pop ecx   <------------- ecx punta al chr corrente della parte finale (la 'A' di "AOEP")
:004134F5   movzx edx, al   
<------- al viene messo in edx
:004134F8   shl edx, 08   <--------- shift a sinistra di 8 bits per edx
:004134FB   or [ebp+00], edx   <---- fa l'or tra il valore di al calcolato dalla call all'indirizzo 4134DE con quello calcolato 4 righe sopra
 
solita storia; all'uscita dalla call al contiene il valore esadecimale F4.
vediamo però un paio di cose degne di nota: l'shl in 4134F8 e l'or in 4134FB. sono infatti studiate per fare la composizione dei due valori di al calcolati rispettivamente da 4134DE e 4134EF. vi faccio vedere con un esempio:
4134DE ritorna al = 1B, ebp punta alla sequenza di bytes 1B 00 00 00
4134EF ritorna al = F4, edx = 000000F4 e l'shl produce edx = 0000F400
infine l'or fa si che ebp punti a 1B F4 00 00
capirete fra poco il perchè di questa cosa...
 
:004134FE   lea eax, [esp+3C]   <--- eax punta a 4 bytes che danno l'indirizzo dell'elemento non ancora visitato della parte finale (la 'A' di 'AOEP')
:00413502   push eax   <------------ lo butta in memoria per la seguente call
:00413503   call 004137A0   <------- ebbene si...è sempre lei:))
:00413508   pop ecx   <------------- ecx punta al chr corrente della parte finale
(la 'E' di 'EP')
:00413509   movzx ecx, al   <------- al viene messo in ecx
:0041350C   shl ecx, 10   <--------- stavolta lo shift a sinistra è di 10 bits
:0041350F   or [ebp+00], ecx   <---- ancora un or
 
come prima shl e poi or. alla fine di queste poche righe di codice ebp punta a 1B F4 0E 00. secondo voi cosa ci sarà adesso??? bravi, indovinato!

:00413512   lea eax, [esp+3C]   
<--- come prima e prima ancora eax...(la 'E' di 'EP')
:00413516   push eax   <------------ lo butta in memoria per la seguente call
:00413517   call 004137A0   <------- vi giuro che questa è l'ultima volta che la incontriamo :)
:0041351C   pop ecx   <------------- la parte finale è finita e ecx punta al nulla:))
:0041351D   movzx eax, al   <------- al è spostato in eax
:00413520   shl eax, 18   <--------- shift a sinistra di 18 bits per eax
:00413523   or [ebp+00], eax   <---- il solito or
 
non credo abbiate bisogno di una spiegazione...ormai dovreste aver capito il gioco:)
la parte finale del codice viene divisa in 4 pezzi per formare quello strano valore puntato da ebp (1B F4 E0 4F) che chiameremo 'codifica'.
siamo quindi arrivati ad avere un codice di registrazione del tipo:
<eventuale parte inutile>SRS<parte iniziale><parte centrale><parte finale>
ok; ora possiamo continuare:

:00413526   lea edi, [esp+1C]   
<----------- edi punta all stringa SRE (SIG_REG_END)
:0041352A   mov ebx, edi   <---------------- anche ebx punta a SRE
:0041352C   lea eax, [ebx+0B]   <----------- eax punta al chr seguente la 'D' di SRE
:0041352F   mov [esp+04], eax   <----------- sposta eax in [esp+4]
:00413533   mov byte ptr [esp+08], 64   <--- mette 0x64 in [esp+8]
:00413538   jmp 0041354D   <---------------- salta
:00413540   mov eax, [esp+3C]   <----------- eax punta al resto del codice non ancora esaminato
:00413544   cmp byte ptr [eax], 53   <------ il chr in questione è 'S' ??
:00413547   jz 00413573   <----------------- si: salta...no: prosegui sotto
:00413549   inc dword ptr [esp+3c]   <------ passa al prossimo chr
:0041354D   sub byte ptr [esp+08], 01   
<--- decrementa il valore puntato da [esp+08]
:00413552   jnb 00413540   <---------------- se questo valore è >=0 salta su altrimenti prosegui sotto
:00413554   jmp 00413573   <---------------- salta
 
quello che abbiamo visto ora lo avevamo già incontrato all'inizio del tute quando si parlava del SIG_REG_START. vi ricordate? no!?! non ci credo:)) comunque sia, come prima questo è un ciclo da cui si esce o se si trova il carattere 'S' oppure se i primi 100 caratteri sono tutti diversi dalla 'S'.
cosa ci aspettiamo dal codice seguente? semplice, il contollo sulla presenza della stringa SRE nel nostro codice!!! vediamo:

:00413556   mov esi, ebx   
<------------- esi punta all'i-esimo chr dell'SRE
:00413558   inc ebx   
<------------------ si sposta sul prossimo chr dell'SRE
:00413559   mov edx, [esp+3C]   <-------- edx punta al j-esimo chr del nostro codice
:0041355D   inc dword ptr [esp+3C]   
<--- si sposta sul prossimo chr (del codice)
:
00413561   mov cl, [edx]   <------------ cl è il j-esimo chr del codice
:00413563   mov al, [esi]   
<------------ al è l'i-esimo chr dell'SRE
:00413565   cmp cl, al   <--------------- al = cl ?
:00413567   jz 00413573   <-------------- si: salta sotto...no: prosegui e vai a ERRORE
:00413569   xor eax, eax   <------------- eax = 0 ci porta alla non registrazione
        ...
:00413572   retn
:00413573   cmp ebx, [esp+04]   <-------- ho controllato tutti i chr di SRE ?
:00413577   jb 00413556   <-------------- si: prosegui sotto...no: salta su
:00413579   mov eax, 1   <--------------- eax = 1 e forse ci siamo quasi:)
come avevamo supposto il codice deve contenere anche la stringa SIG_REG_END, se si vuole preceduta da 100 caratteri purchè privi di 'S'. come detto prima tutto questo è praticamente identico al discorso fatto per l'SRS.
ecco qua il nuovo codice da copiare nella clipboard:
"SIG_REG_STARTAIFKGBGJFCGPEOGOGFBLPEAOEPSIG_REG_END".
dove:
parte iniziale = AI
parte centrale = FKGBGJFCGPEOGOGF
parte finale = BLPEAOEP
usciamo dalla call e continuiamo con il codice:
 
:00412EAF   add esp, 0C
:00412EB2   test eax, eax   
<----------------------- eax = 0 ?
:00412EB4   jz 00412F44   <------------------------- si: salta a ERRORE...no: prosegui sotto
:00412EBA   mov eax, dword ptr [esp+14]   <--------- eax contiene la sequenza di bytes che avevo chiamato codifica (EAX = 4F 0E F4 1B)
:00412EBE   push eax   <---------------------------- la butta in memoria
:00412EBF   push 00   <----------------------------- pusha anche zero
:00412EC1   lea eax, dword ptr [esp+00000120]   <--- eax punta alla sequenza che avevamo chiamato nome (la sequenza è: ZaiRoNne)
:00412EC8   push eax   <---------------------------- la butta in memoria
:00412EC9   call dword ptr [esp+00000244]   <------- call interessante
 
non mi sembra ci sia niente da dire...è semplicemente una preparazione per la call. entriamoci:
 
:00412CC4   sub esp, 00000028
:00412CC7   cmp dword ptr [esp+44], 24138D49   
<--- codifica = 24138D49 ?
:00412CCF   jz 00412CDB   <------------------------ si: salta sotto...no: prosegui
:00412CD1   cmp dword ptr [esp+44], 7B3AB458   <--- codifica = 7B3AB458 ?
:00412CD9   jnz 00412CE8   <----------------------- si: prosegui...no: salta sotto
:00412CDB   mov eax, FFFFFFFF
        ...
:00412CE7   ret
:00412CE8   cmp dword ptr [esp+40], 00000000   <--- [esp+40] = 0 ?
:00412CED   jz 00412D37   
<------------------------ si: salta sotto...no: prosegui
 
breve spiegazione: la codifica viene innanzitutto confrontata con 24138D49 e al limite con 7B3AB458.
se codifica è uguale ad uno di questi due valori il programma verrà comunque registrato ma....scusatemi...non sono riuscito a dare un significato a questi due valori. evidentemente sono associati a due nomi di registrazione particolari...ma questa è soltanto una mia ipotesi;). se volete, una volta letto tutto il tute potete provare a tirare fuori il nome associato a questi due valori e vedere se effettivamente corrispondono a due particolari nomi o se...boh:)))
la nostra codifica è però diversa da questi due valori quindi dobbiamo continuare con lo studio del serial per capire come viene generato un serial valido. per cui vediamo cosa succede all'indirizzo 412D37:
 
:00412D37   xor eax, eax   <-------------- eax = 0
:00412D39   mov esi, eax   <-------------- esi = 0
:00412D3B   push dword ptr [esp+3C]   <--- [esp+3C] punta al nome (ZaiRoNne)
:00412D3F   Call [KERNEL32!lstrlen]   <--- calcola la lunghezza del nome
:00412D45   cmp eax, 00000007   <--------- eax =< 7 ?
:00412D4A   jle 00412DA2   <-------------- si: salta e dai ERRORE...no: prosegui sotto
:00412D4C   mov eax, [esp+3C]   <--------- eax punta al nome
:00412D50   mov [esp+04], eax   <--------- anche esp+04 punta al nome
:00412D54   jmp 00412D85   <-------------- salta
allora, ci siamo, un altro tassello si aggiunge al nostro puzzle. queste poche righe infatti controllano la lunghezza della stringa da noi chiamata nome; nome deve essere composto da almeno otto caratteri.
come forse avrete già intuito nome non è altro che il nome con cui verrà registrato il programma (se il nostro seriale sarà giusto:)).
siamo quindi in grado di costruire sia la parte iniziale che la parte centrale del codice di registrazione ma... purtroppo però non abbiamo ancora finito, resta un'ultimissima cosa...come genero la parte finale del serial a partire dal nome? seguiamo il codice seguente ricordandoci che si parte dall'istruzione all'indirizzo 00412D85:
 
:00412D56   movzx eax, byte ptr [esp+27]   <--- eax punta al j-esimo carattere
:00412D5B   xor esi, eax   <------------------- esi = esi xor eax  (al primo passo esi=0)
:00412D5D   xor esi, 0000006E   <-------------- esi = esi xor 0x6E
:00412D63   mov eax, esi   <------------------- eax prende esi
:00412D65   and eax, 00000007   
<-------------- eax = eax and 0x07
:00412D6A   mov [esp+10], eax   <-------------- [esp+10] prende il contenuto di eax
:00412D6E   mov ecx, 00000020   <-------------- ecx = 0x20
:00412D73   sub ecx, eax   <------------------- ecx = ecx - eax
:00412D75   mov edx, esi   <------------------- edx prende esi
:00412D77   shr edx, cl   <-------------------- shift a destra di cl bits per edx
:00412D79   mov ecx, [esp+10]   <-------------- ecx prende il contenuto puntato da esp+10 :00412D7D   mov eax, esi   <------------------- eax prende il contenuto di esi
:00412D7F   shl eax, cl   <-------------------- shift a sinistra di cl bits per eax
:00412D81   or edx, eax   
<-------------------- edx = edx or eax
:00412D83   mov esi, edx   <------------------- esi prende edx
:00412D85   mov eax, [esp+04]   <-------------- eax punta al j-esimo carattere del nome
:00412D89   mov al, [eax]   <------------------ tale carattere viene messo in al
:00412D8B   mov [esp+27], al   
<--------------- e poi in [esp+27]
:00412D8F   inc dword ptr [esp+04]   <--------- si sposta sul (j+1)-esimo carattere del nome
:00412D93   lea eax, [esp+27]   <-------------- eax punta al j-esimo carattere
:00412D97   mov [esp+20], eax   <-------------- l'indirizzo contenuto in eax viene messo in [esp+20]
:00412D9B   cmp byte ptr [esp+27], 00   <------ il j-esimo carattere è 0 ?
:00412DA0   jnz 00412D56   <------------------- si: prosegui sotto...no: salta su
 
brevissima spiegazione: questo pezzetto di codice, preso separatamente, potrebbe benissimo essere un sottoalgoritmo di protezione basato sul nome inserito. ogni singolo carattere componente il nome viene preso e su di esso vengono fatte svariate (seppur semplici) operazioni. ciò che ci interessa è il valore contenuto in esi al termine delle iterazioni (esi = 4F 0E F4 1B). perchè esi? vediamolo insieme:
 
:00412DA2   and esi, 7FFFFFFF   <--- esi = esi end 0x7FFFFFFF
:00412DA8   mov [esp+18], esi   <--- sposta esi in [esp+18]
:00412DAC   mov edi, esi   <-------- sposta esi in edi
:00412DAE   cmp edi, [esp+44]   <--- edi = [esp+44] ?
:00412DB2   jne 00412DC0   
<-------- si: prosegui sotto...no: salta sotto
 
il contenuto di esi viene and-ato con l'esadecimale 7FFFFFFF e il risultato (4F 0E F4 1B) viene confrontato con il valore puntato da esp+44. vi ricordate cos'è contenuto in [esp+44]? no! provate a fare (ovviamente in softice) 'd esp+44'. ebbene si, è proprio lei!!, ciò che avevamo chiamato codifica. se le due cose coincidono siamo finalmente registrati. al momento della registrazione viene creata la seguente chiave nel registro di configurazione: HKEY_LOCAL_MACHINE\Software\Sig Software\Email Effects\Data
se volete fare altre prove eliminatela e il proggie ritornerà nel suo stato unregistered:))
qui termina la parte relativa al controllo del serial inserito nella clipboard.
abbiamo visto il codice che ci interessava ma forse è meglio...
 
parte terza: facciamo un breve riassuntino finale
 
da dove iniziamo? prima di tutto cerchiamo di semplificarci la vita. e come? tanto per inziare la parte che precede l'SRS verrà omessa (tanto è inutile:P); poi faremo in modo che la famosa 'call 4137A0' lavori soltanto su due caratteri evitando così di complicarci inutilmente la vita lavorando su di un numero più grande di caratteri.
fatte queste premesse eccovi qua come si compone il serial finale da copiare nella clipboard:
SIG_REG_START<parte iniziale><parte centrale><parte finale>SIG_REG_END
dove:
- SIG_REG_START
obbligatoria. questa parola chiave va messa in testa a tutto il codice
- <parte iniziale>
si compone di due caratteri. se vengono manipolati dalla 'call 4137A0' restituiscono la lunghezza del nome di registrazione
- <parte centrale>
se la lunghezza del nome di registrazione è n, questa parte di codice è composta da 2*n caratteri. se vengono manipolati dalla 'call 4137A0' restituiscono il nome di registrazione
- <parte finale>
è composta da 8 caratteri che vengono fuori dall'applicazione di un sottoalgoritmo sul nome di registrazione
- SIG_REG_END
obbligatoria. questa parola chiave va invece messa in fondo a tutto il codice
 
ok? penso di si! adesso dovremmo essere in grado di scrivere un keygen!!! infatti...
 
finalmente: keygen
 
a questo punto abbiamo tutti gli strumenti necessari alla costruzione di un keygenerator. se avete tempo e voglia provateci anche voi altrimenti nell'allegato, insieme all'eseguibile, troverete il sorgente commentato. ho usato l'assembler perchè alcune parti si possono tranquillamente rciclare dal proggie ma ovviamente potete usare il linguaggio che più vi piace;). vista la mia mediocre conoscenza dell'assembler il codice potrebbe essere ulteriormente migliorato ma...bah...prendetelo come un mio esercizio per imparare un minimo di assembler ;))))
 
e per concludere:
 
ok, abbiamo finito. cosa ne pensate? è stato facile, difficile, impossibile:))) sicuramente crackarlo sarebbe stato molto più semplice ma...ogni tanto fa bene studiarsi i vari algoritmi:)))
ho ricontrollato il tutto ma qualche errorino è sempre in agguato quindi...perdonatemi.
questo è quanto...
 
 
                                                                                                            ZaiRoN
 

Note finali

 
oh boia dè...'n ce la fò più. soltanto poche parole per salutare tutti, in particolar modo il Que ( maestro ), Iczelion (per i suoi tute sull'asm) e Pusillis (senza il suo tutorial non avrei mai scritto una riga di codice in assembler:)))
alla prossima e scrivetemi pure per commenti, suggerimenti, insulti (spero proprio di no:))...
 

Disclaimer

ovviamente il tutto è a scopo puramente didattico. vi ricordo che il software va comprato e  non rubato. finito ir periodo di valutazione se volete 'ontinuà ad usà il prodotto e vi dovete frugàààààààààà...