KeygenMe Reversing
keygenning and autokeygenning

Data

by "kratorius"

 

23/03/2003

UIC's Home Page

Published by Quequero

Ci vuole più tempo a riempire i campi di 'sto form...

Posso scrivere qui? :)

Ovviamente no :)

...che non a scrivere il tutorial vero e proprio

....

Home page se presente: http://kratorius.cjb.net
E-mail: [email protected]
irc.azzurra.org @ #crack-it && #reversing

....

Difficoltà

(x)NewBies ( )Intermedio ( )Avanzato ( )Master

 

Costruiamo un keygen e costringiamo il keygenme a svelarci il seriale


KeygenMe Reversing
keygenning and autokeygenning
Written by kratorius

Introduzione

Siccome il keygenning di questo programma era una mega cavolata, ho deciso che oltre a fare il keygen "normale" fosse meglio fare qualcosa di più "insolito" (nel senso di meno diffuso :)), ovvero creare un autokeygen.

Tools usati

Un disassemblatore qualsiasi Io ho usato IDA che è er mejo, ma voi usate quel che vi pare :)
Hiew o l'editor esadecimale che preferite
Visual C++ o un qualsiasi compilatore C (anche il più schifoso va bene)
Un cervello semi-funzionante (la versione base va bene, se avete la professional è meglio :))

URL o FTP del programma

www,crackmes.de. Il keygenme in questione è il KeyGen-me N° 1 di devilz. Lo trovate nella sezione "A-D".

Notizie sul programma

Un keygenme, niente di più :)

Essay

Weeeeeeee, finalmente si iniziaaaaaaaaaaa! :P
Mano a IDA (o quello che preferite) e iniziamo subito il reversing del programma...
Diamo uno sguardo alle funzioni importate, notiamo subito che l'unica funzione che potrebbe prendere il testo dai textbox è GetDlgItemTextA (perchè potrebbe benissimo fare un SendMessageA con WM_GETTEXT). Doppioclikkiamoci sopra e andiamo a guardare le xref. Ce ne sono 4, noi dirigiamoci verso la prima.
Inizio subito col dire che ho rinominato un po' di locazioni per semplificarmi la vita, quindi voi sul vostro disassemblato le cose le vedrete leggermente diverse :)
Con un po' di intuito possiamo subito capire che quella chiamata prende il nome dal textbox:

.text:004010E1  pusha
.text:004010E2  push 0Ch --------------------------> ; nMaxCount
.text:004010E4  push offset Nome ------------------> ; lpString
.text:004010E9  push 64h --------------------------> ; nIDDlgItem
.text:004010EB  push [ebp+hDlg] -------------------> ; hDlg
.text:004010EE  call GetDlgItemTextA --------------> ; Si prende il nome
.text:004010F3  or eax, eax
.text:004010F5  jnz short PijaSerial --------------> ; Lunghezza diversa da 0? Salta
.text:004010F7  push 0 ----------------------------> ; uType
.text:004010F9  push offset aFillInTheBlank -------> ; lpCaption
.text:004010FE  push offset aTheNamePlease --------> ; lpText
.text:00401103  push 0 ----------------------------> ; hWnd
.text:00401105  call MessageBoxA ------------------> ; Altrimenti stampami la msgbox d'errore
.text:0040110A  leave
.text:0040110B  retn 10h

Bene, abbiamo preso il nome, ora passiamo al seriale:

.text:00401110 PijaSerial:
.text:00401110  push 0Ch --------------------------> ; nMaxCount
.text:00401112  push offset Nome ------------------> ; lpString
.text:00401117  push 0C8h -------------------------> ; nIDDlgItem
.text:0040111C  push [ebp+hDlg] -------------------> ; hDlg
.text:0040111F  call GetDlgItemTextA --------------> ; Prendi il serial
.text:00401124  or eax, eax
.text:00401126  jnz short GenSerial ---------------> ; Lunghezza diversa da 0? Salta
.text:00401128  push 0 ----------------------------> ; uType
.text:0040112A  push offset aFillInTheBla_0 -------> ; lpCaption
.text:0040112F  push offset aTheSerialPleas -------> ; lpText
.text:00401134  push 0 ----------------------------> ; hWnd
.text:00401136  call MessageBoxA ------------------> ; Altrimenti stampa la msgbox d'errore
.text:0040113B  leave
.text:0040113C  retn 10h

Praticamente è uguale alla prima sezione di codice, andiamo avanti nel "cuore dell'algoritmo". Infatti in questa parte viene generato il seriale:

.text:0040113F GenSerial:
.text:0040113F  push 0Ch --------------------------> ; nMaxCount
.text:00401141  push offset Nome ------------------> ; lpString
.text:00401146  push 64h --------------------------> ; nIDDlgItem
.text:00401148  push [ebp+hDlg] -------------------> ; hDlg
.text:0040114B  call GetDlgItemTextA --------------> ; Si riprende il nome
.text:00401150  xor edx, edx ----------------------> ; Azzera edx...
.text:00401152  xor ebx, ebx ----------------------> ; ...ebx
.text:00401154  xor ecx, ecx ----------------------> ; ...ecx
.text:00401156  xor eax, eax ----------------------> ; ...eax
.text:00401158  mov esi, offset Nome --------------> ; inizializza esi
.text:0040115D
.text:0040115D loop:
.text:0040115D  mov bl, [ecx+esi] -----------------> ; Prende ogni char del nome
.text:00401160  add eax, ebx ----------------------> ; e somma il suo valore hex a eax
.text:00401162  inc ecx ---------------------------> ; incrementa ecx
.text:00401163  cmp bl, 0 -------------------------> ; NON siamo arrivati alla fine del nome?
.text:00401166  jnz short loop --------------------> ; allora ripeti il ciclo
.text:00401168  mov edx, 28h ----------------------> ; sposta in edx il valore 28h
.text:0040116D  mul edx ---------------------------> ; moltiplica eax per edx (28h)
.text:0040116F  add eax, 19h ----------------------> ; aggiunge 19h a eax
.text:00401172  push eax --------------------------> ; converte a stringa
.text:00401173  push offset unk_0_403364 ----------> ; il serial giusto (che si trova in eax)
.text:00401178  push offset RightSerial -----------> ; e lo memorizza in right serial
.text:0040117D  call wsprintfA --------------------> ; con wsprintf
.text:00401182  add esp, 0Ch ----------------------> ; aggiunge 0Ch allo stack pointer
.text:00401185  mov edx, offset RightSerial -------> ; sposta in edx il serial giusto
.text:0040118A  push edx --------------------------> ; e lo pusha nello stack
.text:0040118B  push 0Ch --------------------------> ; nMaxCount
.text:0040118D  push offset SerialInserito --------> ; lpString
.text:00401192  push 0C8h -------------------------> ; nIDDlgItem
.text:00401197  push [ebp+hDlg] -------------------> ; hDlg
.text:0040119A  call GetDlgItemTextA --------------> ; riprende il serial
.text:0040119F  mov esi, offset SerialInserito ----> ; sposta il serial inserito in esi
.text:004011A4  pop edx ---------------------------> ; si riprende il serial giusto dallo stack
.text:004011A5  mov eax, [esi] --------------------> ; Carica in eax il serial inserito
.text:004011A7  mov ebx, [edx] --------------------> ; Carica in ebx il serial giusto
.text:004011A9  cmp eax, ebx ----------------------> ; Confronta eax con ebx (serial vero con serial inserito)
.text:004011AB  jnz short BadSerial ---------------> ; Se non coincidono salta
.text:004011AD  push 0 ----------------------------> ; uType
.text:004011AF  push offset aGoodWork -------------> ; lpCaption
.text:004011B4  push offset aGoodSerialNowS -------> ; lpText
.text:004011B9  push 0 ----------------------------> ; hWnd
.text:004011BB  call MessageBoxA ------------------> ; altrimenti... congratulazioni :)
.text:004011C0  jmp short loc_0_4011D5
.text:004011C2 ; ----------------------------------------------------------------------
.text:004011C2
.text:004011C2 BadSerial:
.text:004011C2  push 0 ----------------------------> ; uType
.text:004011C4  push offset aFatalError -----------> ; lpCaption
.text:004011C9  push offset aBadBoyReadMore -------> ; lpText
.text:004011CE  push 0 ----------------------------> ; hWnd
.text:004011D0  call MessageBoxA ------------------> ; chiama la msgbox d'errore
.text:004011D5
.text:004011D5 loc_0_4011D5:
.text:004011D5  popa
.text:004011D6  leave
.text:004011D7  retn 10h

Il listato è molto semplice da comprendere, anche perchè c'è praticamente un commento per ogni istruzione :) Tuttavia, volevo precisare che il serial è memorizzato in chiaro, senza nessun tipo di "protezione", percui quando arrivate al cmp eax, ebx (a 004011A9), se fate da SoftICE ? eax avrete il seriale giusto in bella mostra.
Però noi vogliamo farci un keygen, quindi i passi da compiere sono:
- Acquisire il nome
- Prendere ogni char del nome e sommare il suo valore in hex ad una variabile che parte da 0
- Moltiplicare questa variabile per 28h
- E aggiungerci 19h

In definitiva, il codice del keygen è questo:

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

int
main()
{
    char username[13];
    int serial=0;
    unsigned int i;

    printf("Insert your name: ");
    scanf("%s", &username);

    for(i=0; i<=strlen(username); i++)
        serial += username[i];

    serial *= 0x28;
    serial += 0x19;

    printf("Serial calculated: %d\n", serial);

    return 0;
}


Prendo 13 caratteri, perchè se notate, nella prima chiamata a GetDlgItemTextA, viene passato come ultimo parametro (il primo a partire da sopra, visto che lo stack usa l'architettura LIFO, Last In First Out) il massimo numero di caratteri da prendere, che equivale a 0Ch = 13d.
Compilate il tutto ed eseguite il programma, ed ecco che il nostro keygen è pronto :)
Bene, ma avevo detto che avremmo convinto il programma a svelarci il seriale, quindi all'opera :)
Come ho fatto notare in precedenza, il seriale è memorizzato in chiaro, quindi non avremo bisogno di complicarci la vita con decrypting vari.
Potremmo far comparire, al posto della messagebox che ci dice che il serial che abbiamo inserito è sbagliato, una msgbox che ha come testo il serial giusto :)
Diamo un'occhiata a 004011C9: lì viene pushato il testo della msgbox d'errore, quindi perchè non modificare quell'istruzione in modo che ci mostri il nostro serial? La modifica è a dir poco banale:
- apriamo Hiew
- andiamo a 004011C9
- F3->F2 e mettiamo push edx seguito da 4 nop (per bilanciare gli opcode)
- F9
- F10
Perchè pushiamo edx? Semplice, perchè in edx c'è il nostro vero serial che NON è stato modificato in nessun modo :)
Alcuni di voi diranno, "ma non si dovrebbe fare push edx?". Si, si dovrebbe, ma se guardate qualche istruzione prima, c'è un bel mov edx, offset RightSerial che rende inutile il push offset.
E' stato abbastanza semplice, non trovate? :)

kratorius      

Note finali

Un saluto a tutti gli amici di #crack-it, in particolare a Ironspark, AndreaGeddon, al Que che m'ha pubblicato sta specie di tutorial (e che magari si faceva vedere ogni tanto :)), a Ntoskrnl e a chi ho dimenticato :)

Disclaimer

Niente di illegale stavolta, stiamo reversando un keygenme :)