Mirc 6.03
Serial fishing + keygening tutto da Ida con un pizzico di ntsd :)

Data

by "AndreaGeddon"

 

25/09/2002

UIC's Home Page

Published by Quequero


I can't take no more

what are we fighting for ?

Potenza del tasto delete hihihihi HIHIHIHH FINALMENTE SONO PADRONE DL MIO SPAZIO :P hahahahah cmq...Andre non so come t'e' preso di metterti a fare ida scripting, cmq e' carino :)

you are my brothers

each one i would die for

....

Home page:http://www.andreageddon.8m.com
E-mail: [email protected]
irc.azzurra.org   #crack-it
 

....

Difficoltà

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

 

Un semplice reversing e keygening per il mirc


Mirc 6.03
Serial fishing + keygening tutto da Ida con un pizzico di ntsd :)
Written by AndreaGeddon

Introduzione

Calcoliamoci il seriale con l'idc script di ida :-)

Tools usati

SoftIce? no, usiamo ntsd per un attimo solo
IDA (4.17, ma qualunque versione va bene)

URL o FTP del programma

www.mirc.com

Notizie sul programma

Con ntsd troviamo il punto di attacco e poi tutto offline con ida e idc scripting ci calcoliamo il seriale.

Essay

 

Simpatico il mirc, peccato che chieda il serial per registrarsi :-\ Ok, time to frag!

Andate su help/register... tadaaa! Nome e seriale. A questo punto manco scomodo softice perchè: 1) sarebbe too easy 2) sto downloadando! Per cui mano a ntsd: prompt di dos: ntsd mirc.exe ... e ntsd breaka su DebugBreak, l'api chiamata all'inizializzazione del processo. Bene, settiamo un breakpoint sulla solita messagebox (bp MessageBoxA), ora premete G e lasciate correre il mirc. Andate su help->register, inseriamo nome e serial ad cazzum, premiamo ok e mirc dovrebbe freezarsi. Andiamo su ntsd e vediamo che ci è stato restituito il controllo (breakato sull'api!). Ora usate "t" finchè non raggiungete il ret nell'api, oppure usate g che è meglio, cmq una volta tornati al programma chiamante (il mirc) siete all'address 0x004C69A9. Bene non ci serve altro. Il lavoro di ntsd è finito, ora toccherà alla nostra cara ida darsi da fare:

 

.text:004C69A0 call sub_0_42C771
.text:004C69A5 push eax ; lpText
.text:004C69A6 push [ebp+hWnd] ; hWnd
.text:004C69A9 call MessageBoxA ; error

questo è il punto incriminato, poco più sopra abbiamo una xref:

 

.text:004C6957 ErrorBox: ; CODE XREF: sub_0_4C67BA+E0j
.text:004C6957 push 0

naturalmente voi la label ErrorBox non l'avete, ce l'ho messa io. Cmq tracciate questa xref e vedete che poco più su c'è la parte interessante!

 

.text:004C6857 push offset Nome ; lParam
.text:004C685C push 3E7h        ; buffer size 999
.text:004C6861 push 0Dh         ; WM_GETTEXT
.text:004C6863 push 83h         ; nIDDlgItem
.text:004C6868 push [ebp+hWnd]  ; hDlg
.text:004C686B call SendDlgItemMessageA
.text:004C6870 push offset Serial   ; lParam
.text:004C6875 push 3E7h        ; buffer size
.text:004C687A push 0Dh         ; WM_GETTEXT
.text:004C687C push 82h         ; nIDDlgItem
.text:004C6881 push [ebp+hWnd]  ; hDlg
.text:004C6884 call SendDlgItemMessageA
.text:004C6889 push offset Serial
.text:004C688E push offset Nome
.text:004C6893 call Check_Routine
.text:004C6898 test eax, eax
.text:004C689A jz ErrorBox

ecco perchè magari non vi breakava su GetDlgItemTextA o GetWindowTextA! Usa SendMessage col messaggio WM_GETTEXT per prendere il testo. Ok come vedete dopo aver preso il testo abbiamo anche una call incriminante, abbiamo localizzato subito il punto del check! Guarda caso alla routine passa Nome e Serial come parametri! Sappiamo anche che in uscita dalla routine se eax è zero il serial è errato, per cui entriamo ora in quella Check_Routine. Lì dentro dopo un paio di memset (che azzerano due buffer dove poco dopo vengono copiati nome e seriale, a parte che i buffer azzerati sono più piccoli di quelli in cui all'inizio sono stati messi nome e serial (data loss or overflow?? :-P), che necessità c'è di spostare le stringhe?????? boh... "no wonder windows takes 64 megs ramfor nothing!" hihi) troviamo un'altra call:

 

.text:004C6439 pop edi
.text:004C643A pop esi
.text:004C643B push offset BufferSerial
.text:004C6440 push edi ; BufferNome
.text:004C6441 call Check2
.text:004C6446 test eax, eax
.text:004C6448 jz short ErrorQuit
.text:004C644A mov eax, 1
.text:004C644F jmp OkQuit

come vedete il valore della call Check2 decide se far ritornare 0 (errore) o 1 (ok!). Per cui entriamo anche in questa call e vediamo cosa fare:

 

.text:004C62D5 call _strlen
.text:004C62DA pop ecx
.text:004C62DB cmp eax, 5 ; is Nome > 5 char?
.text:004C62DE jnb short NomeOk ; yes - continue
.text:004C62E0 xor eax, eax
.text:004C62E2 jmp ErrorQuit ; no - errorquit

 

qui ha controllato la lunghezza del nome, almeno 5 caratteri

.text:004C62E7 push 2Dh ; c
.text:004C62E9 push esi ; s = serial
.text:004C62EA call _strchr ; find first occurence of "-"
.text:004C62EF add esp, 8
.text:004C62F2 mov ebx, eax
.text:004C62F4 test ebx, ebx ; is "-" found?
.text:004C62F6 jnz short MinusOk ; yes - continue
.text:004C62F8 xor eax, eax
.text:004C62FA jmp ErrorQuit ; no - errorquit

 

qui ha controllato la presenza del carattere "-" nel seriale, quindi ora sappiamo che deve essere del tipo xxxxx-xxxxx

.text:004C62FF mov byte ptr [ebx], 0 ; taglia le due stringhe numero col terminatore al posto di -
.text:004C6302 push esi ; s
.text:004C6303 call _atol           ;trasforma in numero il primo pezzo
.text:004C6308 pop ecx
.text:004C6309 mov [ebp+Serial1], eax
.text:004C630C mov byte ptr [ebx], 2Dh ; ripristina il -
.text:004C630F inc ebx
.text:004C6310 cmp byte ptr [ebx], 0 ; dopo il - c'è qualcosa?
.text:004C6313 jnz short Serial2Ok ; si - continua
.text:004C6315 xor eax, eax
.text:004C6317 jmp ErrorQuit ; no - errorquit

 

qui con atol ha trasformato la stringa davanti al "-" in numero (salvato in serial2)

.text:004C631C push ebx ; s
.text:004C631D call _atol     ;trasforma in numero il secondo pezzo
.text:004C6322 pop ecx
.text:004C6323 mov [ebp+Serial2], eax
.text:004C6326 push [ebp+Nome] ; s
.text:004C6329 call _strlen ; get nome length
.text:004C632E pop ecx
.text:004C632F mov [ebp+NomeLength], eax

qui ha trasformato la stringa DOPO il "-" in numero. Ok ha preso i due pezzi del serial come due numeri, quindi ci aspettiamo un semplice cmp tra due valori numerici. Arriviamo finalmente ai calcoli interessanti:

 

.text:004C6346 CicloControllo1: ; CODE XREF: Check2+9Aj
.text:004C6346 movzx esi, byte ptr [ecx]
.text:004C6349 imul esi, Undici[eax*4] ; accumulatore = accumulatore + char * undici[counter]
.text:004C6351 add ebx, esi
.text:004C6353 inc eax
.text:004C6354 cmp eax, 26h
.text:004C6357 jle short loc_0_4C635B
.text:004C6359 xor eax, eax
.text:004C635B 
.text:004C635B loc_0_4C635B: ; CODE XREF: Check2+91j
.text:004C635B inc edx
.text:004C635C inc ecx
.text:004C635D cmp edx, [ebp+NomeLength]
.text:004C6360 jl short CicloControllo1
.text:004C6362 
.text:004C6362 Controllo1: ; CODE XREF: Check2+7Ej
.text:004C6362 cmp ebx, [ebp+Serial1] ; controllo1 = serial1
.text:004C6365 jz short Controllo1ok ; si - continua
.text:004C6367 xor eax, eax
.text:004C6369 jmp short ErrorQuit ; no - errorquit

"Undici" è un array di long che contiene i numeri che vengono moltiplicati ad ogni iterazione con il char attuale del nome. In pratica parte dal terzo char del nome e itera per tutti i char, e ad ogni n-esima iterazione moltiplica l'n-esimo char per Undici[n], quindi aggiunge il risultato ad una variabile. La forumla è quindi:

accumulatore = accumulatore + char * (undici[n])

arrivati alla linea 4C6362 c'è un cmp tra il primo pezzo del serial che abbiamo inserito e il numero che lui si è calcolato. Se passiamo questo CMP arriviamo al controllo successivo:

 

.text:004C637F CicloControllo2: ; CODE XREF: Check2+DAj
.text:004C637F movzx esi, byte ptr [ecx]
.text:004C6382 movzx edi, byte ptr [ecx-1]
.text:004C6386 imul esi, edi ; accumulatore = (char x (char precedente)) x undici[counter]
.text:004C6389 imul esi, Undici[eax*4]
.text:004C6391 add ebx, esi
.text:004C6393 inc eax
.text:004C6394 cmp eax, 26h
.text:004C6397 jle short loc_0_4C639B
.text:004C6399 xor eax, eax
.text:004C639B 
.text:004C639B loc_0_4C639B: ; CODE XREF: Check2+D1j
.text:004C639B inc edx
.text:004C639C inc ecx
.text:004C639D cmp edx, [ebp+NomeLength]
.text:004C63A0 jl short CicloControllo2
.text:004C63A2 
.text:004C63A2 Controllo2: ; CODE XREF: Check2+B7j
.text:004C63A2 cmp ebx, [ebp+Serial2] ; controllo2 = serial2?
.text:004C63A5 jz short AllOk ; si - ok routine finita con successo
.text:004C63A7 xor eax, eax
.text:004C63A9 jmp short ErrorQuit ; no - errorquit

che è praticamente uguale al precedente algoritmo, viene solo aggiunta una moltiplicazione dell'n-esimo char per l'(n-1)-esimo. Anche qui la formula è semplice:

accumulatore = accumulatore + (char * char_precedente) x Undici[n]

anche qui arriviamo a 004C63A2 e c'è il CMP tra il numero inserito da noi e quello calcolato dal programma. Se anche questo cmp va bene la routine esce con return value = 1 il che vuol dire che il programa avrà accettato il serial. C'è solo un piccolo problema, noi stiamo su ida, quindi non possiamo vedere dai CMP quali numeri dobbiamo inserire! No problemo, usiamo l'idc script e calcoliamoci i due pezzi del serial: aprite un file di testo e scriveteci il seguente codice:

 

static serial1()
{
   auto i, serial, fattori, fattore, stringa, nome, carattere;

   fattori = 0x0056A470;
   nome = 0x0056A420;
   serial = 0;

   for(i = 3; i<12; i++)
   {
      fattore = Dword(fattori+((i-3)*4));
      carattere = Byte(nome + i);
      serial = serial + (carattere*fattore);
   }
   stringa = ltoa(serial, 10);
   Message(stringa);
}

static serial2()
{
   auto i, serial, fattori, fattore, stringa, nome, carattere, pcarattere;
   fattori = 0x0056A470;
   serial = 0;
   nome = 0x0056A420;

   for(i = 3; i<12; i++)
   {
      fattore = Dword(fattori+((i-3)*4));
      carattere = Byte(nome+i);
      pcarattere = Byte(nome+i-1);
      serial = serial + (carattere*pcarattere)*fattore;
   }
   Message(nome);
   stringa = ltoa(serial, 10);
   Message(stringa);
}

 

ora spieghiamo un attimino. fattori è l'address di Undici, cioè dell'array dei long che sono usati per moltiplicare l'n-esimo char. nome è una locazione che io ho patchato con ida per inserirci la stringa "AndreaGeddon", tanto per non dover usare gli array che con l'idc scripting sono un pò pesanti. Fatto questo itero da 3 fino alla fine del nome (12 chars) e di volta in volta eseguo il calcolo. Alla fine scriverò i due risultati con la funzione Message. Ovviamente essendo il serial un numero prima va convertito in stringa con la funzione ltoa. Ecco fatto, a questo punto usate IDC File per caricare il file di script appena fatto, e poi in IDC Command aggiungete le due righe:

serial1();

serial2();

eseguite e nella output window di ida vi verranno scritti i due pezzi del serial separati dal nome (sennò li scriveva attaccati!)

nome:  AndreaGeddon

serial:  10565-1049689

ecco finito, softice si è fatto un bel sonnellino stavolta! Basta un minimo di modifica alle routine precedenti per adattarle al calcolo del vostro nome!

Ciauz

AndreaGeddon

 

Note finali

Un saluto a tutta la UIC e a tutto #crack-it. Un mega saluto ad Ironspark perchè questo reversing l'avevo fatto insieme a lui :) byeeee

Disclaimer

Noi reversiamo perchè... beh lo sapete il perchè!

Capitoooooooo????? Bhè credo di si ;))))