Cracking di Koala Term 4.4 Build 2115

Data

by Epokh

�

19/01/2005

UIC's Home Page

Published by Quequero

Ci vestimmo con lembi di vento, colorati di nembi di cielo. Percorremmo le strade del monte, incontrando le genti del mondo. Solo alcuni ci riconobbero, non furono molti.

Davvero un bel tute, bravo Epo e grazie

Meno ancora trovarono il tempo di sedersi a parlare con noi. Eppure, quante cose avevamo da dire, quanto tempo per potervi ascoltare.

[ Salm Delmai]

....

 
E-mail: [email protected]

....

Difficolt�

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

�
�

Introduzione

Quando reversate non gettate mai la spugna!

Tools usati

SoftIce 4.05
W32Dasm 89
OllyDBG
File Monitor
Registry Monitor

URL o FTP del programma

Koala Term 4.4 della Foxit Software
 

Notizie sul programma

Koala Term è un emulatore di terminale che permette di collegarci ad un host mediante telnet, porta seriale e modem .

Essay

Il programma in questione è un trial: il periodo di prova è di 30 giorni, durante i quali quando facciamo Connection->New.. una MessageBox fa il popup e ci avvisa che mancano x<=30 giorni alla scadenza del trial. Dopo il 30-esimo giorno, il programma smette di funzionare dopo 20 minuti.
Il programma nel menu Register ci fornisce le informazioni necessarie per acquistarlo: dopo il pagamento la FoxitSoftware ci invia un file che dobbiamo mettere nella stessa cartella dove si trova l'eseguibile mkt.
In questo modo ci siamo già fatti un idea del tipo di protezione che il programma usa, essenzialmente un key file ed è lì che andremo ad insistere.
 
Ricostruire il key file è l'approccio più difficile per crackare questo programma perchè quello più facile consiste nel:
1) disabilitare la MessageBox che fa popup quando clickiamo su Connection->New
2) disabilitare la chiamata alla SetTimer in cui il parametro del timeout uElapse=20*60*1000 millisecondi che in esadecimale sono 124F80 millisecondi.
Infatti se disassembliamo con WDasm fra le funzioni importate troviamo proprio quelle attese:
USER32: MessageBoxA, MessageBeep candidate per la finestra di popup
USER32: SetTimer per il timer di 20 minuti
 
Quindi usando il SoftIce e impostando i break point sulle funzioni suddette il gioco è fatto, ma noi che siamo persone serie vogliamo reversare il key file.
Appurato che il programma deve leggere un file nella sua stessa directory usiamo File Monitor. Eseguiamo per primo il file monitor, impostando come filtro mkt.exe, poi lanciamo mkt.exe e lo terminiamo. Salviamo i log del file monitor, apriamo il file di log, copiamone il contenuto e incolliamolo su un foglio di excel in modo da analizzare più facilmente tutte le chiamate (Excel riconosce automaticamente la divisione in colonne, ottimo!).
Fra tutte le chiamate dobbiamo cercare quelle il cui path si riferisce alla directory in cui è presente mkt.exe, nel mio caso è per esempio C:\Documenti\MKT\MKT.exe ed il risultato è questo:

 

--Processo---|---- File --------------------|----Stato-------|-----Operazione---

    Mkt       C:\Documenti\MKT\kltkey.txt        NOTFOUND          GetAttributes

    Mkt       C:\Documenti\MKT\klt.key           NOTFOUND          GetAttributes     

 
 
Le osservazioni che possiamo fare subito:
a) l'eseguibile mkt.exe legge se stesso, questo ha comunque a che fare con la protezione di 30 giorni che tratteremo alla fine.
b)il programma chiama GetAttributes su due file chiamati KLTKEY.TXT e KLT.KEY

Attenzione: queste operazioni vengono fatte all'avvio del programma, è scontato ma è meglio precisarlo quindi non sono triggerate da qualche evento.

Beh ragazzi, i nomi dei due file parlano da soli: quindi sembrerebbe che i file di registrazione necessari sono 2,ma sulla info. di registrazione la Foxit ci diceva che il key file era uno. Probabilmente uno dei due file è necessario per compatibilità con i key file delle versioni precedenti di KoalaTerm.

Tuttavia la chiamata a GetAttributes è un po strana: non esiste ! Esiste invece GetFileAttributes, (evidentemente RegMonitor sottointende il File visto che fa solo quello) che a pensarci su, al programma non serve a niente! Gli attributi di un file sono normal, read, hidden, compressed, archive ecc. su cui non si può basare un controllo di licenza.
In effetti se usiamo il SoftIce la chiamata GetFileAttributes non viene fatta da mkt durante il boot. Evidentemente il programma userà una OpenFile oppure una CreateFile per leggere il contenuto dei file di registrazione,l'intuizione è confermata dal fatto che fra le funzioni importate c'è una CreateFileA che serve sia per leggere che scrivere un file.
Allora con ICe impostiamo un break point su CreateFileA e lanciamo il programma mkt, constantando con dispiacere che la funzione non viene usata!! Però quando facciamo Connection->New la funzione viene chiamata, ma non ha a che fare con il file di registrazione, infatti lo stack frame relativo alla chiamata, dumpato con OllyDBG, è:
�
0012F2D0 009055D0 |FileName = "C:\Documenti\MKT\default.MKT"
0012F2D4 80000000 |Access = GENERIC_READ
0012F2D8 00000000 |ShareMode = 0
0012F2DC 0012F3FC |pSecurity = 0012F3FC
0012F2E0 00000003 |Mode = OPEN_EXISTING
0012F2E4 00000080 |Attributes = NORMAL
0012F2E8 00000000 |hTemplateFile = NULL
Il file default.mkt è un misero file per la configurazione della connessione di default usata dal programma.
Ma come è possibile? Il programma in qualche modo deve pur aprirli quei 2 maledetti file! L'unica spiegazione possbile è che i programmatori della Foxit abbiano usata una funzione di libreria "strana" o poco usata, che necessariamente fa qualche operazione sui 2 file di registrazione. Il RegMonitor se ne accorge ma non sa dirci con precisione qual'è l'arcana funzione.
A questo punto per individuare la suddetta servono una o entrambe delle due doti seguenti:
1) fortuna (molta visto che la lista delle funzioni importate segnalateci da WDasm è lunghissima!)
2) esperienza (non tanta)
Oppure possiamo analizzare il disassemblato, nello specifico troviamo le occorrenze di klt.key e kltkey.txt fra le String References di WDasm ed esaminiamo il codice che le usa.
Per quanto riguarda kltkey.txt abbiamo:
Mentre invece per klt.key:
 
 
La funzione GetPrivateProfileStringA sembra essere proprio quella che stavamo cercando perchè
1) viene chiamata una volta per kltkey.txt e una volta per klt.key
2) un parametro riguarda il nome del file
3)un altro parametro è SN, sarà Serial Number?
Leggiamo l'API reference su questa funzione:
La funzione GetPrivateProfileString ritorna una stringa da una specifica sezione da un file di inizializzazione. La funzione è fornita per compatibilità con le applicazioni di Windows a 16 bit. Le applicazioni Windows a 32bir dovrebbero registrare l'informazione nel registro.
Il prototipo della funzione è:
DWORD GetPrivateProfileString(

LPCTSTR lpAppName, // punta al nome della sezione
LPCTSTR lpKeyName, // punta al nome chiave
LPCTSTR lpDefault, // punta alla stringa di default
LPTSTR lpReturnedString, // punta al buffer di destinazione
DWORD nSize, // dimensione del buffer di destinazione
LPCTSTR lpFileName // punta al nome del file di inizializzazione
);

L'ultimo parametro indica il nome del file di inizializzazione che nel nostro caso sarà kltkey.txt per la prima volta e klt.key per la seconda volta che viene chiamata la GetPrivateProfileString.Un file di inizializzazione è ad esempio quello di windows.ini e quindi ha una struttura del genere:
[sezione_1]
chiave1=valore1
chiave2=valore2
chiaven=valoren
[sezione_2]
.
.
.
[sezione_n]
chiave1=valore1
.
.
chiaven=valoren
Il nostro scopo è ora quello di ricostruire il file di inizializzazione, mediante due passi:
a) creazione di due file vuoti kltkey.txt e klt.key nella stessa cartella di mkt.exe

b)debuggin di mkt.exe (con OllyDB) impostando un breakpoint sulla prima chiamata di GetPrivateProfileString ,nel mio caso si riferisce all'indirizzo 0040ABCB.
Procedendo in avanti ci accorgiamo che viene fatta una chiamata di GetPrivateProfileString sul file di kltkey.txt e 6 chiamate di GetPrivateProfileString sul file klt.key.

Lo stack frame della prima chiamata ( relativo ai parametri) è:

1a)

0012F90C Section = "KoalaTerm"
0012F910 Key = "SN"
0012F914 Default = ""
0012F918 ReturnBuffer = 0012FC98
0012F91C BufSize = 100 (256.)
0012F920 IniFileName = "C:\Documenti\MKT\kltkey.txt"

Lo stack frame delle successive 6 chiamate ( relativo ai parametri ) è:

1b)

0012F90C Section = "KoalaTerm"
0012F910 Key = "SN"
0012F914 Default = ""
0012F918 ReturnBuffer = 0012FC98
0012F91C BufSize = 100 (256.)
0012F920 IniFileName = "C:\Documenti\MKT\klt.key"

2b)

XXXXXX Section = "KoalaTerm"
XXXXXX Key = "Users"
XXXXXX Default = ""
XXXXXXReturnBuffer = 0012FC98
XXXXXX BufSize = 100 (256.)
XXXXXX IniFileName = "C:\Documenti\MKT\klt.key"

3b)

XXXXXX Section = "KoalaTerm"
XXXXXX Key = "Licensee"
XXXXXX Default = ""
XXXXXX ReturnBuffer = 0012FC98
XXXXXX BufSize = 100 (256.)
XXXXXX IniFileName = "C:\Documenti\MKT\klt.key"

4b)

XXXXXXSection = "KoalaTerm"
XXXXXX Key = "ExpireDate"
XXXXXXDefault = ""
XXXXXX ReturnBuffer = 0012FC98
XXXXXX BufSize = 100 (256.)
XXXXXX IniFileName = "C:\Documenti\MKT\klt.key"

5b)

XXXXXXSection = "KoalaTerm"
XXXXXX Key = "Sign"
XXXXXX Default = ""
XXXXXX ReturnBuffer = 0012FC98
XXXXXX BufSize = 100 (256.)
XXXXXX IniFileName = "C:\Documenti\MKT\klt.key"

6b)

XXXXXX Section = "KoalaTerm"
XXXXXX Key = "LicenseDate"
XXXXXX Default = ""
XXXXXX ReturnBuffer = 0012FC98
XXXXXX BufSize = 100 (256.)
XXXXXX IniFileName = "C:\Documenti\MKT\klt.key"

La prima osservazione è che il programma anche se i due file di inizializzazione sono vuoti, va avanti a leggere tutti i valori delle chiavi che gli servono, infatti il parametro Default="" fa si che se il la chiave non è presente,la stringa letta è quella vuota "".
In questo modo ci siamo ricostruiti la struttura dei 2 file.
Il file kltkey.txt deve essere così composto:

[KoalaTerm]
SN=1234567891

La chiave SN (=Serial Number) la riempiamo con un valore casuale, la cui lunghezza non deve comunque superare i 100 caratteri, infatti il parametro BuffSize=100.
Il file klt.key deve essere così composto:

[KoalaTerm]
SN=1234567891 <- un numero seriale casuale
Users=100 <- il numero di utenti per cui vale la licenza
Licensee=full <- il tipo di licenza
ExpireDate=2010/10/10 <- la data di scadenza
Sign=Epokh <- la firma?
LicenseDate=2004/05/05 <- la data di aqcuisizione della licenza

La data la indichiamo in modo anglosassone (vedremo in seguito perchè), per le altri chiavi usiamo sempre valori casuali compatibili con la chiave.
Ora con questi file opportunamente creati riavviamo il debugger e cerchiamo di capire cosa fa il programma con queste stringhe.L'algoritmo è piuttosto artificioso quindi bypasseremo solo il controllo finale, altrimenti il tutorial verrebbe lungo almeno 10 pagine.

 
 

Chiamanta della GetPrivateProfileString (1a)

0040ABE4 CALL mkt.0045F389 <- 1 parametro: valore della chiave SN

0040ABFB CALL mkt.00407A50 <- 2 parametri:

0040AC05 TEST EAX,EAX
0040AC07 JE SHORT mkt.0040AC66

Il valore di SN viene letto prima dal file kltkey.txt, se soddisfa il controllo (TEST AX,AX) legge il valore di Users dal file klt.key, altrimenti legge il valore di SN di nuovo però dal file klt.key. Questo probabilmente è per mantenere le compatibilità con le licenze precedenti.

Chiamanta della GetPrivateProfileString (1b)

0040AC61 CALL mkt.0045F389 <- 1 parametro: valore della chiave SN

0040AC6C CALL mkt.00403DB0 <- nessun parametro

Chiamanta della GetPrivateProfileString (2b)

0040ACA8 CALL mkt.0045F389 <- 1 parametro: valore della chiave Users

0040ACB3 CALL mkt.00403DB0 <- nessun parametro

Chiamanta della GetPrivateProfileString (3b)

0040AC61 CALL mkt.0045F389 <- 1 parametro: valore della chiave Licensee

0040AC6C CALL mkt.00403DB0 <- nessun parametro

Chiamanta della GetPrivateProfileString (4b)

0040AC61 CALL mkt.0045F389 <- 1 parametro: valore della chiave ExpireDate

0040AC6C CALL mkt.00403DB0 <- nessun parametro

Chiamanta della GetPrivateProfileString (5b)

0040AC61 CALL mkt.0045F389 <- 1 parametro: valore della chiave Sign

0040AC6C CALL mkt.00403DB0 <- nessun parametro

Chiamanta della GetPrivateProfileString (6b)

0040AC61 CALL mkt.0045F389 <- 1 parametro: valore della chiave LicenseDate

0040AC6C CALL mkt.00403DB0 <- nessun parametro

In linea di massima si può dedurre che: la chiamata a mkt.0045F389 formatta la stringa in input in un formato specifico per effetuare in seguito vari controlli,infatti le operazioni usate sono principalmente concatenamenti, mentre la chiamata a mkt.00403DB0 alloca le variabili: cioè assegna i valori letti alle variabili locali del programma.

Una volta che il programma ha acquisito tutte le stringhe dai file di inizializzazione si effettua il controllo che inizia dall'indirizzo 0040ADF3 con JMP SHORT mkt.0040AE04 e termina a 0040B10B JE mkt.0040B2CC.

La parte finale del controllo da bypassare è:

0040B0FE MOV DWORD PTR SS:[EBP-320],EAX
0040B104 CMP DWORD PTR SS:[EBP-320],0
0040B10B JE mkt.0040B2CC

Invertiamo il salto JE mkt.0040B2CC -> JNE mkt.0040B2CC ed andiamo avanti: il programma a questo punto effettua dei controlli sulle date.

0040B10B JNZ mkt.0040B2CC <- salto invertito
0040B111 PUSH mkt.004A75F0 <- parametro A
0040B116 MOV EAX,DWORD PTR SS:[EBP-450]
0040B11C ADD EAX,0E4
0040B121 PUSH EAX <- parametro B
0040B122 CALL mkt.00407A50 <- chiamata per il controllo dei dati: 2 parametri
0040B127 AND EAX,0FF
0040B12C TEST EAX,EAX <- verifica controllo
0040B12E JE SHORT mkt.0040B145 <- questo salto va invertito!
0040B130 MOV ECX,DWORD PTR SS:[EBP-450]
0040B136 MOV DWORD PTR DS:[ECX+D0],1
0040B140 JMP mkt.0040B2C7 <- questo salto fa fallire il controllo

0040B145 LEA EDX,DWORD PTR SS:[EBP-378]
0040B14B PUSH EDX <- struttura SystemTime
0040B14C CALL DWORD PTR DS:[<&KERNEL32.GetSystemTime>] <- prende l'ora di sistema

La chiamata a mkt.00407A50 effettua l'ultimo controllo sulle stringhe quindi è necessario invertire il salto JE SHORT mkt.0040B145 -> JNE SHORT mkt.0040B145 in modo che il programma acquisisca l'ora di sistema.Il controllo sulle date viene effettuato dall'indirizzo 0040B14C all'indirizzo 0040B28E,in cui il programma verifica se la data ExpireDate presa dal file di inizializzazione sia inferiore alla data di sistema corrente e calcola i giorni che rimangono per la valutazione. La nostra filosofia sarà quella di arrivare fino in fondo al controllo senza uscire da questo set di indirizzi con una jump.

L'ultimo salto da invertire è:

0040B1A7 PUSH ECX <- parametro a
0040B1A8 LEA EDX,DWORD PTR SS:[EBP-368]
0040B1AE PUSH EDX <-parametro b
0040B1AF CALL mkt.0040D0F0 <- un altro controllo
0040B1B4 AND EAX,0FF
0040B1B9 TEST EAX,EAX
0040B1BB JE SHORT mkt.0040B1D2 <- un altro salto da invertire
0040B1BD MOV EAX,DWORD PTR SS:[EBP-450]
0040B1C3 MOV DWORD PTR DS:[EAX+D0],0
0040B1CD JMP mkt.0040B2B8

 

Invertiamo l'ultimo salto JE SHORT mkt.0040B1D2 -> JNE SHORT mkt.0040B1D2. Il formato della data è quello anglosassone perchè una delle funzioni di controllo prende come parametro la stringa "%04d/%02d/%02d" che rappresenta il formato della data aaa/mm/gg. Ecco perchè nel file di inizializzazione le date sono espresse in questo formato.

Quindi in sostanza nel 2 file di inizializzazione possiamo porre qualasi valore con i vincoli seguenti:

File kltkey.txt

[KoalaTerm]
SN=1234567891 <- una stringa alfanumerica qualunque

File klt.key

[KoalaTerm]
SN=1234567891 <- una stringa alfanumerica qualunque
Users=100 <- un intero positivo
Licensee=full <- una stringa qualunque
ExpireDate=5000/10/10 <- la data di scadenza: una qualsiasi data futura
Sign=Epokh <- la firma: una stringa qualunque
LicenseDate=2004/05/05 <- la data di aqcuisizione della licenza precedente a quella corrente

Poi con OllyDb copiate tutte le modfiche apportate all'eseguibile e lanciate di nuovo mkt, la licenza è quella temporanea con 12802 giorni che se non vi bastano, è sufficiente eliminare tutti e due i file in modo da avere una licenza infinita.

Beh se vi dovessa capitare una protezione particolare come questa sapete come muovervi!

���������������������������������������������������������������������������������������������������������������� ..::EPOKH::..

Note finali

Ringrazio mio padre per avermi "obbligato" a crackare questo simpatico programma.
Nell'allegato ho inserito anche i due keyfile kltkey.txt e klt.key.

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