Giocherellando con  WinZip 9.0
(e divertiamoci pure!)

Data

by "LordMoon"

 

01/04/2005

UIC's Home Page

Published by Quequero

Io non ho particolari doti... sono solo appassionatamente curioso

Albert Einstein

questo tutorial � stupendo...

hihihihihi bravo lord :))))

Tu solamente tu...

...uhm...

Home page:Nahh
E-mail: bottonim@yahoo.it
....boh...

Finch� il vin dia la terre ,sempre all'acqua guerra guerra....

Difficolt�

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

 

 

Introduzione

Bene ben trovati a tutti..questo � il mio secondo tut(a distanza di quasi due anni) il nick lordmoon � solo per compatibilit� con le versioni precedenti ehm volevo dire per chi mi conosceva ancora cos�,ma francamente ora preferisco essere chiamato luca ...e si con la l minuscola...
Beh WinZip lo conoscete tutti...la protezione � banale ,non � cambiata dalla versione precedente solo c'� la richiesta che l'username sia pi� lungo(...averlo saputo prima ,cos� evitavo di reversarlo) come tutorial � in teoria semplicissimo ma reso (forse) impossibile dalla mia capacit� di spiegarmi!
 

Tools usati


Ida
Sice
Un Cervello(quasi acceso,forse lo trovate in internet su ebay)

URL o FTP del programma

Mah che ne dite di cercare nel vostro HardDisk...sono quasi certo che lo troviate.altrimenti cercatelo in internet

Essay

Allora per prima cosa un dovere...
nel mio prima tutorial avevo promesso che il tut successivo sarebbe stato su ida e su opera....
sono paccati con lo stesso programma...entrate con sice nella prima call arrivate al primo jmp condizionato non eseguito(credo un jnz) e mettete un bpx all'indirizzo di arrivo di quel jmp...F5 e via siete all'OEP l� dumpate.
opera era molto facile da craccare...ida impossibile perch� mancavano un 10Mb di file...sigh
cmq a parte questi file mancanti si cracca facilmente anche con wdasm.a parte il salvataggio...l� per risolvere basta farla crashare perch� esiste il salvataggio automatico dopo un p� di minuti...il file salvato risulta danneggiato....a meno a che non lo facciate chiudere per benino...beh � solo un idea arrangiatevi!!!il tut non riguarda ida

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...


.text:0040DCF7 call ds:GetDlgItemTextA ----> siamo qui...
.text:0040DCFD push edi
.text:0040DCFE call sub_4701F9
.text:0040DD03 push edi
.text:0040DD04 call sub_470222
.text:0040DD09 pop ecx
.text:0040DD0A pop ecx
.text:0040DD0B push 0Bh ; nMaxCount
.text:0040DD0D mov esi, offset String
.text:0040DD12 push esi ; lpString
.text:0040DD13 push 0C81h ; nIDDlgItem
.text:0040DD18 push ebx ; hDlg
.text:0040DD19 call ds:GetDlgItemTextA
.text:0040DD1F push esi
.text:0040DD20 call sub_4701F9
.text:0040DD25 push esi
.text:0040DD26 call sub_470222
.text:0040DD2B cmp byte_4E6574, 0
.text:0040DD32 pop ecx
.text:0040DD33 pop ecx
.text:0040DD34 jz short loc_40DD8F
.text:0040DD36 cmp String, 0
.text:0040DD3D jz short loc_40DD8F
.text:0040DD3F call sub_40D9AF
.text:0040DD44 test al, al
.text:0040DD46 jz short loc_40DD8F
.text:0040DD48 push edi
.text:0040DD49 push offset aName ; "Name"
.text:0040DD4E mov edi, offset AppName ; "WinZip"
Ora siccome non voglio assolutamente pensare....sono stanco perch� ho avuto un esame stamattina...seguiamo il codice steppando con F10 senza entrare nelle call e notiamo che viene eseguito un salto all'indirizzo 40DD46...poi non ci sono altri salti condizionati ma appare una msgbox.."hey bello non hai inserito il serial giusto!!!!".Ok qui non ci deve arrivare...allora bpx in sice all'indirizzo 40DD46 e gli diciamo guarda che ti stai sbagliando non devi saltare...detto meglio noppiamo il jz (cio� 90 90...ahiahi come mi sono ridotto...una volta avrei detto cambiate il flag...sigh � l'et� che si fa sentire...) bene dicevo premete ora F5 e via il prog dice complimenti hai inserito il seriale giusto...accetti la licenza???che CxxxO di domanda.. No non accetto!!!...uffa accettate la licenza e ahi winzip � molto furbo ed � ancora in versione shareware....uhm...altri controlli..???allora uno che pensa cerca i controlli....io sono diverso ed il cervello l'ho lasciato assieme agli occhi su una ragazza stupenda in corso con me...cos� ne faccio a meno e dico bene il controllo che ho superato deve essere subito prima del jz...quindi entro nella call 40D9AF e ci metto un bel breakpoint...premo F5 e ogni volta che sice poppa esco dalla call con F12 e poi modifico il jump condizionato...chiudo winzip lo riavvio modifico ancora qualche altro jmp condizionato  e via crack finito.

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!!!

 

Bene siamo giunti alla conclusione che la call 40D9AF debba restituire al diverso da zero...ora analizziamo la call

partiamo dal fondo e chiediamoci come posso fare "al" diverso da zero e anche come NON fare "al"=zero

.text:0040DC06 mov al, byte_4E5866
.text:0040DC0B add esp, 18h
.text:0040DC0E pop edi
.text:0040DC0F pop esi
.text:0040DC10 pop ebx
.text:0040DC11 mov ecx, [ebp+var_4]    Xref
.text:0040DC14 xor ecx, [ebp+4]
.text:0040DC17 call sub_4A857C ; non fa nulla...
.text:0040DC1C leave
.text:0040DC1D retn

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
Cosa possiamo dire?semplice dal jmp in 40D9CE non deve passare...allora deve saltare dal jnz ...guardiamo poco prima la cmp che dice :se il byte in 4E6574 � zero non saltare...bene non deve essere vuoto...ma cosa c'� in quel byte?se provate con un debugger o con ida se avete una versione recente.. scoprite che c'� il vostro  username...OK se l'username non � vuoto salta...!!!
.text:0040D9D3 lea eax, [ebp+var_20]
.text:0040D9D6 push eax <--bene a cosa serve?
.text:0040D9D7 push offset aC_0 <--� una stringa fissa
.text:0040D9DC call sub_40124F <--crea MuradMeraly
.text:0040D9E1 lea eax, [ebp+var_20] <--e lo mette in eax
.text:0040D9E4 push eax
.text:0040D9E5 call _strlen
.text:0040D9EA add esp, 0Ch
.text:0040D9ED cmp eax, 14h
.text:0040D9F0 jb short loc_40DA00
.text:0040D9F2 push 6Ah
.text:0040D9F4 push offset aAuth_c ; "auth.c"
.text:0040D9F9 call sub_42068A
.text:0040D9FE pop ecx
.text:0040D9FF pop ecx

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...!!)

.text:0040DA00 cmp username, 0 <--� vuoto?
.text:0040DA07 push ebx
.text:0040DA08 push esi
.text:0040DA09 mov esi, offset username<-username in esi
.text:0040DA0E push edi
.text:0040DA0F lea edi, [ebp+username]
.text:0040DA15 mov ebx, esi
.text:0040DA17 jz short loc_40DA32 <--meglio non saltare.

 

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?

.text:0040DA35 lea eax, [ebp+username] <--user in eax
.text:0040DA3B push eax <-- username
.text:0040DA3C call _strlen
.text:0040DA41 mov edi, 0C8h
.text:0040DA46 cmp eax, edi<-se � + lungo di C8 non salta
.text:0040DA48 pop ecx
.text:0040DA49 jb short loc_40DA59<--meglio saltare...

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:0040DA59 lea eax, [ebp+username]<--user in eax
.text:0040DA5F push eax
.text:0040DA60 lea eax, [ebp+var_20]<--MuradMeraly in eax
.text:0040DA63 push eax
.text:0040DA64 call __stricmp <--li confronta e...niente.
.text:0040DA69 lea eax, [ebp+var_20]<--MuradMeraly in eax
.text:0040DA6C push eax
.text:0040DA6D push offset aB ; "�����"
.text:0040DA72 call CreaStringa<-MuradMeraly->bcom.Meraly
.text:0040DA77 lea eax, [ebp+var_20] <--e la mette in eax
.text:0040DA7A push eax
.text:0040DA7B call _strlen <--controlla la lunghezza
.text:0040DA80 add esp, 14h
.text:0040DA83 cmp eax, 14h <--salta se minore di 14h=20d
.text:0040DA86 jb short loc_40DA96 <--meglio saltare

.text:0040DA96 lea eax, [ebp+var_20]<--c'� bcom.Meraly
.text:0040DA99 push eax <-- salva bcom.Meraly
.text:0040DA9A push esi <--salva l'username
.text:0040DA9B call __stricmp <-- e li confronta..
.text:0040DAA0 test eax, eax <--eax=0 se e solo se uguali
.text:0040DAA2 pop ecx
.text:0040DAA3 pop ecx
.text:0040DAA4 jnz short loc_40DAAC <--se sono uguali non salta...

 

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:0040DAAC mov ecx, esi <--in esi c'� l'username
.text:0040DAAE call sub_40CC74 <--cosa fa?
.text:0040DAB3 push 14h
.text:0040DAB5 mov bl, al <-- mette al in bl...
.text:0040DAB7 lea eax, bcom.Meraly
.text:0040DABA push 0
.text:0040DABC push eax
.text:0040DABD call _memset <--cancella il contento
.text:0040DAC2 push edi
.text:0040DAC3 lea eax, username
.text:0040DAC9 push 0
.text:0040DACB push eax
.text:0040DACC call _memset<--cancella l'username
.text:0040DAD1 add esp, 18h
.text:0040DAD4 test bl, bl <--bl=zero?...
.text:0040DAD6 jz short loc_40DAEB <--se si salta..

.text:0040DAE4 xor al, al <--fai al=zero
.text:0040DAE6 jmp loc_40DC0E

 

 "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:0040CD1D cmp byte ptr [ebp-11h], 0
.text:0040CD21 jnz loc_40CE0D <-- bl=1 per ora...se salta resta cos�
.text:0040CD21 ; e poi non viene modificato
.text:0040CD21 ; e noi invece vogliamo bl=0

 

.text:0040CDAA mov eax, [esi] <-- � un loop per controllare l'user
.text:0040CDAC cmp byte ptr [eax], 0
.text:0040CDAF jz short loc_40CE01 <-- se salta allora errore
.text:0040CDB1 lea ecx, [ebp-1CCh]
.text:0040CDB7 push ecx
.text:0040CDB8 push eax
.text:0040CDB9 call CreaStringa <--crea diversi user tutti non accetti
.text:0040CDBE pop ecx
.text:0040CDBF pop ecx
.text:0040CDC0 push ebx
.text:0040CDC1 lea eax, [ebp-1CCh]
.text:0040CDC7 push eax
.text:0040CDC8 lea ecx, [ebp-7Eh]
.text:0040CDCB call sub_438610
.text:0040CDD0 push 2
.text:0040CDD2 push eax
.text:0040CDD3 lea ecx, [ebp-38h]
.text:0040CDD6 mov byte ptr [ebp-4], 5
.text:0040CDDA call sub_436F25
.text:0040CDDF lea ecx, [ebp-7Eh]
.text:0040CDE2 mov [ebp-11h], al
.text:0040CDE5 mov byte ptr [ebp-4], 2
.text:0040CDE9 call sub_436EA5
.text:0040CDEE cmp byte ptr [ebp-11h], 0
.text:0040CDF2 jnz short loc_40CE01 <-- se salta allora c'� errore
.text:0040CDF4 add esi, 4
.text:0040CDF7 cmp esi, offset off_4DFDA0
.text:0040CDFD jl short loc_40CDAA
.text:0040CDFF xor bl, bl <-- prima ha messo bl=1 ora  fa bl=zero...
.text:0040CDFF ; e se le call non modificano bl
.text:0040CDFF ; allora � quello che vogliamo
.text:0040CDFF ; in pratica se va tutto bene
.text:0040CDFF ; deve passare per qui
.text:0040CE01 and byte ptr [ebp-4], 0

 

.text:0040CE19 mov al, bl <--mette bl in al..se voglio al= zero
.text:0040CE19 ; deve essere bl=zero
.text:0040CE1B pop ebx
.text:0040CE1C jmp short loc_40CE20 <-- dobbiamo passare di qui
.text:0040CE1E mov al, 1 <-- di qui � meglio non passare..

.text:0040CE31 call sub_4A857C <--se ci entro scopro che non fa nulla
.text:0040CE36 leave
.text:0040CE37 retn <--vogliamo che al sia 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!

.text:0040DAEB mov edi, 12Ch
.text:0040DAF0 push edi <--salva 12Ch
.text:0040DAF1 lea eax, [ebp+indirizzo]<--� un indirizzo
.text:0040DAF7 push eax <-- salva questo indirizzo
.text:0040DAF8 push esi <--salva l'username
.text:0040DAF9 call sub_40CE5E
.text:0040DAFE lea eax, [ebp+indirizzo]<--lo stesso indirizzo di prima?
.text:0040DB04 push eax <--qui trovo un seriale...
.text:0040DB05 call _strlen <--che lunghezza ha?
.text:0040DB0A add esp, 10h
.text:0040DB0D cmp eax, edi <--deve essere minore di 12Ch
.text:0040DB0F jb short loc_40DB22 <--deve saltare...

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... :-D

.text:0040DB54 lea eax, [ebp+var_C]
.text:0040DB57 push eax
.text:0040DB58 lea eax, [ebp+var_8]
.text:0040DB5B push eax
.text:0040DB5C mov ebx, offset String<--c'� il mio serial
.text:0040DB61 push ebx <---salva il mio seriale
.text:0040DB62 push esi <--salva il mio username
.text:0040DB63 call sub_40D0AE <--- ma che fa??????
.text:0040DB68 lea eax, [ebp+indirizzo]<--solito indiriz
.text:0040DB6E push ebx <--qui c'� il mio seriale
.text:0040DB6F push eax <--qui c'� il seriale generato
.text:0040DB70 call __stricmp <--li confronta
.text:0040DB75 add esp, 18h<--cambia stato al flag z
.text:0040DB78 neg eax <---nega eax (anche al e anche z)
.text:0040DB7A sbb al, al <--se al=zero non fa nulla
.text:0040DB7C inc al <---incrementa al di uno
.text:0040DB7E mov byte_4E5866, al <--salva il val di al
.text:0040DB83 jnz short loc_40DBE8<-se il flag � 0 salta
.text:0040DB85 lea eax, [ebp+var_14C]
.text:0040DB8B push ebx
.text:0040DB8C push eax
.text:0040DB8D call __stricmp
.text:0040DB92 neg eax
.text:0040DB94 sbb al, al
.text:0040DB96 pop ecx
.text:0040DB97 inc al<--si ripete come prima fino al jnz
.text:0040DB99 pop ecx
.text:0040DB9A mov byte_4E5866, al
.text:0040DB9F jnz short loc_40DBE8
.text:0040DBA1 push 4 <--si ripete ancora come prima
.text:0040DBA3 lea eax, [ebp+var_148]
.text:0040DBA9 push eax
.text:0040DBAA push ebx
.text:0040DBAB call __memicmp
.text:0040DBB0 add esp, 0Ch
.text:0040DBB3 test eax, eax
.text:0040DBB5 jnz short loc_40DBDA <--fino a qui
.text:0040DBB7 push 4  <--di nuovo da qui
.text:0040DBB9 lea eax, [ebp+var_14C]
.text:0040DBBF push eax
.text:0040DBC0 push offset unk_4E65A4
.text:0040DBC5 call __memicmp
.text:0040DBCA add esp, 0Ch
.text:0040DBCD test eax, eax
.text:0040DBCF jnz short loc_40DBDA <--fino a qui
.text:0040DBD1 mov byte_4E5866, 1
.text:0040DBD8 jmp short loc_40DBE8

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!

.text:0040DBE8 push edi
.text:0040DBE9 lea eax, [ebp+indirizzo]
.text:0040DBEF push 0
.text:0040DBF1 push eax
.text:0040DBF2 call _memset<-cancella il contenuto di eax
.text:0040DBF7 push edi
.text:0040DBF8 lea eax, [ebp+var_14C]
.text:0040DBFE push 0
.text:0040DC00 push eax
.text:0040DC01 call _memset <--cancella ancora
.text:0040DC06 mov al, byte_4E5866  <--rimette a posto al
.text:0040DC0B add esp, 18h
.text:0040DC0E pop edi
.text:0040DC0F pop esi
.text:0040DC10 pop ebx
.text:0040DC11 mov ecx, [ebp+var_4]
.text:0040DC14 xor ecx, [ebp+4]
.text:0040DC17 call sub_4A857C <--non fa un CxxxO...
.text:0040DC1C leave
.text:0040DC1D retn

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:

.text:0040CE5E push ebp
.text:0040CE5F mov ebp, esp
.text:0040CE61 mov ecx, [ebp+USERNAME]
.text:0040CE64 mov dl, [ecx]<--primo carattere user in dl
.text:0040CE66 push ebx <--un indirizzo(bl � 0 per prima)
.text:0040CE67 push esi <--username
.text:0040CE68 push edi <--contiene 12Ch
.text:0040CE69 xor ebx, ebx <--ebx=0
.text:0040CE6B xor eax, eax <--eax=0
.text:0040CE6D mov esi, ecx <--rimette l'username in esi
.text:0040CE6F xor edi, edi <--edi=0
.text:0040CE71 jmp short loc_40CE80

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

.text:0040CE84 mov byte_4E6570, 1 <--byte_4E6570 = 1
.text:0040CE8B mov esi, ecx <--esi=ecx(mette user in esi)
.text:0040CE8D mov cl, [ecx] <--cl = [ecx]
.text:0040CE8F jmp short loc_40CEA5 <--beh...salta

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:

.text:0040CE91 movzx ecx, cl <--valore ascii da cl in ecx
.text:0040CE95 push 1021h <--salva 1021h
.text:0040CE9A push ecx <--salva ecx(valore ascii)
.text:0040CE9B call ParteDiUnSeriale <-call da analizzare
.text:0040CEA0 pop ecx <-salva ecx(val ascii = a prima)
.text:0040CEA1 inc esi <-- incrementa esi
.text:0040CEA2 pop ecx<-1021 in ecx,serve toglierlo stack
.text:0040CEA3 mov cl, [esi] <--lettera da esi in cl
.text:0040CEA5 test cl, cl <--arriviamo qui e cl non � 0
.text:0040CEA7 jnz short loc_40CE91

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)

.text:0040CE38 push ebp
.text:0040CE39 mov ebp, esp
.text:0040CE3B push 8 <--salva 8 nello stack
.text:0040CE3D xor ecx, ecx <-- ecx=0
.text:0040CE3F mov ch, [ebp+
Puntatore]<--val ascii in ch
.text:0040CE42 pop edx <--edx ora � 8
.text:0040CE43 push esi <-- esi punta al carattere user
.text:0040CE44 mov esi, eax <--inizio loop,eax in esi
.text:0040CE46 xor esi, ecx <--esi xor ecx e risul in esi
.text:0040CE48 test si, si <--si � zero?
.text:0040CE4B jns short loc_40CE54 <--se si non saltare!
.text:0040CE4D add eax, eax <--eax*2
.text:0040CE4F xor eax, [ebp+cost]<--eax xor cost
.text:0040CE52 jmp short loc_40CE56
.text:0040CE54 shl eax, 1  <--shifta di 1 a sinistra
.text:0040CE56 shl ecx, 1  <--shifta di 1 a sinistra
.text:0040CE58 dec edx  <--decrementa edx
.text:0040CE59 jnz short loc_40CE44<--se edx=0 NON salta
.text:0040CE5B pop esi <--riprenditi esi
.text:0040CE5C pop ebp
.text:0040CE5D retn

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:

.text:0040CEA9 movzx ecx, bx <-- cancella ecx e mette bx
.text:0040CEAC add eax, 63h <--eax � il param importante
.text:0040CEAF push ecx <-- salva ecx
.text:0040CEB0 movzx eax, ax <--mette ax in eax
.text:0040CEB3 push eax <-- salva eax nello stack

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:

.text:0040CEAC add eax, 63h<--eax � il parametro importan
.text:0040CEAF push ecx <--nello stack
.text:0040CEB0 movzx eax, ax <--via gli ultimi 16 bit
.text:0040CEB3 push eax <--nello stack
.text:0040CEB4 push offset a04x04x <--salvo "%04X%04X"
.text:0040CEB9 push [ebp+ParametroPassato(12Ch)]
.text:0040CEBC mov byte_4E65E0, 1
.text:0040CEC3 push [ebp+IndirizzoDaRiempire]
.text:0040CEC6 call sub_4B85A1<--printf formato %04x%04x

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.