| Lezione per studenti n°2 |
||
| 31/08/2004 |
by "Pnluck" |
|
| 31/08/2004 |
Published by Quequero |
|
|
|
Bravo luck! |
Se inventano la macchina del tempo uckido guell'iqnorante di Carlo Magno ;D |
| .... |
E-mail: pnluck@virgilio.it Pnluck #crack-it,#asm,#c,#assembly |
.... |
| Difficoltà |
(X)NewBies ( )Intermedio ( )Avanzato ( )Master |
|
Questa luzione è basata sul controllo del keygen basato su seriale, il key è generato con i rotate e gli shift
Lezione x studenti n°2
Peschiamo il serial
Written by Pnluck
| Introduzione |
In questo tutozzo mi accingo a descrivere il processo tramite il quale il crackme n°2 delle lezioni x studenti, controlla user e psw. In poche parole vi descrivo la procedura tramite la quale il prg controlla la psw generata tramite l'user inserito.
| Tools usati |
Ollydbg e dev-cpp (per il serial)
| Notizie sul programma |
L'user e psw possono contenere max 5 char,ma x rendere + semplice il keygeneretor,
metteremo l'user di 4 char.
Perche questa vienne
immesso nei registri eax ed ebx, quindi max contengono 4 char
| Essay |
Avviamo il prg, e vediamo che massimo user e psw contengono 5 char, vabbe mettiamo user e char a casaccio di 4 char,e ci conpare un msg d'errore. Ora analiziamo il codice.
Con olly facciomo destro->search->all_intermodular_call, e cerchiamo qualche api che ci può servire.Troviamo un GetWindowTextA. Ora iniziamo a descrivere il codice
| 004011FF CALL <JMP.&USER32.GetWindowTextA> ; \GetWindowTextA 00401204 XOR ECX,ECX azzera ecx 00401206 MOV AL,BYTE PTR DS:[40219F] prende i char di user 0040120B TEST AL,AL se al=0 0040120D JE due.00401371 va al msg ke dice che que non è scema ;D 00401213 XOR EAX,EAX azzera eax |
#################Ecco la msg################
| 00401371 PUSH 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL 00401373 PUSH due.0040208D ; |Title = "Ehmmmmm!!! No!" 00401378 PUSH due.0040213B ; |Text = "Wè, son mica scemo!!! :)" 0040137D PUSH 0 ; |hOwner = NULL |
############################################
Dove ci sono i tre punti, significa ke ho tolto codice inutile
| 00401215 MOV AL,BYTE PTR DS:[ECX+40219F] prende il char di user, dipendentemente da ecx 0040121B TEST AL,AL controlla se al=0 0040121D JE SHORT due.00401279 se si va all'altra procedura 00401221 MOV EDI,ECX edi=ecx 00401223 MUL EDI moltiplica eax*edi con risultato in eax 00401225 SUB AL,25 sottrae ad al 0x25 00401227 ADD AL,CL gli aggiunge cl 00401229 XOR AL,BYTE PTR DS:[ECX+402000] prende un valore di 4020000 ke sarebbero in hex:12 45 D1 FF ... 00401245 ADD AL,BYTE PTR DS:[ECX+402000] aggiunge ad al 402000+ecx ... 00401251 SHL AL,2 shift left di al di 2 00401254 ROR AL,4 ruota a destra al di 4 ... 00401270 MOV BYTE PTR DS:[ECX+40218F],AL mette al in 40218f+ecx 00401276 INC ECX incrementa ecx 00401277 JMP SHORT due.00401215 salta, passando al prossimo char con ecx++ Controlla se il char generato sia ascii-comprensibile, se no lo fa diventare (almeno credo :P) 00401279 XOR ECX,ECX azzera ecx 0040127B MOV AL,BYTE PTR DS:[ECX+40218F] prende stringa generata e la mette in al 00401281 TEST AL,AL se è zero 00401283 JE due.00401331 vai a 401331 00401289 CMP AL,66 se no lo compara con "f" 0040128B JG due.0040131B se è maggiore salta 00401291 CMP AL,30 se no cmp con "0" 00401293 JL due.00401326 se minore vai a 401326 00401299 INC ECX ecx++ 0040129A MOV BYTE PTR DS:[ECX+4021A7],AL se è tutto a posto mette il char in 4021a7 004012A0 JMP SHORT due.0040127B e fa da capo |
Ecco la procedura se il char generato è minore di 0x30
| 00401326 ADD AL,18 gli aggiunge 0x18 00401328 CMP AL,30 e lo compara con 0x30 0040132A JL SHORT due.00401326 se minore reinizia |
Ecco l aprocedura se il char generato è maggiore di 0x66
| 0040131B SUB AL,12 gli sottrae 0x12 0040131D CMP AL,66 e lo compara con 0x66 00401321 JMP due.00401291 se no salta |
Questa e la procedura quando si è finito di controllare i char
| 00401331 XOR ECX,ECX azzeramento ecx 00401333 MOV AL,BYTE PTR DS:[ECX+4021A7] muove 4021a7+ecx in al 00401339 TEST AL,AL se non c'è + nulla 0040133B JE SHORT due.004012C8 salta se no 0040133D MOV AH,BYTE PTR DS:[ECX+4021A8] muove 4012a8+ecx in ah 00401343 JE SHORT due.004012C8 se si è dinuovo alla fine salva 00401345 CMP AH,AL cmp ah ed al 00401347 INC ECX ecx++ 00401348 INC EDX edx++ 00401349 JNZ due.004012BA se diversi salta 00401351 CMP AL,66 e cmp al con 0x66 00401353 JG SHORT due.00401366 se maggiore salta a 401366 00401355 CMP AL,30 se no cmp con 0x30 00401357 JL SHORT due.0040135B se minore salta a 40135b, ke corrisponde all’uscita del prg. 00401359 JMP SHORT due.00401333 se no salta ad inizio ciclo |
#######Questo ciclo non fa altro ke, far uscire il prg dal processo di controllo della psw####
| 0040135B ADD AL,2 al+2 0040135D CMP AL,30 cmp con 0x30 00401361 JMP due.004012BA se no esci da tutto 00401366 SUB AL,3 al-3 00401368 CMP AL,66 cmp al 66 0040136A JG SHORT due.00401366 se maggiore reinizia |
########Questo ciclo non fa altro ke, far uscire il prg dal processo di controllo della psw######
Questa è la procedura azionata da 401349
| 004012BA MOV BYTE PTR DS:[ECX+402173],AL mette al in 402173+ecx 004012C0 MOV BYTE PTR DS:[ECX+402174],AH mette ah in 402174+ecx 004012C6 JMP SHORT due.00401333 salta a 401333 cioè alla procedura descritta prima |
Qui sotto c'è la procedura di controllo della psw, che è azionata della procedura in 401333, quando i char da prendere sono finiti
| 004012C8 PUSH 19 ; /Count = 19 (25.) 004012CA PUSH due.004021A3 ; |Buffer = due.004021A3 004012CF PUSH DWORD PTR DS:[4020DB] ; |hWnd = 00020104 (class='Edit',parent=000200EE) 004012D5 CALL <JMP.&USER32.GetWindowTextA> ; \GetWindowTextA Prende la psw 004012DA XOR ECX,ECX azzera ecx 004012DC MOV EAX,DWORD PTR DS:[ECX+4021A3] eax=psw inserita 004012E2 MOV EBX,DWORD PTR DS:[ECX+4021A8] ebx=psw generata 004012E8 INC ECX ecx++ 004012E9 CMP EAX,EBX compara eax con ebx 004012EB JNZ SHORT due.004012A2 se diversa va al msg ke dice kiave sbagliata 004012ED MOV AL,BYTE PTR DS:[ECX+4021A3] / 004012F3 MOV BL,BYTE PTR DS:[ECX+4021A8] |Questo controllo è inutile xkè se le due psw 004012F9 TEST AL,AL ! 004012FB JE SHORT due.00401303 |sono uguali continua fino al msg di complimenti 004012FD CMP 004012FF JNZ SHORT due.004012A2 00401301 JMP SHORT due.00401303 00401303 PUSH 20 ; /Style = MB_OK|MB_ICONQUESTION|MB_APPLMODAL 00401305 PUSH due.00402057 ; |Title = "Ce l'hai fatta!!!" 0040130A PUSH due.0040209C ; |Text = "Chiave indovinata...Complimenti!!!" 00401311 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA |
Qui è la msg di errore in caso di psw sbagliata
| 004012A2 PUSH 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL 004012A4 PUSH due.004020DF ; |Title = "No! No! No! E poi Noooooo!!!" 004012A9 PUSH due.004020C3 ; |Text = "Serial sbagliato ;(" 004012AE PUSH 0 ; |hOwner = NULL 004012B0 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA 004012B5 JMP due.00401156 |
Ho descritto tutta la procedura di controllo della psw in ordine cronologico di come vengono effettuate, e non come sono decompilate, in modo da rendere il tutto il + comprensibile possibile ed dato ke non ho tempo di fare il key, vi riporto solo l’implementazione di ror.
Per prima cosa in c++, non c'è ne "ror" quindi bisogna implementarlo, a me stava scritto sul libro di c++, ed ora ve lo riporto.
| long ror(char num,int var) { long a; a = ( num << var) | (a >> 32-var); return a; } |
(NxQUE, non ho pututo mettere la tua implementazione asm, xkè sul cazzo di dev-cpp non funge.Que la devi cancellare se la metti on-line :P)
Qui è tutto il keygeneretor, non l’ho descritto nei minimi particolari, xkè fa le stesse cose ke fa i il prg in as,
| #include<iostream> #include<cstring> using namespace std; long ror(char num,int var); int main(){ char user[] = {0x39, 0x31, 0x32,0x34}; //qui ho inserito l’user in hex, lo potete modificare con “cout” e via dicendo char *key; //qui verrà inserita la psw int hex [] = {0x12, 0x45, 0xd1, 0xff}; //questo è 402000 for (int i=0;i<=strlen(user)-1;i++) { //qui calcola il key key[i] = user[i]^i; key[i] *= i; key[i]-=0x25; key[i] += i; key[i] ^=hex[i]; key[i] += hex[i]; key[i] = key[i] << 2; key[i] = ror(key[i],4); key[i]-=0x5; } for (int i=0;i<=strlen(user)-1;i++) { //qui lo asciizza(by Bonu$) :P while (key[i] > 0x60) { key[i] -=0x12;} while (key[i] < 0x30) { key[i] += 0x18;} cout << key[i]; //stampa il key finale } return 0; } |
Pnluck
| Note finali |
Thenkazzo a tutti gli abitanti di #crack-it. Soprattutto |GeO|, Cr[]w, X-treem, Quake( ke ultimamente non gli sto rompendo + le palle),ad AndreaGeddon, a Que, all sommo(a me ancora inpronunciabile),NtosK, ke mi hanno aiutato x implementare il ror, e poi a Bender0, ke mi ha passato la sua routine(ke è quella ke ho messa), xkè gli altri litigavano x vedere ki aveva fatta la routine + lamera :D
| Disclaimer |
vorrei ricordare che il software va comprato e non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Vi ricordo di pagare anke i creatori dei crackme, in che maniara dipende da loro ma anke dai vostri mezzi ;D
Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.