KeyGen Fishing in WinZip 8.1
(troviamo il serial e creiamo il keygen)

Data

by "Ox87k"

 

14/12/2004

UIC's Home Page

Published by Quequero

St. Jimmy's comin' down across the alleyway. Up on the boulevard like a zip code on parade. Light on the sillohette

Ottimo inizio Ox87k :)


He's insubordinate.
Coming at you on account of wonder.
1 2 3 4

....

Home page: http://nuuuuuuuu.ahahahah.it :P
E-mail: [email protected]
IRC Chan: #crack-it

....

Difficoltà

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

 
KeyGen Fishing in WinZip 8.1
Troviamo il serial e creiamo il keygen
Written By Ox87k

Allegato

Introduzione

Introduzione?? Ehm... WinZip ki non lo conosce?? Purtroppo chiede una registrazione [purtroppo??? :)))]. Non è per niente difficile, l'unico particolare che forse poteva confondere è ke la routine della creazione del seriale è imboscata a parecchio codice, cmq con un po di pazienza ci si arriva e devo dire ke non è per niente difficile notarla... hihihihi! Vediamo come WinZip genera il seriale del nome inserito, peschiamo il seriale e creiamo il keygen... [Per ora versione 8.1 anke se la 9.0 SR-1 è identica solo ke nel nome non prende i numeri :) ]

Tools usati


- OllyDbg [qualsiasi versione purchè abbiate command line ;) ]
- Borland c++ 5 [o qualsiasi altro compilatore c]
- Uno stereo con un po di musica.. e una brioche :)

URL o FTP del programma

www.winzip.com

Notizie sul programma

Notizie su WinZip??? Muhahuauhahuahuahu!!! Se non lo conosci forse è meglio che leggi qualche libro su come usare un computer dopo averlo acceso!!!

Essay

Essay... Let's go!
Avviate WinZip e subito vi appare quella noiosissima nag ke vi chiede se volete registrarvi oppure continuare da non registrati. Clickando sul pulsante Register vi appare una finestrella dove inserire nome e serial.. Va bhe tentar non nuoce: inseriamo nome e serial. Nome, Ox87k, serial, 123456789, Invalid name o serial.. dannazione! Ok ok niente paura.. avviamo OllyDbg e carichiamo il winzip. Come abbiamo notato prima, nella finestra di registrazione ci sono due textbox. Una volta caricato il programma in olly, proviamo a piazzare un break su GetDlgItemTextA [magari è la API giusta... magari.... :)], ALT+F1 (x la command line) e scriviamoci bp GetDlgItemTextA. Ok piazzato. Ora avviamo tutto, F9. Benissimo, il programma parte, clickiamo sul pulsante di registrazione, e inseriamo i dati di prima, Ox87k e 123456789 e poi OK. Olly poppa (API azzeccata chissà come mai!!!!). Usciamo dalla API con CTRL+F9. e ci ritroviamo sotto la chiamata alla API.



:0040BD00 call ds:GetDlgItemTextA         
//tornati dalla API siamo qui.          
:0040BD06 push esi                         //esi contiene il seriale inserito
:0040BD07 call sub_4607BD                  //fa dei controlli sul seriale. non ci interessa
:0040BD0C push esi                        
:0040BD0D call sub_4607E6                  //altri controlli sul serial, nemmeno li guardiamo
:0040BD12 cmp nome, 0                      //controlla se il primo carattere del nome inserito è 0
:0040BD19 pop ecx
:0040BD1A pop ecx
:0040BD1B jz short loc_40BD7C              //salto relativo al controllo sul nome (vedi sopra)
:0040BD1D cmp serial, 0                    //controlla se il primo carattere del serial inserito è 0
:0040BD24 jz short loc_40BD7C              //salto relativo al confronto del serial
:0040BD26 call Genera_Codice               //CHIAMATA PER GENERARE IL SERIAL VERO, Entriamoci!
:0040BD2B test al, al                     
:0040BD2D jz short loc_40BD7C
 
Ok come notiamo in fondo c'è la chiamata alla routine della creazione del seriale valido. Posizioniamoci sulla riga relativa a questa chiamata e premiamo F7 per entrarci. Ora è la parte un pochino più complicata.. bisogna trovare la chiamata alla creazione vera e propria del serial. Evito di postare tutto il codice perchè non ne vale la pena, vi riporto l'indirizzo dove troveremo la chiamata fatidica: poche righe più in giù di dove siamo arrivati entrando nella call troviamo un'altra call, esattamente a questo inidirizzo:
 

:
0040B783 CALL WINZIP32.0040B875                    //CALL KE GENERA IL SERIALE
 
 
Yeah. Entriamo qui con F7. Finalmente vediamo che ci siamo.. ci sono calcoli vari che sicuramente indicano che il seriale viene generato qui. Incominciamo:
//Call relativa all'opcode :0040B783

:0040B875  push ebp                        //siamo sbarcati qui :)
:0040B876  mov ebp, esp
:0040B878  mov ecx, dword ptr ss:[ebp+8]   //ecx contiene il nome
:0040B87B  push ebi
:0040B87C  push esi
:0040B87D  push edi
:0040B87E  mov dl, byte ptr ds:[ecx]       //dl contiene il primo carattere del nome ke è in ecx
:0040B880  xor ebx, ebx                    //azzero ebx
:0040B882  xor eax, eax                    //azzero l'accumulatore eax
:0040B884  mov esi, ecx                    //copio il nome che è in ecx anche in esi
:0040B886  xor edi, edi                    //azzero l'indice di destinazione

//Primo ciclo per il seriale:

:0040B888  +->  test dl, dl                   //sono arrivato all'ultimo carattere del nome?
:0040B88A  |    je short Fine_primo_ciclo     //se si esco dal primo ciclo e proseguo sotto
:0040B88C  |    movzx dx, dl                  //metto il carattere che ho in dl nella parte bassa di dx
:0040B890  |    imul edx, edi                 //moltiplica il edx che contiene il carattere con il
          
|                                    //contatore dei caratteri del nome che ogni ciclo viene inc.
:0040B893  |    add ebx, edx                  //aggiunge al primo pezzo del serial il risultato
:0040B895  |    mov dl, byte ptr ds:[esi+1]   //dl punta al carattere successivo
:0040B898  |    inc edi                       //incremento il contatore di caratteri
:0040B899  |    inc esi                       //esi punta quindi al carattere successivo
:0040B89A  +->  jmp short Inizio_primo_ciclo  //torno su
//Fine primo ciclo
 

Ora, l'algoritmo ha generato metà del seriale valido. Specificamente ha generato la parte bassa. Prende ogni carattere del nome inserito e lo moltiplica per l'indice che funge da contatore di caratteri. Vediamo come sarebbe questa parte in c;


//primo pezzo del serial, parte bassa

for (int i=0;name[i]!=0;i++)
{
    serial1+=(name[i] * i);
}

 

Ok, continuiamo l'analisi della seconda parte del serial... il codice ke segue sotto è la parte seguente all'algoritmo sopra esaminato:


:0040B89C  mov byte ptr ds:[4CC78B],1
:0040B8A3  mov esi, ecx                    //copio il nome contenuto in ecx in esi
:0040B8A5  mov cl, byte ptr ds:[ecx]       //cl contiene il primo carattere del nome  

//secondo ciclo:

:0040B8A7  +->  test cl, cl                   //sono arrivato all'ultimo carattere del nome?    
:0040B8A9  |    je short Fine_secondo_ciclo   //se si esco dal secondo ciclo e proseguo sotto
:0040B8AB  |    movzx cx, cl
:0040B8AF  |    push 1021                     //prendo questo valore 00001021, poi vedremo a cosa serve
:0040B8B4  |    push ecx 
:0040B8B5  |    push eax 
:0040B8B6  |    call Calcoli_del_serial       //VEDIAMO SOTTO COSA ACCADE IN QUESTA CALL
:0040B8BB  |    mov cl, byte ptr ds:[esi+1]   //finita la call, carico in cl il carattere successivo
:0040B8BE  |    add esp, 0c
:0040B8C1  |    inc esi
:0040B8C2  +->  jmp short Inizio_secondo_ciclo //torno su all'inizio x ripetere tutto   
//fine secondo ciclo
 

Ora notiamo quella chiamata, andiamo a vedere cosa succede quando arriviamo li. Una volta arrivati sopra la call, premiamo F7 ed entriamo anke qui.

//Call relativa all'opcode :0040B8B6

:0040B8E4  push ebp
:0040B8E5  mov ebp, esp
:0040B8E7  mov eax, dword ptr ss:[ebp+8]
:0040B8EA  push esi                        //nello stack il nome
:0040B8EB  xor ecx, ecx                    //azzero il contatore ecx
:0040B8ED  push 8                          //nello stack il valore 8
:0040B8EF  mov ch, byte ptr ss:[ebp+C]     //in ch il primo carattere del nome
:0040B8F2  pop edx                         //edx=8 cioe' le volte ke ripete il seguente ciclo

//Ciclo che viene ripetuto 8 volte per ogni singolo carattere del nome
:0040B8F3  +->  mov esi, eax                    //esi = eax
:0040B8F5  |    xor esi, ecx                    //esi ^= ecx (ecx, nella parte alta, contiene il carattere)
:0040B8F7  |    test si, 8000                   //if (esi & 0xFFFF) >= 8000
:0040B8FC  |    je short                      //se esi & 0xFFFF è minore di 8000 salta alla parte 2°
:0040B8FE  |1°: add eax, eax                    //altrimenti [se è maggiore o uguale a 8000] eax = eax+eax
:0040B900  |    xor eax, dword ptr ss:[ebp+10]  //e poi SS:[EBP+10] = 1021 ---> eax ^= 1021
:0040B903  |    jmp short 3°                    //salta alla parte 3° [siamo fuori dal if/else]
:0040B905  |2°: shl eax, 1                      //eax = eax<<1;  shifto eax di 1
:0040B907  |3°: shl ecx, 1                      //[FUORI IF ELSE] ecx = ecx<<1; shifto ecx di 1
:0040B909  |    dec edx                         //decremento le 8 volte iniziali
:0040B90A  +->  jnz short Inizio_ciclo          //torno all'inizio del ciclo
//Fine ciclo

:0040B90C  pop esi
:0040B90D  pop ebp
:0040B90E  retn

//Finita la CALL torno al ciclo di prima ovvero all'opcode :0040B8BB

Ok.. siamo più o meno sani e salvi!! Tutto il codice in c che riporto di seguito è il secondo pezzo del serial, ovvero la parte alta questa volta. Vediamo tutto sto macello in c per cercare di capire meglio: [non ho messo commenti perchè mi pare di averne messi fin troppi sopra... poi magari il Que s'incaz!!!]

//Genera serial2 [seconda parte del serial]:

for (int x=0;name[x]!=0;x++)
{
   ecx=(name[x]<<8);

   for (z=0;z<8;z++)
   {
      esi=eax;
      esi=esi^ecx;

      if ((esi & 0xFFFF)>=0x8000)
      {
         eax=eax+eax;
         eax=eax^0x1021;
      }
      else
      {
         eax=eax<<1;
      };
      ecx=ecx<<1;
   };
};

Ora andiamo a completare l'opera. Analizziamo le righe finali situate sotto la primissima call ke abbiamo visto prima, all'inizio del tute:


:0040B8C4  add eax, 63                     //Aggiunge ad eax 63 ---> eax += 0x63;
:0040B8C7  movzx ecx, bx
:0040B8CA  movzx eax, ax                   //metto nella parte bassa di eax il valore di ax, ovvero la
                                             //1° metà del mio serial
:0040B8CD  push ecx                        //ecx contiene la seconda meta del mio serial
:0040B8CE  push eax                        //eax contiene la prima parte del serial
:0040B8CF  push %04X%04X                   //prelevo questi caratteri dallo stack --> %04X%04X
:0040B8D4  push dword ptr ss:[ebp+C]
:0040B8D7  call winzip32.00493104
:0040B8DC  add esp, 10
:0040B8DF  pop edi
:0040B8E0  pop esi
:0040B8E1  pop ebx
:0040B8E2  pop ebp
:0040B8E3  retn                            //ritorno della prima call

 

name: Ox87k
serial: 9F4F0339

KEYGEN:

The End! Finito di esaminare il proggy, prendiamo un qualsiasi compilatore c [io ho usato Borland 5] ed eccovi il KeyGen: [una cosa.. se volete potete creare anke il keygen del winzip 9.0 sr1. La routine ke genera il seriale è identica alla versione 8.1 solo che non accetta numeri sul nome.]

//KEYGEN WINZIP 8.1

#include <stdio.h>
#include <conio.h>

char name[100];
char serial[9];

unsigned int serial1 = 0;
unsigned int serial2 = 0;

unsigned int esi = 0;
unsigned int eax = 0;
unsigned int ecx = 0;

void main()
{
   printf(" [ winzip 8.1 keygen ]\n\n");
   printf("name: ");
   gets(name);
   for (int i=0;name[i]!=0;i++)
   {
      serial1+=(name[i] * i);
   }
   for (int x=0;name[x]!=0;x++)
   {
      ecx=(name[x]<<8);
      for (int z=0;z<8;z++)
      {
         esi=eax;
         esi=esi^ecx;
         if ((esi & 0xFFFF)>=0x8000)
         {
            eax=eax+eax;
            eax=eax^0x1021;
         }
         else
         {
            eax=eax<<1;
         }
         ecx=ecx<<1;
      }
   }
   serial2=eax+0x63;
   serial2=serial2&0xFFFF;
   sprintf(serial, "%0.4X%0.4X", serial2, serial1);
   printf("serial: ");
   printf("%s",serial);
   printf("\n\npress any key to exit....");
   getch();
}

 

Bene.. Questo era il mio primo tute e ho preso una scannata pazzesca per scriverlo tutto, spero almeno ne sia valsa la pena.

Note finali

Oddio la sezione più difficile di tutto il tutorial! Essendo il mio primo tute, devo ASSOLUTAMENTE ringraziare [active85k], (il mio nick è un onore a lui) che mi ha dato le prime dritte tramite email sul mondo del reverse, e sopratutto che mi ha sopportato!!!

Oltre a lui devo ringraziare, Quequero ke mi ha dato la possibiltà di studiare grazie al suo sito, ad AndreaGeddon perchè mi ha aiutato anke lui, e al mitico Zero_G che nel forum è sempre un amore :)

Poi ringrazio tutti quanti voi perchè solo grazie ai vostri tute ho potuto studiare e imparare sempre di più. Lonely Wolf, faina_mdc, pnluck, bender0, zarathustra e via via tutti gli altri, grazie ankora per i vostri tute ke in un certo qual senso mi hanno cresciuto :)

X ultimo ma non meno importante, i Dream Theater che mi hanno tenuto compagnia nel reverse e mentre scrivevo e alla brioche ke nel frattempo mi sono pappato!

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 che ogni sviluppatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.

Reversiamo al solo scopo informativo e per migliorare la nostra conoscenza del linguaggio Assembly.