Giocherellando con WinZip 9.0 | ||
Data |
by "LordMoon" |
|
01/04/2005 |
Published by Quequero | |
Io non ho particolari doti... sono solo appassionatamente curioso Albert Einstein |
questo tutorial � stupendo... hihihihihi bravo lord :)))) |
Tu solamente tu... |
...uhm... |
Finch� il vin dia la terre ,sempre all'acqua guerra guerra.... | |
Difficolt� |
(X)NewBies ( )Intermedio ( )Avanzato ( )Master |
Introduzione |
Tools usati |
URL o FTP del programma |
Essay |
Bene Winzip...
Fase 1:Abbiamo un programma... che facciamo??cerchiamo altri tutorial su quel programma cos� li copio e via...bene, peccato, sulla versione 9 non ce ne sono, per� ne esistono un paio sul sito (ora down) della uic e uno molto completo di(TheMr) che riguardano entrambi la 8.1 da cui tra l'altro potete prendere un keygeneretor opportunamente adattato,anche perch� quello che ho scritto manca di una main e anche di una bella sistematina.QUINDI DA QUESTO MOMENTO IN POI CONSIDERATE QUESTO TUTORIAL SOLO UNA RIEDIZIONE MAGARI AGGIORNATA DELLE DELLE COSE GI� DETTE DA ALTRI .questo solo per essere chiaro(..in realt� prima ho reversato il prog poi ho scoperto che c'erano dei tut...ma ormai l'idea di scrivere questo l'avevo gi� e non posso negare di non essere stato influenzato da questi....)
Fase 2:Spegniamo temporaneamente(spero) il cervello e carichiamo sice.Andiamo sul box della registrazione di winzip,mettiamo una bella bpx dlgitemtexta,scriviamo nome e seriale,premiamo register e voil� sice poppa!!disabilitiamo il bpx e ci troviamo qui sotto...
|
Bene ora visto che non ho voglia di chiudere qui...cerchiamoci un seriale decente... SEMPRE senza usare il cervello...apriamo ida carichiamo winzip entriamo nella call e partiamo dal fondo...e a ritroso andiamo in su fino a cercare qualche call interessante che possa generare un seriale..la prima che incontriamo � la CALL 4A857C ma subito dopo non c'� alcun cmp quindi che caspita genera un seriale a fare??procediamo ancora in su ..incontriamo un paio di call riconosciute tutte da ida...come strlen memset memicmp ecc...e arriviamo all'indirizzo 40DB63...sembra una call nuova...bene subito dopo un bel lea eax,eccetera... e cosa ci sar� mai in eax..???mah proviamo d eax e voil� un bel seriale lo inseriamo nel box di registrazione e via siamo registrati...fine
Mah riuscite anche a capire cosa intendo?..no perch� io rileggendo cosa ho scritto non � che capisca molto....
Dunque FINE.
No...ora il nostro lavoro � di reversare non di craccare programmi(lavoro??perch� ci pagano???) quindi premiamo start (del cervello) e iniziamo il compito...
e prometto di impegnarmi a essere chiaro...in fondo prima avevo il cervello spento!
per prima cosa disassembliamo poco prima della call incriminata...
.text:0040DD19 call ds:GetDlgItemTextA ---> legge il seriale .text:0040DD1F push esi .text:0040DD20 call sub_4701F9 .text:0040DD25 push esi .text:0040DD26 call sub_470222 ---> in 4E6574 c'� l'username .text:0040DD2B cmp byte_4E6574, 0 ---> controlla che non sia vuoto .text:0040DD32 pop ecx .text:0040DD33 pop ecx .text:0040DD34 jz short loc_40DD8F ---> se vuoto salta..quindi � uscita .text:0040DD36 cmp String, 0 .text:0040DD3D jz short loc_40DD8F ---> come prima stesso salto... .text:0040DD3F call sub_40D9AF meglio non saltare...call e poi .text:0040DD44 test al, al ---> un bel test se al=zero allora .text:0040DD46 jz short loc_40DD8F ---> salta...meglio di no quindi dobbiamo fare in modo che al sia diverso da zero!!!
|
partiamo dal fondo e chiediamoci come posso fare "al" diverso da zero e anche come NON fare "al"=zero
|
OK calma e sangue freddo...la call 4A857C non fa assolutamente nulla infatti se ci entrate controlla se ecx uguale a qualcosa se si ret altrimenti salta a report_failure...che sicuramente non ha un nome rassicurante... conclusione questa call non tange "al"... bene passiamo dopo...ehm prima...
incontriamo una Xref all'indirizzo 40DC11....bene vediamo dove porta...ehy siamo finiti all'inizio..non vale io volevo scrivere al contrario,si.. dal fondo verso l'inizio...
.text:0040D9C0
cmp byte_4E6574, 0 .text:0040D9C7 mov [ebp+var_4], eax .text:0040D9CA jnz short loc_40D9D3 .text:0040D9CC xor al, al <--fa eax=zero...meglio di no! .text:0040D9CE jmp loc_40DC11 <--qui salta a dove siamo |
|
bene bene poi?mah direi che salva una stringa strana...poi chiama una call che sottraendo 64h dai valori della stringa ottiene MuradMeraly...bene chi era costui...qui qualcuno della UIC ha scritto che � stato uno dei primi a craccare winzip e questo username non � accettato ...bene bene come dire che � rimasto scioccato!
a questo punto mette in eax MuradMeraly ne calcola la lunghezza e se l'username inserito � pi� corto ok altrimenti errore...per vederlo basta noppare il jb all'indirizzo 40D9F0 e lasciare proseguire il programma da solo
resta un dubbio .A cosa serve eax pushato poco prima della call...:Dice metti MuradMeraly a questo indirizzo puntato da eax.
bene proseguiamo...(se non ve ne siete accorti ora stiamo andando nel verso giusto...!!)
|
fa di nuovo un controllo sull'username....non � ancora convinto che non sia vuoto...e si ve lo risparmio (cmq il succo � che anche qui non deve saltare) e gi� che ci siamo osserviamo che mette l'username in esi..per tutta la durata di questa call da ora in avanti in esi ci sar� l'username.
Ora viene un bellissimo loop che scioltamente vi salto per ragioni dopo spiegate!anzi ve le dico ora...tra poco incontreremo un paio di memset che provvederanno ad azzerare questi risultati...
subito dopo il loop dove siamo?
|
evito di spiegarlo perch� mi sembra banale...
ho la mania di scrivere tutto...e di far impazzire chi legge e detto tra noi anche chi scrive(sempre che io non sia gi� matto... Que il riferimento con una certa frase � del tutto casuale... )
.text:0040DA96 lea eax, [ebp+var_20]<--c'� bcom.Meraly |
credo sia superfluo spiegare il codice..i commenti sono gi� sufficenti!
l'unico puntino sulle i da mettere � all'indirizzo 40DA9B.questa api confronta due stringhe e ritorna eax=0 se sono uguali...subito dopo test eax,eax controlla se eax=zero e se � cosi setta il flag z=1 cos� il jnz non viene eseguito...
dai che siamo quasi a met�!
e anche nel punto interessante!
.text:0040DAE4 xor al, al <--fai al=zero |
"calma e gesso"..ciao paolo!
cosa succede qui?mette l'user in ecx e poi chiama una call.se usate sice vedete che il registro eax viene modificato da questa call...poi salva i primi 16 bit di eax cio� "al" in "bl". le call successive non modificano lo stato di bl e proseguendo in gi� fino al 40DAD4 incontriamo un controllo:se bl=0 allora salta...
domanda:Deve saltare o No?Supponiamo che non salti allora arriviamo all'indirizzo 40DC0E dove fa al=0 e poi salta e arriva dove?basta provare !non ve lo scrivo cmq arriva alla fine della call e trova un bel ret!cio� la call finisce con al=zero e noi non lo possiamo permettere.ricordate lo scopo?era di fare al diverso da zero!
conclusione deve saltare!quindi bl deve essere zero e quindi "al" DEVE essere anche lui da zero!converr� ricordarlo quando andremo ad analizzare la call 40CC74.cio� quando ...?mai!..ehm mai dire mai ed infatti:
.text:0040CC74 mov eax, offset
loc_4B9E36 .text:0040CC79 call __EH_prolog .text:0040CC7E sub esp, 1C0h .text:0040CC84 mov eax, dword_4E2BC0 .text:0040CC89 xor eax, [ebp+4] .text:0040CC8C push esi .text:0040CC8D mov esi, ecx<-ecx contiene l'username e lo mette in esi .text:0040CC8F push esi <-- pusha username... .text:0040CC90 mov [ebp-10h], eax .text:0040CC93 call ds:__imp_lstrlenA <--quanto � lungo? .text:0040CC99 cmp eax, 6 <-- se minore di 6 salta... .text:0040CC9C jl uscita <--qui non deve saltare.. .text:0040CCA2 cmp eax, 28h <-- se maggiore di 28h salta.. .text:0040CCA5 jg uscita <-- qui non deve saltare... .text:0040CCAB xor ecx, ecx <-- ecx=zero .text:0040CCAD test eax, eax <-- eax=0?cio� l'username � nullo? .text:0040CCAD ; se si salta... .text:0040CCAF jle short loc_40CCC7 .text:0040CCB1 mov dl, [ecx+esi] <-- qui c'� un bel loop .text:0040CCB1 ; esi contiene l'username... .text:0040CCB1 ; ecx � usato come incremento .text:0040CCB4 cmp dl, 30h <-- controlla se i caratteri .text:0040CCB4 ; dell'user sono maggiori .text:0040CCB4 ; di 30h e se si non salta.. .text:0040CCB4 ; anche se salta non esce cmq .text:0040CCB7 jb short loc_40CCC2 .text:0040CCB9 cmp dl, 39h ; se sono minori di 39h salta... .text:0040CCB9 ; cio� se sono numeri... .text:0040CCB9 ; visto che per saltare da qui .text:0040CCB9 ; devono essere maggiori di 30h .text:0040CCB9 ; ma minori di 39h .text:0040CCBC jbe uscita <-- qui non deve saltare .text:0040CCC2 inc ecx <-- incrementa ecx cos� .text:0040CCC2 ; esi+ecx punta alla lettera successiva del user .text:0040CCC3 cmp ecx, eax <-- controlla se siamo alla fine del nome .text:0040CCC5 jl short loc_40CCB1 <-- siamo alla fine? non saltare + .text:0040CCC7 push ebx <-- salva ebx..punta alla fine dell'username .text:0040CCC8 xor ebx, ebx <-- ebx=0 .text:0040CCCA inc ebx <-- ebx=1 .text:0040CCCB push ebx <--se va bene..allora poi lo mette a zero... � usato come indicatore .text:0040CCCC push esi <-- salva username
.text:0040CDAA mov eax, [esi] <-- � un loop per controllare l'user
.text:0040CE19 mov al, bl <--mette bl in al..se voglio al= zero |
giusto per intenderci:per reversarla bastava partire dal fondo della call,tenendo presente che al debba essere zero escludo a priori tutti i percorsi (jnz e jz e altri) che mi fanno al diverso da zero...
e si!non sono entrato nei dettagli...per una volta...!!
Le altre call cosa fanno?come spiegato nel codice cancellano i dati passati:cio� l'username(tanto ne abbiamo una copia in esi) e bcom.Meraly il che vuol dire che non li servono pi�...cio� interverranno a rompere nella call ancora da analizzare.NOTA:in realt� memset ,in questo caso,setta a zero il contenuto dell'indirizzo passato.cos� se abbiamo due registri che puntano alla stessa stringa e usiamo memset in realt� cancelliamo il valore del contento di entrambi i registri....solo che qui per l'username abbiamo due indirizza distinti e ne cancelliamo uno!
|
Ok.qui?salva 12Ch nello stack,seguito da un indirizzo e dall'username!chiama una call che da questi tre parametri fa qualcosa.Poi mette lo stesso indirizzo passato alla call prima in eax lo salva nello stack e ne calcola la lunghezza!lungheza che deve essere minore di 12Ch= 300 (minchia lunghetto) altrimenti non salta e solito errore!
dall'indirizzo 40DB22 all'indirizzo 40DB41 fa esattamente la stessa cosa solo che la call chiamata � un altra!evito di riportarvi del codice inutile altrimenti Que mi sgrida ...sigh!
ora ci chiediamo cosa fa la call 40CE5E?beh se in sice poco dopo fate d eax trovate un seriale...
OK genera un seriale...siamo reverser e indovinate che faremo?
reversiamo questa call?si?no!?! .................NI! cio� si ma dopo!
proseguiamo...ecco il pezzo che dovrebbe essere l'ultimo:ehm no quasi, diciamo il quasi ultimo...
|
AhiAhi che casino!con calma...molta calma..!
Se avete letto i commenti avete visto che si ripete un gruppo di istruzioni pi� volte...tuttavia gli ultimi due differiscono dai primi due per una istruzione "inc eax"...Sembra poco ma essendo tutto il codice sul flag z un incremento fa passare da eax=zero (cio� z=0) a eax=1(cio� Z=1).Conclusione devono dare risultati opposti...quindi abbiamo due gruppi di ripetizioni.Si ma perch�?perch� abbiamo due seriali!infatti vengono generati da due call diverse...e se vi chiedete il perch� due seriali diversi....la risposta la d� Que:uno per il decimale e uno per l'esadecimale....e ora mi sento mooolto copione
Resta sempre il dubbio:come mai 4 ripetizioni?ne bastavano due!una per seriale.
si ma mi sa che � una protezione anti errore o anti reverser...efficacissima direi!si ,circa 5 sec per aggirarla, un eternit� per capire l'inutilit�.
bene � commentata e credo sia facile da capire...solo una cosa:cosa fa la call?se ci entrate scoprite che � lunghetta ...sicuramente alloca e libera della memoria...ehm diciamo che fa posto ai seriali in qualche indirizzo??ehm ok non fa niente.fa esattamente la stessa cosa delle call che generano un seriale..solo un pochino di pi�...e con risultati diversi...risultati che per inciso...non vengono presi in considerazione...uhm..sar� mica una perdita di tempo... prontamente dunque la salto
ricordate che incrementare add o decrementare esp fa cambiare lo stato del flag z!!!
quindi possiamo dire:Se le stringhe sono uguali ho che eax=0 e z=0.poi diventa Z=1(add esp...) poi z=0(neg eax).poi un incremento di uno cio� Z=1.alla fine salva il valore del flag in 4E5866 e quindi salta(siccome erano uguali altrimenti il valore del flag � z=0 e quindi non salta...).
Riassunto:se il mio seriale e quello generato sono uguali allora metti 1 in 4E5866 e salta!
dai che siamo alla fine.analizziamo l'ultimo pezzetto di codice!
|
primo siamo arrivati al RET!grande siamo alla fine!fora e coraggio!
come avete capito prima cancella il nostro seriale e quello generato e poi mette in al il valore che aveva salvato prima dopo fa qualcosa di inutile per i nostri scopi ..incontra la call che non fa nulla!l'importante � che ora Z=1 e la nostra richiesta era proprio questo uscire dalla call con Z=1.� solo la conferma che il ragionamento � giusto...
Bene resta solo una cosa da fare:reversare le due call che generano un seriale...
per prima cosa mettiamo i puntini sulle i e ricordiamoci i parametri che richiedevano nello stack:
12Ch ,un indirizzo di memoria (che viene riempito con il seriale generato) e l'username.
Ok iniziamo con la call 40CE5E:
|
Ricordate che bl doveva essere zero?beh se avete dubbi andate a rivederlo.fino a qui il codice � banale.
giusto per fare il punto della situazione...la call � formata da due loop che generano ciascuno un numero...poi questi due numeri vengono uniti da una call...vediamo nei dettagli:
per cominciare arriva il primo loop:
.text:0040CE73 movzx dx, dl <-primo carattere user in dx .text:0040CE77 imul edx, edi <--edx*edi e lo mette in edx .text:0040CE7A add ebx, edx <--ebx+edx e lo mette in ebx .text:0040CE7C inc edi <-- incrementa edi .text:0040CE7D inc esi <-- incrementa esi .text:0040CE7E mov dl, [esi] <--carattere da esi in dl .text:0040CE80 test dl, dl <-- dl � zero? .text:0040CE82 jnz short loc_40CE73 <--arriva qui dal jmp |
Per prima cosa dal jmp all'indirizzo 40CE71 arriviamo al 40CE80,abbiamo dl=0 quindi z=0 e quindi saltiamo a 40CE73.
Mette il valore di dl in dx...(se guardate poche righe sopra vedete che dl contiene il primo carattere dell'username) quindi valore del primo carattere dell'user in dx poi una bella moltiplicazione con edi e risultato in edx,somma edx a ebx(che per ora � zero) e mette il risultato in ebx,incrementa edi(cos� punta al secondo carattere dell'user),incrementa esi ,mette il carattere successivo dell'user in dl e si chiede sono arrivato alla fine oppure no?se sono alla fine non salto + e smetto di fare il loop..(bravo ha fatto rima).
in parole povere:prende un carattere dall'username guarda che posizione ha,ne prende il valore ascii e
ebx=val*n+ebx;
la routine 1:
char username[n]; //con n indico la lunghezza dell'user
int i, j, a;
for ( j = 0 ; j < n ; j++ ) {
i = username[j];
if i == 0 break;
a = i * j + a;
}
fine primo loop...uhm...manca un dettaglio il numero da noi ottenuto � in decimale perch� le operazioni fatto sono in decimale ...per avere il numero corretto bisogna convertirlo in esadecimale...
Ma...siccome la call del secondo seriale fa la stessa cosa ma in decimale...ce ne freghiamo e ci teniamo questo numero
|
gi� che ci siamo notiamo che mette 1 nella variabile all'indirizzo 4E6570:� un check...se c'� uno vuol dire che ho gi� generato il seriale...
ecco il secondo loop:
|
che succede qui?Allora arriviamo all'indirizzo 40CEA5,cl non � zero quindi il jnz viene eseguito e iniziamo il secondo loop!notiamo che all'indirizzo 40CEA2 (pop ecx) mette SEMPRE in ecx il valore 1021h...perch�?lo fa per toglierlo dallo stack...infatti subito dopo lo sovrascrive..Diciamo meglio supponiamo che ora in ecx ci sia 1021h ed esi punti a 61 quindi mov cl,[esi] fa 1061h sovrascrive con il valore ascii il valore di ecx...solo che dopo all'indirizzo 40CE91 si preoccupa di cancellare anche il 10 e cos� resta il 61h.
una considerazione...cosa � il valore che ci interessa?� eax e per scoprirlo basta continuare a leggere...(solo per ragioni pratiche lo ho spiegato verso la fine...)...e dove viene modificato...?nella call ovviamente.
Ora considero che ecx --> i ed esi-->j:
In C la routine 2:
char user[n];
int i=0,j,eax=0;
for (j=0;j<n;j++){
i=user[j];
eax=call_rompi(i,1021h,eax); // h sta per esadecimale
};
per capire bene analizziamo la call che ho chiamato call_rompi...(niente di personale ...solo che fa perdere tempo..)
prima cosa e come al solito ci chiediamo...quali sono i parametri?
Puntatore=Puntatore all'opportuno carattere dell'user(viene incrementato fuori da questa call)
cost=valore fisso di 1021h
e ricordiamo che eax=zero almeno all'inizio(viene azzerato poco prima della chiamata alla funzione)
|
dunque salva 8 nello stack,ecx=0,mette in ch il valore ascii della lettera puntata da esi,edx=8 e salva esi(che contiene l'indirizzo del carattere che ci interessa dell'user).
Ora inizia un loop:mette eax in esi(tanto aveva salvato il valore di esi...),esi xor ecx e risultato in esi,controlla "si" se nullo NON salta e allora eax*2 e eax xor 1021h (e risultato dello xor in eax) poi shifta ecx di 1 a sinistra.Invece se "si" non � nullo salta shifta eax di 1 a sinistra e fa lo stesso per ecx...
Poi in entrambi i casi decrementa edx e se edx= zero non salta altrimenti riprende il loop...(edx � usato qui per controllare il loop).
il parametro importante � eax infatti se guardate poco dopo prima di entrare nell'ultima call(ehm...ok riconosco che per chiarezza non sono proprio un asso...intendevo all'indirizzo 40CEA9 troviamo:
|
vediamo:bx non viene modificato MAI dopo il primo loop.ora viene messo in ecx e poi salvato nello stack.
conclusione ecx non � un risultato che ci interessa(viene cancellato senza essere salvato da nessuna parte),per edx possiamo dire che sar� sempre uguale a zero e per esi beh punta sempre all'username...resta eax
EAX � il registro che ci interessa ed infatti viene pushato nello stack.
solo una cosa ancora ,dh fa parte di edx e insieme a dl forma dx che � un registro a 16bit.e dh sono gli 8 bit alti di dx.quindi sia dx=zero cio� dx=0000 scritto in byte se metto AB in dh viene dx=AB00 se invece metto ab in dl viene dx=00AB.
eccovi il codice in c del loop:cercando di copiare il + possibile il codice...
char user[n];
int call_rompi(int a,int b,int e){
int d;
int c=0;
int esi=0;
c=a;
c=c<<8;
for(d=0;d<8;d++){
esi=e;
esi=esi^c;
if((esi&FFFF)==0){
e=e*2;
e=e^1021;
e=e<<1
}else{
e=e<<1;
c=c<<1;
};
};
return e;
};
ed infine la parte che provvede ad unire i due risultati in uno unico:
|
ricordiamoci che eax viene incrementato di 63h e gli vengono tolti i 16 bit alti es:12345678 -->00005678
chiaro?
bene
char seriale[8];
conclusione(void){
sprintf(seriale,"%04X%04X",((routine2 + 0x63)&0xFFFF),(routine2 &0xFFFF));
printf("il seriale � : %s\n", seriale) ;
};
.....................................................................
bene la main ve la fate voi per esercizio...e mettete insieme anche le variabili..gi� che ci siete
il codice c dovrebbe essere giusto....uhm..conoscendomi � sbagliato. sicuro come l'oro!
beh capito cmq il procedimento il resto salvo errori stupidi � banale...
uffa ho finalmente finito questo tut.
ridendo e scherzando oggi � il 5 ebbene si. Non ho mangiato, non ho dormito e non ho fatto nient'altro...per offrirvi questo tutorial...
Ok sono semplicemente stato occupato all'uni con un gruppo di stagisti liceali che hanno provato l'ebbrezza di fisica e che ci sono innamorati di una ragazza che si chiama Silvia...
E nel frattempo il sito ora non � pi� down...che bello!!!
Mi iniziava a mancare...
Il bello � che non ho bisogno di firmarmi ..i miei tutorial li riconoscete dal numero impressionante di puntini....<---vedi e dal "cervello spento" prima o poi mi decider� a cambiare qualcosina ma nel frattempo....
cmq
luca (lordmoon)
Note finali |
Bene ora i saluti..........
ehm non so da chi iniziare...
Intanto ringrazio Que e saluto tutto lo staff per il servizo che offrite a chi vuole imparare,devo anche ringraziare Zero che una volta mi ha mandato un documento con descritte le varie protezioni anti-sice.
Un saluto speciale v� a Christian(dovunque tu sia,qualunque cosa tu faccia,sarai sempre con noi amico)
Un salutino v� a Stefano,Guido,Aldo,Alessandro,Paolo,Anna,Agnese ed ad altra gente.
Un saluto bello grande v� a Matteo e a Grappolo anche ai 2 Simone e a Diego...che di freni a mani se ne intende..sulla neve
e un Megasaluto v� a Barbara...che mi incanta ogni volta che la vedo!
e a causa della quale perdo tempo e non scrivo tutorial ... Potere donna ;p NdQue
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.