Copy Link
Add to Bookmark
Report

Reverse Engineering di Babylon Translator

DrWatson's profile picture
Published in 
guide hacker
 · 2 Jun 2018

-# intro #-

Babylon Translator è una utility abbastanza utile se si ha a che fare con lingue straniere, in quanto permette con un semplice click la traduzione di una parola qualsiasi in un qualsiasi documento. La versione shareware scade dopo una trentina di giorni, e siamo molto curiosi di vedere come fa il programma a capire la propria scadenza.

-# Considerazioni Generali, ovvero Pre-cracking #-

Una caratteristica dei programmi a tempo è quella di essere, generalmente, legati all'orologio di sistema. I primi programmi a tempo erano facili da bypassare, perchè bastava cambiare la data e tutto filava liscio. Poi le cose sono andate complicandosi. Infatti in alcune applicazioni cambiando la data non si faceva altro che causare la scadenza immediata (la prima applicazione di questo genere che ho incontrato personalmente era Turbo Browser '98, Dicembre '97). Ciò accade anche in Babylon Translator.

Se si cambia la data in avanti nel tempo non succcede niente, non appena la si mette un giorno indietro l'applicazione è scaduta e bisogna registrarla per forza via rete. Però metti che, come nel mio caso, uno non c'ha il modem, c'ha un bordello di traduzioni da fare per il fine settimana ed ha appena buttato il dizionario di inglese nel caminetto perchè siamo in inverno?

-# Reversing Babylon Protection - Parte I #-

Visto che Babylon è una applicazione a tempo ci sarà qualche chiamata API a riguardo. Personalmente quando mi appresto a fare ricerche del genere uso un disassemblatore, perchè ci potrebbero essere diverse funzioni API non-Windows, ma proprietarie del programma, che risiedono in file .dll. Nel nostro caso Babylon ha nella propria directory il file captlib.dll. Facendo 'Anteprima' sul file vediamo che esporta varie funzioni tra cui una un po' sospetta, OpenBabylonDLL. Ed è ora la volta di IDA. Dissassemblando il file nella funzione esportata OpenBabylonDLL c'è l'API GetsystemTime e RegOpenKeyExA come segue:

 
CODE:004020BA 8D 85 D4 FE FF FF lea eax, [ebp+var_12C] ; eax = indirizzo in cui vengono
CODE:004020C0 50 push eax ; salvati i dati dell'orologio
CODE:004020C1 E8 7A CC 00 00 call j_GetSystemTime
CODE:004020C6 8D 55 E8 lea edx, [ebp+var_18]
CODE:004020C9 52 push edx
CODE:004020CA 6A 01 push 1
CODE:004020CC 6A 00 push 0
CODE:004020CE 68 8D 25 42 00 push offset str->SoftwareBa
CODE:004020D3 68 02 00 00 80 push 80000002h
CODE:004020D8 E8 BF CD 00 00 call j_RegOpenKeyExA
CODE:004020DD 85 C0 test eax, eax
CODE:004020DF 0F 85 0C 02 00 00 jnz loc_0_4022F1


Per GetsystemTime la sintassi è:

 
VOID GetSystemTime( LPSYSTEMTIME lpSystemTime // indirizzo della struttura 'Tempo');


quindi eax è quell'indirizzo. La struttura 'Tempo' è questa:

 
typedef struct _SYSTEMTIME { // st
WORD wYear; < - Anno
WORD wMonth; < - Mese
WORD wDayOfWeek;< - Giorno della settimana
WORD wDay; < - Giorno
WORD wHour; < - Ora
WORD wMinute; < - Minuto
WORD wSecond; con la data corrente, la
CODE:004020A6 8B 15 40 23 42 00 mov edx, ds:dword_0_422340 ; | / seconda con i dati sulla
CODE:004020AC 89 55 F4 mov [ebp+Xor_value2], edx ;< -- scadenza


e sono usate prima per decriptare i byte e poi per criptarli nuovamente, a chiasmo (12|21). Così, IndexByData contiene le informazioni sulla data odierna e IndexByExport sui giorni rimanenti.

Con la seguente routine viene decriptata IndexByExport, e controllato che Day_Remaining sia >=0.

 
CODE:004021C0 EB 12 jmp short Start_Xor2
CODE:004021C2 Xor2: ; Routine che decripta
CODE:004021C2 0F BF D0 movsx edx, ax ; IndexByExport usando
CODE:004021C5 8A 4C 15 F4 mov cl, byte ptr [ebp+edx+Xor_value2]; la maschera XOR #2
CODE:004021C9 0F BF D0 movsx edx, ax ; (Xor_value2)
CODE:004021CC 30 8C 15 64 FF FF+xor [ebp+edx+buffer_address], cl ; buffer_addr = dati da
CODE:004021D3 40 inc eax ; decriptare
CODE:004021D4 Start_Xor2: ; buffer_size = dimens.
CODE:004021D4 0F BF C8 movsx ecx, ax ; buffer (4 bytes)
CODE:004021D7 3B 4D EC cmp ecx, [ebp+buffer_size] ;
CODE:004021DA 72 E6 jb short Xor2 ;
CODE:004021DC 66 C7 45 F2 00 00 mov [ebp+Day_Remaining], 0 ; *** memcpy ***
CODE:004021E2 6A 01 push 1 ; num. bytes da copiare
CODE:004021E4 8D 85 64 FF FF FF lea eax, [ebp+buffer_address] ; origine
CODE:004021EA 50 push eax ;
CODE:004021EB 8D 45 F2 lea eax, [ebp+Day_Remaining] ; destinazione
CODE:004021EE 50 push eax ;
CODE:004021EF E8 D4 31 00 00 call _memcpy ; COPIA
CODE:004021F4 83 C4 0C add esp, 0Ch
CODE:004021F7 66 29 75 F2 sub [ebp+Day_Remaining], si
CODE:004021FB 66 83 7D F2 00 cmp [ebp+Day_Remaining], 0 ; Se Day_Remaining è
CODE:00402200 7D 06 jge short Still_some_days ; >= 0, vai avanti


Si capisce che in IndexByExport solo il primo byte è quello significativo, quello che una volta decriptato dà il numero effettivo di giorni rimamenti, il resto dei bytes sono chiacchiere...

Subito dopo il salto, viene 'assemblata' una parola di 4 bytes, di cui il primo valore è quello dei giorni rimanenti. Poi viene salvata nuovamente nel registro...

 
CODE:00402208 Still_some_days:
CODE:00402208 0F B7 95 E2 FE FF+movzx edx, [ebp+Junk_value1]
CODE:0040220F C1 E2 10 shl edx, 10h
CODE:00402212 0F B7 8D E0 FE FF+movzx ecx, [ebp+Junk_value2]
CODE:00402219 C1 E1 08 shl ecx, 8
CODE:0040221C 0B D1 or edx, ecx
CODE:0040221E 0F BF 45 F2 movsx eax, [ebp+Day_Remaining]
CODE:00402222 0B D0 or edx, eax
CODE:00402224 89 55 E4 mov [ebp+Jkval1_Jkval2_Day_Remaining], edx
CODE:00402227 FF 75 EC push [ebp+buffer_size] ; buffer_size = 4 bytes
CODE:0040222A 8D 55 E4 lea edx, [ebp+Jkval1_Jkval2_Day_Remaining]
CODE:0040222D 52 push edx
CODE:0040222E 8D 8D E4 FE FF FF lea ecx, [ebp+XORed_Final_Value]
CODE:00402234 51 push ecx
CODE:00402235 E8 8E 31 00 00 call _memcpy
CODE:0040223A 83 C4 0C add esp, 0Ch
CODE:0040223D 33 C0 xor eax, eax
CODE:0040223F EB 12 jmp short Start_Xor3
CODE:00402241 Xor3: ; Routine di encriptazione
CODE:00402241 0F BF D0 movsx edx, ax
CODE:00402244 8A 4C 15 F4 mov cl, byte ptr [ebp+edx+Xor_value2]
CODE:00402248 0F BF D0 movsx edx, ax
CODE:0040224B 30 8C 15 E4 FE FF+xor [ebp+edx+XORed_Final_Value], cl
CODE:00402252 40 inc eax
CODE:00402253 Start_Xor3:
CODE:00402253 0F BF C8 movsx ecx, ax
CODE:00402256 3B 4D EC cmp ecx, [ebp+buffer_size]
CODE:00402259 72 E6 jb short Xor3
CODE:0040225B FF 75 EC push [ebp+buffer_size]
CODE:0040225E 8D 85 E4 FE FF FF lea eax, [ebp+XORed_Final_Value] ; Valore finale criptato
CODE:00402264 50 push eax
CODE:00402265 6A 03 push 3
CODE:00402267 6A 00 push 0
CODE:00402269 68 CE 25 42 00 push offset str->Indexbye_0
CODE:0040226E FF 75 E8 push [ebp+Bab_Handle_of_open_HKey_data]
CODE:00402271 E8 20 CC 00 00 call j_RegSetValueExA ; Salva valore finale


Il resto della protezione non fa più parte effettivamente della protezione, in quanto la parte critica è appena stata eseguita. La parte finale è:

 
CODE:004022F1 0F BF 45 F2 movsx eax, [ebp+Day_Remaining]
CODE:004022F5 8B 55 08 mov edx, [ebp+Addr_Day_Remaining]
CODE:004022F8 89 02 mov [edx], eax
CODE:004022FA 85 DB test ebx, ebx ; Se ebx=1, app scaduta
CODE:004022FC 74 04 jz short loc_0_402302
CODE:004022FE 33 C0 xor eax, eax
CODE:00402300 EB 04 jmp short loc_0_402306
CODE:00402302 loc_0_402302:
CODE:00402302 0F BF 45 F2 movsx eax, [ebp+Day_Remaining]
CODE:00402306 loc_0_402306:
CODE:00402306 5E pop esi
CODE:00402307 5B pop ebx
CODE:00402308 8B E5 mov esp, ebp
CODE:0040230A 5D pop ebp
CODE:0040230B C2 04 00 retn 4


, e non fa altro che spostare i giorni rimanenti in un indirizzo che viene utilizzato per visualizzarli nel programma, nella dialog box di informazioni.

Ora che la protezione è stata spiegata del tutto sta a voi modificare il flusso del programma o cambiare i valori nel registro per avere il massimo dei giorni possibili. Questo numero non può superare i 255 giorni, poichè Day_Remaining è di 1 byte (FF=255).

-# Conclusione #-

Se mi è stato possibile analizzare nei particolari questa routine di protezione è stato grazie ad IDA. E' possibile scaricarlo dalla pagina di Iczelion (iczelion.cjb.net) e per utilizzarlo al meglio sarebbe bene leggere la essay di +mammon su fravia o sul suo sito stesso. Se riceverò abbastanza richieste farò la traduzione del 'manuale di Ida' di +mammon.

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT