Keygeneriamo il mIRC 6.16

Data

by active85k

 

11 settembre 2005

UIC's Home Page

Published by Quequero

 

Preciso come sempre active, grazie
ciau q :PPP (active, ti seleziono sul serio! :))

 

....

Home page (se presente): www.active85k.da.ru
E-mail: active85k at hotmail dot com

....

Difficoltà

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

 


Introduzione

Sapete tutti che cosa sia il mIRC.. con questo tutorial lo keygeneriamo.

Tools usati


- IDA Disassembler 4.7 (e' un disassemblatore ma e' in grado anche di debuggare)
- Microsoft Visual C# (per scrivere un generatore di chiavi)


URL o FTP del programma

www.mirc.com

Essay

Ciao Mondo.
Il problema di questi programmi e' dato dal fatto che i newbie, per imparare a reversarli, ne scaricano sempre l'ultima versione... e trovano difficolta' leggendo i vecchi tutorials per piccoli cambiamenti che non corrispondono con quanto letto. Ecco perche' oggi reversiamo la versione 6.16.
La prima cosa da fare e' ovviamente quella di disassemblare il programma. Io ho usato IDA 4.7... perche' lo uso anche per il debugging... voi potete usare quello che vi sta piu' a cuore. Appena ottenuto il disassembly, cliccate sul tasto Names e andate alla ricerca delle funzioni win32 che servono per ritirare il testo dai componenti. Mi sono subito accorto che GetDlgItemTextA non esiste proprio... invece sono riuscito a trovare la GetWindowTextA. Ho provato a mettere quindi un breakpoint su questa chiamata ma quando provo a registrarmi con dati a caso, il debugger non poppa affatto... hmmm... evidentemente il bastardo usa o la SendDlgItemMessageA o la SendMessageA per ritirare il testo. Il problema e' che se mettiamo un breakpoint su queste chiamate qua... il debugger non ci lascera' neanche il tempo di respirare... per cui dobbiamo individuare la finestrella di registrazione e poi procedere manualmente. Mettiamo un breakpoint su tutte le chiamate a DialogBoxParamA (come vedete ce ne sono 15) e fermiamoci solo ad analizzare quella che poppa quando clicchiamo su Register: a me poppa in questo punto:

 
.text:0046760C push ebx
.text:0046760D push ebp                 ; lpDialogFunc
.text:0046760E movzx edx, si
.text:00467611 push edi                 ; hWndParent
.text:00467612 push edx                 ; lpTemplateName
.text:00467613 push eax                 ; hInstance
.text:00467614 call ds:DialogBoxParamA
Allora: se ho fatto bene le cose, ebp dovrebbe contenere l'indirizzo della window procedure della finestrella di registrazione. La trovo esattamente a .text:004C7AA0. Adesso... scorriamo un po' giu' o cerchiamo in qualche sub procedure per trovare due chiamate consecutive a SendDlgItemMessageA oppure a SendMessageA (presumo che siano due: una per il nome e l'altra per il serial...): Ecco... non posso aver sbagliato! Andate a text:004C7BA0. E' proprio bello! Proviamo a piazzare un bel breakpoint e... infatti ci siamo! Quando ho cliccato su OK, il debugger mi ha poppato subito! :D Non ci resta che debuggare. Come nome ho inserito "active85k1" e come serial "active85k2". Vediamo cosa succede:
.text:004C7BA0 mov esi, [esp+4Ch]
.text:004C7BA4 mov edi, ds:SendDlgItemMessageA
.text:004C7BAA push offset username
.text:004C7BAF push 3E7h
.text:004C7BB4 push 0Dh
.text:004C7BB6 push 83h
.text:004C7BBB push esi
.text:004C7BBC call edi                        ; SendDlgItemMessageA che ritira il nome
.text:004C7BBE push offset serial
.text:004C7BC3 push 3E7h
.text:004C7BC8 push 0Dh
.text:004C7BCA push 84h
.text:004C7BCF push esi
.text:004C7BD0 call edi                        ; SendDlgItemMessageA che ritira il serial
.text:004C7BD2 mov edx, offset serial
.text:004C7BD7 mov ecx, offset username
.text:004C7BDC call sub_4C7600                 ; Ecco la bella procedura che ci interessa :D
.text:004C7BE1 test eax, eax
.text:004C7BE3 jz NonRegistrato

Come potete vedere... e' proprio palese che sub_4C7600 sia la procedura di calcolo del seriale... gli vengono passati i nostri dati come parametri quindi siamo apposto. In realta' basterebbe noppare quel jz finale per crackare il programma... ma poi dovremmo fare cosi' per tutti i jump che ci sono dopo ogni chiamata a questa procedura. Adesso noi ci entriamo dentro e la analizziamo tutta quanta. Guardate... vi faccio un riassunto se no e' un macello... seguendo tutte le procedure studipe non sono arrivato a nulla diverso da una marea di controlli che a noi nn toccano affatto... sono poi arrivato a un punto interessante:

.text:004C7518 mov dl, [eax]                 ; eax punta al nome utente
.text:004C751A inc eax
.text:004C751B test dl, dl                   ; controlla se la stringa
.text:004C751D jnz short loc_4C7518          ; e' finita o meno
.text:004C751F sub eax, esi                  ; ottiene la lunghezza del nome
.text:004C7521 cmp eax, ecx                  ; qua abbiamo ecx = 4
.text:004C7523 jnb short loc_4C7532          ; controlla che il nostro nome sia almeno di
                                             ; 4 caratteri. altrimenti errore.

Allora noi ci becchiamo questo salto e proseguiamo (ricordate... il nome di almeno 4 caratteri). Proseguiamo:

.text:004C7532 mov ebx, [esp+0B4h+var_A4]    ; ebx punta al seriale
.text:004C7536 push '-'
.text:004C7538 push ebx
.text:004C7539 call sub_570260               ; procedura utile

Quella sub che vedete... e' una procedura che va alla ricerca del trattino ('-') tra i caratteri che compongono il serial. Se non lo trova salta a errore. Quindi, evitiamo l'errore e continuiamo ad andare avanti: Ho ripetuto la procedura di registrazione ma questa volta sono stato attento a inserire il trattino nel seriale. Il mio nuovo seriale sara' "1234-1234". Passando questo punto arriviamo qui:

.text:004C7547 push ebx                ; ebx punta al serial
                                       ; mentre esi punta al serial a partire dal trattino
.text:004C7548 mov byte ptr [esi], 0   ; il serial viene spezzato in due stringhe diverse
                                       ; proprio nel punto in cui si trova il trattino

Da questo possiamo dedurre che noi dobbiamo generare, col nome, due numeri che poi andranno concatenati, separati da un trattino nella stringa finale. Vabbe'... andiamo avanti... ebx viene azzerato e poi ci troviamo qua:

.text:004C7590 movzx eax, byte ptr [esi+edi]      ; esi+edi punta al nome (quarto carattere)
.text:004C7594 imul eax, [esp+edx*4+0B4h+var_A0]  ; il char viene moltiplicato con un val di un array
.text:004C7599 add ebx, eax                       ; il risultato della imul viene aggiunto a ebx
.text:004C759B inc edx                            ; passiamo al val successivo nell'array
.text:004C759C cmp edx, 26h                       ; se edx > 26h (lunghezza dell'array di valori)
.text:004C75A1 xor edx, edx                       ; viene riazzerato
.text:004C75A3 inc esi                            ; si passa al carattere successivo del nome
.text:004C75A4 cmp esi, ecx                       ; siamo arrivati alla fine del nome?
.text:004C75A6 jl short loc_4C7590                ; NO: analizziamo il prossimo carattere

Questa e' la generazione della prima parte del seriale. Dopo queste istruzioni, il numero generato viene confrontato con quello che abbiamo inserito noi (ovvero 1234). Dopo tutta questa roba c'e' la generazione della seconda parte del seriale:

.text:004C75C0 movzx eax, byte ptr [esi+edi-1]   ; esi+edi punta al quarto char del nome
.text:004C75C5 movzx ebp, byte ptr [esi+edi]     ; si prendono terzo e quarto char
.text:004C75C9 imul eax, ebp                     ; si moltiplicano tra loro
.text:004C75CC imul eax, [esp+edx*4+0B4h+var_A0] ; il risult viene moltipl per l'edxesimo val dell'array
.text:004C75D1 add ebx, eax                      ; il risultato viene aggiungo a ebx
.text:004C75D3 inc edx
.text:004C75D4 cmp edx, 26h
.text:004C75D7 jle short loc_4C75DB
.text:004C75D9 xor edx, edx
.text:004C75DB
.text:004C75DB loc_4C75DB: ; CODE XREF: sub_4C7400+1D7 j
.text:004C75DB inc esi
.text:004C75DC cmp esi, ecx
.text:004C75DE jl short loc_4C75C0

Tutto qua. L'array e' l'unica cosa che ci manca... quindi andiamo a prendercelo (sappiamo che e' lungo 0x26h):

public static string Keygen(string username)
{
    int l = username.Length;
    if(l < 4) return "L'username deve avere almeno 4 caratteri!";
    int[] array1 = {
        0x0B, 6, 0x11, 0x0C, 0x0C, 0xE, 5, 0x0C, 0x10, 0x0A, 0x0B, 6, 0x0E, 0x0E, 4, 0xB,
        6, 0x0E, 0x0E, 4, 0x0B, 9, 0x0C, 0x0B, 0x0A, 8, 0x0A, 0x0A, 0x10, 8, 4, 6, 0x0A,
        0x0C, 0x10, 8, 0x0A, 4 };
    int p1 = 0;
    int p2 = 0;
    for(int i=3; i<l; i++)
    {
        int a = (int) username[i-1];
        int b = (int) username[i];
        int v = array1[(i-3) % 0x26];
        p1 += b*v;
        p2 += a*b*v;
    }
    return "" + p1 + "-" + p2;
}

Ed ecco scritta la procedura di generazione della chiave seriale.
Per quanto riguarda questo piccolo tutorial, abbiamo proprio finito... e quindi, ci vediamo alla prossima puntata! :D

                                                                                                                 active85k

Note finali

Note finali e ringraziamenti. (non essere troppo prolisso mi raccomando ;p NdQ)

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.