Tutorial per Babylon

Babylon, per chi non lo conosce, Φ un traduttore simultaneo
italiano-inglese molto utile. Come migliaia di altri programmi
Φ per≥ in versione shareware o precisamente in versione demo,
completa e funzionante per 100 giorni. Dopo la scadenza di tale
data il programma non funziona pi∙.

Partir≥ dal presupposto che si abbia SoftIce installato.

Detto questo iniziamo il vero 'attacco':

Io mi diverto a vedere ci≥ che i programmi visualizzano una 
volta che il loro tempo di valutazione Φ scaduto, perci≥
mandiamo avanti l'orologio di qualche mesetto (un salto nel
futuro fa sempre bene...) e notiamo che all'avvio il programma
ci avverte con una MessageBox che la versione Φ scaduta, bla,
bla, bla. Diamo l'Ok e notiamo che non Φ pi∙ possibile attivare
il programma.

Ok, la protezione Φ stupida... ci avverte addirittura con una
MessageBox che il programma Φ scaduto...
Entriamo in SoftIce e settiamo un breakpoint (bpx) per la 
MessageBox. Avviamo babylon e ci ritroviamo nel bel mezzo della
funzione desiderata. Usciamo con F11 e premiamo 'OK'. SoftIce 
ritorna visibile puntando alla linea del codice successiva alla
funzione. Strano...

Se guardiamo in che modulo ci troviamo (sulla linea che delimita
il codice dalla parte in cui si scrivono i comandi) notiamo di
essere in CAPTLIB!CODE+105A.
Pi∙ chiaro di cos∞...
Apriamo W32Dasm e disassembliamo il file captlib.dll. 
Posizioniamoci nell'entrata del programma (Program Entry Point) e
aggiungiamo all'indirizzo 105Ah (401000h + 105Ah = 40205Ah).
Andiamo a quell'indirizzo e, magia delle magie, siamo proprio
nel punto in cui viene chiamata la funzione MessageBoxA.
Essendo in una DLL possiamo cercare di capire in che funzione 
esportata siamo. Risaliamo per qualche pagina e il codice e ci
troviamo all'inizio della funzione che Φ OpenBabylonDLL.

Senza neanche farlo apposta cosa troviamo una manciata di righe 
pi∙ sotto? Ma GetSystemTime, ovviamente...
Che questa funzione verifichi solamente se Babylon Φ scaduto?
Noooo... Chi mai pu≥ dirlo...

Osserviamo il resto del codice:

- una chiamata a RegOpenKeyEx
- due chiamate a RegQueryValueEx
- due chiamate a RegSetValueEx
- una chiamata a RegCloseKey
- una chiamata a wsprintf
- una chiamata a GetForeGroundWindow
- una chiamata a MessageBox

Usciamo da Babylon e ritorniamo in SoftIce. Impostiamo un 
breakpoint per GetSystemTime e avviamo Babylon. SoftIce ci 
riporta alla funzione OpenBabylonDLL e precisamente nel 
suo entry point. Avanziamo fino ai due RegQueryValueEx e 
osserviamo ci≥ che viene immagazzinato nello stack 
(attraverso l'istruzione push).

:00401E03 52                      push edx
:00401E04 683F000F00              push 000F003F
:00401E09 6A00                    push 00000000
:00401E0B 6801254200              push 00422501 ; <-- Qui
:00401E10 6802000080              push 80000002

* Reference To: ADVAPI32.RegOpenKeyExA, Ord:0000h
                                  |
:00401E15 E8A8CD0000              Call 0040EBC2

:00401E33 50                      push eax
:00401E34 6A00                    push 00000000
:00401E36 6A00                    push 00000000
:00401E38 6828254200              push 00422528 ; <-- Qui
:00401E3D FF75E8                  push [ebp-18]

* Reference To: ADVAPI32.RegQueryValueExA, Ord:0000h
                                  |
:00401E40 E871CD0000              Call 0040EBB6

Nel codice qui riportato notiamo le due funzioni e in corrispondenza
di 'Qui' un indirizzo che ci riporta alla chiave del registro che 
viene prima aperta e poi letta da RegQueryValueEx.
La chiave Φ dunque la seguente:
HKLM\Software\Babylon\Babylon Translator\b1
La prima stringa richiesta Φ IndexByData mentre la seconda Φ 
IndexByExport.

Osservando il codice che Φ tra le due funzioni RegQueryValueEx ci 
rendiamo conto che Φ dove avviene il controllo dei giorni.
Tra le molte linee ne evidenzio solo alcune che sono, in pratica,
una seconda protezione che permette di mascherare in parte la data
vera e propria:

:00401E51 0FBFD0                  movsx edx, ax
:00401E54 8A4C15F8                mov cl, byte ptr [ebp+edx-8]
:00401E58 0FBFD0                  movsx edx, ax
:00401E5B 308C1564FFFFFF          xor byte ptr [ebp+edx-9C], cl
:00401E62 40                      inc eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401E4F(U)
|
:00401E63 0FBFC8                  movsx ecx, ax
:00401E66 3B4DEC                  cmp ecx, dword ptr [ebp-14]
:00401E69 72E6                    jb 00401E51

Ebbene in queste poche linee avviene la decifrazione della data 
criptata e appena prelevata dalla chiave dall'innocente nome 
IndexByData.
Da notare che tutto il processo Φ legato unicamente all'xor di 401E5B
i cui membri sono il valore prelevato dal registro (un byte alla volta) 
e dei valori prelevati da una tavola che Φ la seguente:

37 C2 9A 23 DC B3 41 F8

(valori in esadecimale)

Il codice seguente ricava i giorni totali (sfruttando la struttura
SYSTEMTIME, consultate la guida API per ulteriori informazioni) 
e si porta alla chiamata successiva passando per≥ per un punto 
rilevante:

:00401EC1 6685F6                  test si, si
:00401EC4 7D0A                    jge 00401ED0
:00401EC6 BB01000000              mov ebx, 00000001
:00401ECB E956010000              jmp 00402026

in 401EC4 il programma decide infatti se Φ ancora entro i 100 giorni
oppure no settando ebx se la versione Φ scaduta.

La seconda chiamata a RegQueryValueEx che ritorna il valore di 
IndexByExport Φ utile al programma stesso per calcolare quanti giorni
rimangono alla fine della valutazione ma non ha importanza per quanto 
riguarda la protezione.

A questo punto possiamo applicare svariate patch per valutare il 
programma ancora un p≥ di giorni (settimane, mesi, anni, secoli...):
possiamo sostituire a mov ebx, 1 mov ebx, 0 in 401EC6 e il programma
funzionerα anche quando Φ scaduto oppure possiamo evitare di eseguire
le funzioni RegSetValueEx che registrano i cambiamenti di data e fanno 
quindi avanzare l'orologio del programma...
Insomma, si possono trovare svariate soluzioni, dalle pi∙ semplici alle 
pi∙ complicate, il tutto Φ a piacere...

The_Dux