Autokeygen e Keygen per Winzip Self-Extractor 2.2

Data

by Graftal

 

14/novembre/2003

UIC's Home Page

Published by Quequero


If freedom is outlawed...

Cooooosa volevo dire? Non lo so... Ma c'ho ragione! FATTI NON PUGNETTEEE! :P grazie Graft e complimenti pure per il progetto

...only outlaws will have freedom

....

E-mail:  [email protected]
#asm, #cpu, #crack-it, #cryptorev, #focushack, #folli, #gamesradar, #graftal, #informazionelibera, #nsh, #pmode, #programming, #slipknot, #spippolatori

....

Difficoltà

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

 

Benissimo, oggi ci accingeremo a fare un semplice autokeygen per mezzo di una messagebox, toglieremo sia la schermata di errore più altre eventuali scocciature, ci analizzeremo l'algo che genera il serial e ci faremo pure un bel keygen (semplicissimo) sotto windows in C :)))


Autokeygen e Keygen per Winzip Self-Extractor 2.2
Written by Graftal
 

Allegato

 

Introduzione

Bene bene, buon giorno a tutti :) Questo è il primo tutorial che invio alla UIC e spero che sia di vostro gradimento. Oggi vedremo un po di vedere come funziona
il Winzip SE e vediamo cosa possiamo fare per prendercene gioco (ma soprattutto per imparare qualcosa di nuovo :))
Spiegherò per prima cosa come fare l'autokeygen e successivamente il keygen. Buona lettura :)))

Tools usati

I tools sono i soliti:
Ollydbg (o qualsiasi altro debugger che più vi piace)
IDA Pro (o qualsiasi altro disasm che più vi piace)
Hiew (o qualsiasi altro editor esadecimale che più vi piace)
Tenetevi pure una calcolatrice, un notepad e un po di musica vicino, non si sa mai :)

URL o FTP del programma

www.winzip.com

Notizie sul programma

Il programma in questione è utile nel caso abbiamo bisogno di farci un programma di installazione per dei file zippati che dobbiamo magari inviare a degli amici che non hanno il winzip, altri possibili utilizzi non me ne vengono in mente :)
Appena finiamo di installarlo e lo apriamo, si apre una succulenta MessageBox che ci avverte che il programma non presenta suddetto messaggio una volta registrato...ma bene bene :) Clicchiamo su ok e successivamente su Enter Registration Code e siamo pronti per leggere il tute.

Essay

Allora, per prima cosa dobbiamo trovare un punto d'attacco. In questo caso, a noi serve il momento in cui un registro in memoria contiene il serial esatto (attenti però perché solo nei programmi meno protetti i programmatori non cercano di "nascondere" il serial ai nostri occhi, e questo è uno di quelli :))) quindi diamoci da fare. Perfetto, settiamo i soliti breakpoint su GetDlgItemTextA e vediamo che il debugger poppa :) Guardiamoci quindi un po il codice per trovare il punto favorevole per fare l'autokeygen. Ci possono essere molte alternative, aggiungere una sezione al file per esempio, ma perché dovremmo andarci a complicare la vita quando possiamo semplicemente trovare un paio di istruzioni che non servono a nulla o un po di spazio libero? :)
Io ho trovato questo (ci troviamo all'offset 95AA):
 
 
:00409F99 lea eax, [ebp+var_104]
:00409F9F push eax
:00409FA0 push offset byte_43E640
:00409FA5 call sub_409D1E
:00409FAA push offset byte_43E520 ; Noi siamo qua
:00409FAF lea eax, [ebp+var_104]
:00409FB5 push eax
:00409FB6 call __strcmpi
:00409FBB pop ecx
:00409FBC pop ecx
:00409FBD neg eax
:00409FBF sbb eax, eax ;almeno fino a qui è tutto inutile
:00409FC1 inc eax ;quindi possiamo modificare tutto

Come vedete, ci troviamo giusto giusto sotto una call (attenzione perché quella call è fondamentale, quindi non fateci pasticci!). Apriamo il nostro hiew, F5 e scriviamo l'offset (95AA), quindi F3. Ora scrivete gli opcode che seguono:

opcode ------------- azione
6A20            push 20h ;pusha lo stile della msgbox, in questo caso è un MB_OK e un MB_ICONASTERISK
50              push eax ;pusha il titolo della msgbox
50              push eax ;pusha il testo della msgbox
FF7508          push d,[ebp][00008] ;pusha l'hWnd
FF1574234200    call MessageBoxA ;chiama la msgbox :)
--------------------------------------------

E' di vitale importanza che facciate attenzione a ciò che trovate, perché dovete noppare una istruzione (che ora vi segnalo all'interno del codice):

:00409F99 lea eax, [ebp-104h]
:00409F9F push eax
:00409FA0 push offset byte_43E640
:00409FA5 call sub_409D1E
:00409FAA push 20h
:00409FAC push eax
:00409FAD push eax
:00409FAE push dword ptr [ebp+8]
:00409FB1 call ds:MessageBoxA
:00409FB7 push ebp
:00409FB8 push ebp
:00409FB9 add [eax], eax ;noppiamo questo!!!!!!!!
:00409FBB pop ecx
:00409FBC pop ecx
:00409FBD neg eax
:00409FBF sbb eax, eax
:00409FC1 inc eax

Ocio quindi  all'offset 95B9 ke senno da errore! :) Perfetto, possiamo ora testare la nostra "creatura" :) Scriviamo un User e un serial a caso e vediamo ke ci poppa la nostra msgbox con il seriale giusto! EVVAI! Ma...hehe, gia, non è ancora mica finita! Io penso sia davvero poco professionale, non trovate? Prima di tutto, vediamo di zittire quella msgbox di errore: non andiamo a trovare il salto ke ci porta alla msgbox, semplicemente CANCELLIAMOLA! (mi è sempre piaciuta la forza bruta :) Come? Prima di tutto dopo che abbiamo inserito user e serial, steppiamo fino a quando non troviamo la call dove sta la masgbox, e piano piano entriamo nella call e analizziamo di nuovo il tutto, finché non la troviamo. Ecco quindi che ci troviamo all'offset 9940: noppate tutto di sana pianta (ci vanno 6 nop ;) Eccovi il codice:

:0040A32E push 10h
:0040A330 push 0
:0040A332 push 12FCh
:0040A337 call sub_406CC7
:0040A33C push eax
:0040A33D push [ebp+arg_0]
:0040A340 call ds:MessageBoxA ;noppiamolo!

Ora però, andiamo a provare. Vediamo che la msgbox di errore non compare, perfetto! Si ma, uff, dopo 3 volte che sbagliamo, ci esce e dobbiamo rientrare nella finestra che chiede il serial... Vediamo di farla finita una volta per tutte. Andiamo all'offset 9958 (cioe subito dopo la msgbox di errore ke abbiamo appena cancellato) e vediamo di cambiare il jnz in un jmp. Infatti se fate attenzione, vediamo che compara una varaibile (che si incrementa ogni volta che sbagliamo serial) con il numero 3: se sono uguali ci chiude la finestra :) Ecco qua, abbiamo terminato (o quasi :)! Ora andiamo a farci il patcher, pelandroni! :) Ho messo qui il sorgente, voi fateci le modifiche che volete. Io l'ho compilato con dev-cpp 4.8 e va alla grande, comunque la sostanza è questa.

----------------------------cutehere-----------------------------------------
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define NOP 0x90
#define JMP 0xEB
#define PUSH_EAX 0x50
#define PUSH_6A 0x6A
#define PUSH_20 0x20
#define HWinDFF 0xFF
#define HWinD75 0x75
#define HWinD08 0x08
#define MSGBOXAFF 0xFF
#define MSGBOXA15 0x15
#define MSGBOXA74 0x74
#define MSGBOXA23 0x23
#define MSGBOXA42 0x42
#define MSGBOXA00 0x00
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
FILE *fl_open;
char *s,*k;
long z,a;
if (!(fl_open=fopen("WZIPSE32.EXE","rb")))
{
MessageBox(0, "Non posso aprire il file", "Errore", MB_OK + MB_ICONHAND);
exit(0);
}
fseek(fl_open,0,SEEK_END);
z=ftell(fl_open);
fseek(fl_open,0,SEEK_SET);
s=k=(char*)malloc(z);
if (!k)
{
MessageBox(0, "Non posso allocare la memoria", "Errore", MB_OK + MB_ICONHAND);
exit(0);
}
while (!feof(fl_open))*(s++)=fgetc(fl_open);
*(k+0x95AA)=PUSH_6A;
*(k+0x95AB)=PUSH_20;
*(k+0x95AC)=PUSH_EAX;
*(k+0x95AD)=PUSH_EAX;
*(k+0x95AE)=HWinDFF;
*(k+0x95AF)=HWinD75;
*(k+0x95B0)=HWinD08;
*(k+0x95B1)=MSGBOXAFF;
*(k+0x95B2)=MSGBOXA15;
*(k+0x95B3)=MSGBOXA74;
*(k+0x95B4)=MSGBOXA23;
*(k+0x95B5)=MSGBOXA42;
*(k+0x95B6)=MSGBOXA00;
*(k+0x95B9)=NOP;
*(k+0x95BA)=NOP;
*(k+0x9864)=JMP;
*(k+0x98A0)=JMP;
*(k+0x9940)=NOP;
*(k+0x9941)=NOP;
*(k+0x9942)=NOP;
*(k+0x9943)=NOP;
*(k+0x9944)=NOP;
*(k+0x9945)=NOP;
*(k+0x9958)=JMP;
if (!(fl_open=fopen("WZIPSE32Crk.exe","wb")))
{
MessageBox(0, "Non posso creare il file", "Errore", MB_OK + MB_ICONHAND);
exit(0);
}
for (a=0;a<z;a++)
fputc(*(k++),fl_open);
fflush(NULL);
fclose(fl_open);
MessageBox(0, "Crack completato con successo!", "Congratulazioni!!", MB_OK + MB_ICONASTERISK);
free(fl_open);
exit(0);
}
---------------------------------------cuthere-------------------------------
 

Devo dire ke l'ho fatto un po "alla mia", nel senso che ho un gusto particolare nel fare i sorgenti, quindi modificatevelo quanto vi pare, la sostanza, come dicevo prima, rimane la stessa! :) Attenzione perché il patcher e il file originale vanno nella stessa cartella e soprattuto il file WZIPSE32Crk.exe che viene creato, lo dovete rinominare in WZIPSE32.exe perché funzioni!

Ok, direi che la prima parte del tutorial è fatta, passiamo quindi a crearci il keygen! :))

Allora, questa volta abbiamo ovviamente un approccio diverso da prima, e invece di andare a trovare un punto in cui il programma fa qualcosa di inutile (o proprio non fa nulla :)) andiamo ad analizzarci tutto l'algo che genera il serial :)
Mettiamo nuovamente i breakpoint su GetDlgItemTextA e analizziamo il codice che ci compare una volta che il debugger poppa:

:0040A1D7 call ds:GetDlgItemTextA ;qui prende l'username

--------snip----tanto non ci interessa------

:0040A22F call ds:GetDlgItemTextA ;qui invece il serial da noi immesso

-------snip----tanto non ci interessa di nuovo :)------

Arriviamo invece al primo vero check:

:0040A260 pop ecx
:0040A261 cmp eax, 8
:0040A264 jnz short loc_40A296

Che cosa fa qui? semplicemente prende il nostro serial e lo compara con 8: se sono uguali (se l'user insomma è lungo 8 caratteri) ci fa comparire una messagebox di errore che ci avvisa del fatto che il serial di winzip e di winzip SE sono diversi (il serial di winzip è lungo 8 caratteri, quello di winzip SE invece 6 :)). A questo punto quindi, attenti a mettere un serial più corto o più lungo. Avvenuto il salto, vediamo cosa troviamo:

:0040A2FC movzx eax, byte_43E640
:0040A303 test eax, eax
:0040A305 jnz short prima_della_call ;qui c'è un altro dei check, saltiamo alla label da me rinominata prima_della_call :)
:0040A307 movzx eax, byte_43E520
:0040A30E test eax, eax
:0040A310 jz short loc_40A369
:0040A312 ;arriviamo quindi qui
:0040A312 prima_della_call: ; CODE XREF: sub_40A09E+267j
:0040A312 push 0
:0040A314 call sub_409F35 ;call FONDAMENTALE :)
:0040A319 test eax, eax
:0040A31B jnz short loc_40A369

Ora entriamo nella call che ci porta a 409F35 e dobbiamo un po vedere come muoverci...Analizzando un po il codice iniziale vediamo che sono tutti dei check (molti inutili e ripetitivi, come troverete anche più avanti nell'algo) e arriviamo ad una call...Proprio quello che cercavamo:

:00409FA5 call sub_409D1E

Entriamoci e vediamo che sorprese ci aspettano :) Inizialmente ci sono un po di call e check vari, l'unica cosa davvero fondamentale qui è che il nostro user viene salvato in lowercase (con tutte le lettere minuscole insomma, e qui c'è una grande differenza, perché voi ovviamente sapete che il codice ascii di una lettera maiuscola e diversa da una minuscola :)). Ecco quindi che ci troviamo di fronte al nostro primo loop, analizziamolo:

:00409D66 mov eax, [ebp+var_4]
:00409D69 inc eax
:00409D6A mov [ebp+var_4], eax
:00409D6D
:00409D6D loc_409D6D: ; CODE XREF: sub_409D1E+46j
:00409D6D mov eax, [ebp+var_4]
:00409D70 movzx eax, byte ptr [eax]
:00409D73 test eax, eax
:00409D75 jz loc_409DFB
:00409D7B cmp cchMultiByte, 1
:00409D82 jle short loc_409D9F
:00409D84 push 103h ; int
:00409D89 mov eax, [ebp+var_4]
:00409D8C movzx eax, byte ptr [eax]
:00409D8F push eax ; int
:00409D90 call __isctype
:00409D95 pop ecx
:00409D96 pop ecx
:00409D97 mov [ebp+var_118], eax
:00409D9D jmp short loc_409DBA
:00409D9F ; ---------------------------------------------------------------------------
:00409D9F
:00409D9F loc_409D9F: ; CODE XREF: sub_409D1E+64j
:00409D9F mov eax, [ebp+var_4]
:00409DA2 movzx eax, byte ptr [eax]
:00409DA5 mov ecx, dword_427710
:00409DAB movzx eax, word ptr [ecx+eax*2]
:00409DAF and eax, 103h
:00409DB4 mov [ebp+var_118], eax
:00409DBA
:00409DBA loc_409DBA: ; CODE XREF: sub_409D1E+7Fj
:00409DBA cmp [ebp+var_118], 0
:00409DC1 jz short loc_409DF6
:00409DC3 mov eax, [ebp+var_4] ;per noi, il loop comincia da qui, perché il resto non ci interessa :)
:00409DC6 movzx eax, byte ptr [eax] ;mette la prima lettera dell'user
:00409DC9 movzx ecx, [ebp+var_114] ;mette la sua posizione all'interno dell'username
:00409DD0 imul eax, ecx ;li moltiplica con risultato in eax
:00409DD3 mov cx, [ebp+var_110] ;il risultato...
:00409DDA add cx, ax ;...viene aggiunto in cx...
:00409DDD mov [ebp+var_110], cx ;...per essere poi messo in una variabile (di vitale importanza :))
:00409DE4 mov ax, [ebp+var_114] ;ora incrementa ax in modo che alla prossima moltiplicazione...
:00409DEB add ax, 1 ;...ci sia la posizione successiva della lettera all'interno dell'username...
:00409DEF mov [ebp+var_114], ax ;...e quindi salva il tutto...
:00409DF6
:00409DF6 loc_409DF6: ; CODE XREF: sub_409D1E+A3j
:00409DF6 jmp loc_409D66 ;ricomincia il ciclo :)

Ok, per essere maggiormente chiaro vorrei ripetere tutta questa prima parte in modo un po più concreto, usando degli esempi. Noi abbiamo come username "graftal" (attenti eh, lowercase), vediamo cosa fa il prog: prende la prima lettera (la "g"), prende la sua posizione all'interno dell'username (è la prima lettera, quindi prende il numero 1); ora li moltiplica e il risultato lo AGGIUNGE in una variabile. Incrementa l'indice per passare alla seconda lettera e per fare quindi la moltiplicazione tra "r" (2° lettera) e 2 (perché è questa la sua posizione nell'username). In poche parole, moltiplica il carattere e il suo indice e aggiunge il risultato in una variabile, semplice no? :))) Teniamo d'occhio la variabile nella quale i vari risultati sono aggiunti perché come dicevo nel codice commentato, è di vitale importanza. Ora non pensiate sia finita eh, abbiamo da analizzare la seconda e ultima parte dell'algo :)

:00409E10 loc_409E10: ; CODE XREF: sub_409D1E+167j
:00409E10 mov eax, [ebp+var_4]
:00409E13 inc eax
:00409E14 mov [ebp+var_4], eax
:00409E17 .text:00409E17 loc_409E17: ; CODE XREF: sub_409D1E+F0j
:00409E17 mov eax, [ebp+var_4]
:00409E1A movzx eax, byte ptr [eax]
:00409E1D test eax, eax
:00409E1F jz short loc_409E87
:00409E21 cmp cchMultiByte, 1
:00409E28 jle short loc_409E45
:00409E2A push 103h ; int
:00409E2F mov eax, [ebp+var_4]
:00409E32 movzx eax, byte ptr [eax]
:00409E35 push eax ; int
:00409E36 call __isctype
:00409E3B pop ecx
:00409E3C pop ecx
:00409E3D mov [ebp+var_11C], eax
:00409E43 jmp short loc_409E60
:00409E45 ; ---------------------------------------------------------------------------
:00409E45
:00409E45 loc_409E45: ; CODE XREF: sub_409D1E+10Aj
:00409E45 mov eax, [ebp+var_4]
:00409E48 movzx eax, byte ptr [eax]
:00409E4B mov ecx, dword_427710
:00409E51 movzx eax, word ptr [ecx+eax*2]
:00409E55 and eax, 103h
:00409E5A mov [ebp+var_11C], eax
:00409E60 .text:00409E60 loc_409E60: ; CODE XREF: sub_409D1E+125j
:00409E60 cmp [ebp+var_11C], 0
:00409E67 jz short loc_409E85
:00409E69 push 1021h ;da qui comincia il vero loop: anche questo valore (che chiameremo "mask") è importante, è usato nella call dopo
:00409E6E mov eax, [ebp+var_4] ;prende l'username
:00409E71 movzx ax, byte ptr [eax] ;prende la prima lettera in AX, attenti!
:00409E75 push eax
:00409E76 push [ebp+var_8]
:00409E79 call sub_409ECF ;una call che analizzeremo di seguito e che è importantissima
:00409E7E add esp, 0Ch
:00409E81 mov word ptr [ebp+var_8], ax
:00409E85
:00409E85 loc_409E85: ; CODE XREF: sub_409D1E+149j
:00409E85 jmp short loc_409E10 ;riparte il loop

Ok, qui non fa molto come potete vedere, è infatti quella call a 409ECF che è importantissima: salto la parte prima del loop e ve la spiego qua a parole, perché fa praticamente una sola cosa: shifta il carattere dell'username preso prima di 8 verso sinistra (shl carattere, 8 ;in asm) e cosi se prima avevamo in ax "67" ora abbiamo "6700". Perfetto, passiamo al loop:

:00409ECF push ebp
:00409ED0 mov ebp, esp
:00409ED2 push ecx
:00409ED3 mov ax, [ebp+arg_4] ;mette il primo carattere dell'user in ax (se è la prima volta che viene eseguito il loop, se è la seconda allora è il secondo carattere dell'user che viene messo in ax ecc)
:00409ED7 shl ax, 8 ;shifta il carattere di 8, in modo da avere in ah il carattere e 00 in al
:00409EDB mov [ebp+arg_4], ax ;salva ax e poi si comincia il vero loop da 409EE5
:00409EDF and [ebp+var_4], 0
:00409EE3 jmp short loc_409EEC
:00409EE5 ; ---------------------------------------------------------------------------
:00409EE5
:00409EE5 loc_409EE5: ; CODE XREF: sub_409ECF+5Ej
:00409EE5 mov eax, [ebp+var_4] ;questa parte viene saltata la prima volta...
:00409EE8 inc eax ;qui incrementa l'indice...
:00409EE9 mov [ebp+var_4], eax ;...e lo salva :)
:00409EEC
:00409EEC loc_409EEC: ; CODE XREF: sub_409ECF+14j
:00409EEC cmp [ebp+var_4], 8 ;lo compara quindi con 8...in pratica è un loop che si ripete per 8 volte...
:00409EF0 jge short loc_409F2F ;se siamo arrivati a 8, allora esci dal loop e vai a 409F2F dove si esce dalla call
:00409EF2 movzx eax, [ebp+arg_0] ;prende una variabile che nel keygen noi chiameremo "value"
:00409EF6 movzx ecx, [ebp+arg_4] ;ora prende il carattere (che nel keygen si chiamerà "ch") che nelle istruzioni seguenti verra manipolato molto :)
:00409EFA xor eax, ecx ;li xorra con risultato in eax (nel keygen creeremo una variabile per questo e la chiameremo "eax")
:00409EFC and eax, 8000h ;ora fa un and tra eax e 8000h...
:00409F01 test eax, eax ;...se fa 0...
:00409F03 jz short loc_409F17 ;...allora saltiamo a 409F17...
:00409F05 movzx eax, [ebp+arg_0] ;altrimenti prende "value" (la variabile di prima)...
:00409F09 shl eax, 1 ;...la raddoppia grazie al shift left di 1...
:00409F0B movzx ecx, [ebp+arg_8] ;...ora prende la "mask" che vale 1021h dal ciclo che abbiamo analizzato prima...
:00409F0F xor eax, ecx ;...li xorra con risultato in eax...
:00409F11 mov [ebp+arg_0], ax ;ora seleziona solo la word del risultato di prima, in C sarebbe eax &= 0xFFFF;
:00409F15 jmp short loc_409F22 ;e ora passiamo a 409F22 per continuare il loop...
:00409F17 ; ---------------------------------------------------------------------------
:00409F17 ;nel caso prima eax and 8000h facesse 0, allora capiteremmo qui...vediamo cosa ci attende...
:00409F17 loc_409F17: ; CODE XREF: sub_409ECF+34j
:00409F17 mov ax, [ebp+arg_0] ;prende "value" e lo mette in ax...
:00409F1B shl ax, 1 ;...lo raddoppia...
:00409F1E mov [ebp+arg_0], ax ;...e lo salva di nuovo...
:00409F22 ;dal jmp di poco fa capitiamo qui...
:00409F22 loc_409F22: ; CODE XREF: sub_409ECF+46j
:00409F22 mov ax, [ebp+arg_4] ;prende il carattere e...
:00409F26 shl ax, 1 ;...lo raddoppia...
:00409F29 mov [ebp+arg_4], ax ;...lo salva e...
:00409F2D jmp short loc_409EE5 ;...riparte il loop :) ...
:00409F2F ; ---------------------------------------------------------------------------
:00409F2F
:00409F2F loc_409F2F: ; CODE XREF: sub_409ECF+21j
:00409F2F mov ax, [ebp+arg_0] ;una volta finito il loop di 8 iterazioni, si salva "value" in ax e si esce dalla call
:00409F33 leave
:00409F34 retn
A questo punto esce dalla call, rientra nel loop di prima, e si rifà tutto daccapo con il carattere successivo dell'username :)
Vediamo solo di fare il punto della situazione riguardo a questa call, giusto per essere sicuri che abbiate le idee chiare:
prende il carattere dell'username, lo shifta a sinistra di 8 così da avere in ah il carattere (e non più in al) e di avere in al 00. Se per esempio l'username da noi immesso è "graftal", avremo in ax questo: 6700. 67 sarà quindi ah, e 00 al, mi sembra oltremodo semplice :)
Ora invece comincia il loop vero e proprio che si rifarà per 8 volte (a causa di quel check presente all'inizio del loop a 409EEC): prima di tutto prende una variabile che all'inizio di tutto varrà ovviamente 0, poi prende il carattere (il famoso 6700 di prima :)) e li xorra con risultato in eax. Fa quindi l'and logico tra eax e il numero 8000h (attenti che è esadecimale eh! ;)) e se il risultato fa 0 allora il salto ci porta a 409F17, altrimenti si continua il loop normalmente; prendiamo il caso in cui si continua normalmente e vediamo che prima raddoppia "value" tramite un altro shift left e poi prende quel numero 1021h di prima e lo xorra con "value": attenti però perché questa volta il risultato viene salvato (sempre di word si parla!) in "value"! A questo punto salta alla fine del loop dove "ch" viene shiftato di 1 a sinistra e viene ovviamente salvata (come sempre) solo la word.
Nel caso il jz di prima fosse saltato, avevamo il raddoppiamento di "value" e il salvataggio del risultato sempre sottoforma di word all'interno di "value" e quindi quel raddoppiamento di "ch" che viene eseguito in ogni loop.
Quando anche questi loop sono finiti, abbiamo in "value" il risultato della seconda parte dell'algo: ecco quindi che facendo il punto della situazione, sappiamo finalmente che nella prima parte dell'algo abbiamo il numero che ci serve in "multot" mentre nella seconda parte in "value"; il programma in seguito aggiunge 9DDh a "value", fa uno sprintf per fare in modo che il risultato da noi ottenuto sia unsigned, ma a noi non interessa particolarmente. Ci interessa invece il fatto che alla fine, il serial viene creato dal programma prendendo i primi 3 numeri di multot CONCATENATI ai primi 3 di value :))))
Huh, spero di essere stato almeno chiaro :)))
Arrivati qui pero non abbiamo ancora finito, ci manca il keygen! Allora, io ho deciso di farlo sotto windows utilizzando una semplicissima DialogBox e il Visual C++ .NET: vi metto in allegato al tutorial il file sorgente comunque, magari dateci un'occhiata, e se di programmazione sotto windows non sapete nulla, chissà che non vi dia l'ispirazione per cominciare :)
Ok, non mi rimane altro da dire riguardo al tutorial e/o al programma, quindi penso proprio di aver (finalmente ;p) finito :)) E mo beccatevi i ringraziamenti!! :P

Byez,

                                                                                                                                                                  Graftal

Note finali

Ommadonna, questa è la parte più difficile di tutto il tute, ricordarsi tutte le innumerevoli persone da ringraziare è sempre arduo, ma cercherò di scrivere i loro nomi in ordine puramente casuale: se per caso mi scordo di qualcuno non abbiatemene :)

kOrn[CsA] che è un mio grande amico e mi ha sempre aiutato e sostenuto :), Eimiar che è pure lui un grande amico e che almeno conosco di persona (:P), Ntoskrnl che è un grande (sisi, proprio cosi =)), evilcry che mi ha sempre aiutato a imparare nuove cose nell'arte del reversing e che io stimo moltissimo :), Quake2^AM pure, mi ha dato un po di dritte molte volte ;), AndreaGeddon, unrelated, cyberdude, active85k[], Kitsune-San (aka Xargon :)(o viceversa, non so, gh :P)), Ch4osm4n, SeiF3r, SiberianSTAR, [igor], Caligola (che sembra si sia volatilizzato :)), N0bodY88, blacksword, ZaDoK, Akagi, cHr, Dejavu, jhon[array] e ultimo nella lista (e non per ordine di importanza ;)) il nostro GRANDE Quequero che mi ha pubblicato questa "patacata" (come direbbe Palmiro Cangini :P) :))) Thx que! =)

Disclaimer

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.