Lindo 6.1 cracking | ||
Data |
by Spider |
|
19 Novembre 2002 |
Published by Quequero | |
Lei:
"Da quanto tempo non fai sesso?" |
Qualche mio eventuale
commento sul tutorial :))) |
...ah! ma tu dici con una donna??" Ezio Greggio in "Killer per caso" |
.... |
|
.... |
Difficoltà |
( )NewBies (X)Intermedio ( )Avanzato ( )Master |
Un esempio di target in cui la difficoltà non è insita nella protezione ma nella immane quantità di codice su cui essa è imperniata :)
Introduzione |
Tools usati |
Si presume nel lettore una conoscenza base dei comandi di IDA; in caso contrario si rimanda al tutorial di Quequero.
URL o FTP del programma |
Notizie sul programma |
Demo | Trial | Super | Hyper | Industrial | Extended | Constraints: 150 | ? | 1000 | 4000 | 16000 | unlimited | Variables: 300 | ? | 2000 | 8000 | 32000 | unlimited | Int variables: 50 | ? | 200 | 800 | 3200 | unlimited | Nonzeros: 2000000 | ? | N/A | N/A | N/A | N/A |
Perché riporto tutti questi dettagli? Semplice: conoscere questi dati ci permetterà di crackare il programma saltando tutto il codice superfluo e giungendo quindi in fretta al codice che ci interessa modificare.
Essay |
Ok, cominciamo. Installiamo il programma, eseguiamo (nel frattempo iniziamo a disassemblare da IDA), ed ecco la finestrella che ci avverte che se non inseriamo una password corretta si avvierà il programma in versione demo. Mettiamo una password a caso, settiamo gli usuali breakpoint su GetWindowTextA e GetDlgItemTextA, e clicchiamo su OK. SoftICE poppa diligentemente per via del bpx sulla seconda API; premiamo F11 per tornare al codice del programma (il codice è preso da IDA):
BEGTEXT:0041B993 push 197h ; nMaxCount BEGTEXT:0041B998 mov eax, offset byte_4AD6A4 BEGTEXT:0041B99D push eax ; lpString BEGTEXT:0041B99E push 1AAh ; nIDDlgItem BEGTEXT:0041B9A3 push [ebp+hDlg] ; hDlg BEGTEXT:0041B9A6 call cs:GetDlgItemTextA BEGTEXT:0041B9AD mov [ebp+var_8], eax ;<---noi siamo qui BEGTEXT:0041B9B0 mov eax, [ebp+var_8] BEGTEXT:0041B9B3 mov ds:byte_4AD6A4[eax], 0 BEGTEXT:0041B9BA push 1 ; nResult BEGTEXT:0041B9BC push [ebp+hDlg] ; hDlg BEGTEXT:0041B9BF call cs:EndDialog
Osservando il codice, vediamo che il serial da noi immesso viene salvato all'offset 004AD6A4 (che in IDA rinominiamo Serial); subito dopo la dialog viene chiusa, quindi è chiaro che il controllo del serial avviene da qualche altra parte. Osservando le xreferences a quella locazione, vediamo che ci sono ben 9 punti di codice che fanno riferimento ad essa; impiegheremmo 5 minuti a controllarle tutte, ma siccome noi siamo pigroni preferiamo impiegare 4 minuti usando softice (con il considerevole risparmio di 1 minuto!)... Torniamo dunque in softice, rimettiamo il breakpoint su GetDlgItemTextA, e quando softice poppa sullo schermo mettiamo un bel "bpm 4AD6A4 rw", ovvero chiediamo al softice di intercettare qualunque accesso in lettura/scrittura alla locazione in cui sappiamo che è contenuto il nostro serial. Premiamo F5 e softice riappare subito dopo. Un'occhiata veloce al codice e ci accorgiamo di trovarci su una piccola procedura che fa qualche manipolazione di stringhe, per cui premiamo F11 per giungere a questo codice:
BEGTEXT:0042C24A mov eax, offset Serial BEGTEXT:0042C24F call strlen BEGTEXT:0042C254 test eax, eax BEGTEXT:0042C256 ja short loc_42C273 BEGTEXT:0042C258 mov eax, [ebp+var_18] BEGTEXT:0042C25B mov dword ptr [eax], 0 BEGTEXT:0042C261 mov eax, [ebp+var_14] BEGTEXT:0042C264 mov dword ptr [eax], 0 BEGTEXT:0042C26A mov [ebp+var_10], 0FFFFFFFEh BEGTEXT:0042C271 jmp short loc_42C2B2 BEGTEXT:0042C273 ; --------------------------------------------------------------------------- BEGTEXT:0042C273 BEGTEXT:0042C273 loc_42C273: ; CODE XREF: sub_42C1E4+72j BEGTEXT:0042C273 mov eax, offset Serial BEGTEXT:0042C278 call strlen BEGTEXT:0042C27D mov [ebp+var_1C], eax BEGTEXT:0042C280 mov eax, [ebp+var_1C] BEGTEXT:0042C283 mov edx, [ebp+var_14] BEGTEXT:0042C286 cmp eax, [edx] BEGTEXT:0042C288 jle short loc_42C296 BEGTEXT:0042C28A mov eax, [ebp+var_14] BEGTEXT:0042C28D mov eax, [eax] BEGTEXT:0042C28F mov ds:Serial[eax], 0 BEGTEXT:0042C296 BEGTEXT:0042C296 loc_42C296: ; CODE XREF: sub_42C1E4+A4j BEGTEXT:0042C296 mov edx, offset Serial BEGTEXT:0042C29B mov eax, [ebp+var_18] BEGTEXT:0042C29E mov eax, [eax] BEGTEXT:0042C2A0 call strcpy_ BEGTEXT:0042C2A5 mov eax, offset Serial BEGTEXT:0042C2AA call strlen BEGTEXT:0042C2AF mov [ebp+var_10], eax
Qui non troviamo nulla di interessante... A parte qualche chiamata a strlen e strcpy non troviamo niente di strano. Risaliamo perciò il codice e andiamo alla procedura chiamante:
BEGTEXT:0042BFDE cmp [ebp+var_10], 0 BEGTEXT:0042BFE2 jnz loc_42C05C BEGTEXT:0042BFE8 lea edx, [ebp+var_14] BEGTEXT:0042BFEB lea eax, [ebp+var_20] BEGTEXT:0042BFEE call sub_42C1E4 ;noi veniamo da qui BEGTEXT:0042BFF3 mov [ebp+var_C], eax BEGTEXT:0042BFF6 mov [ebp+var_18], 1 BEGTEXT:0042BFFD cmp [ebp+var_C], 0FFFFFFFEh BEGTEXT:0042C001 jnz short loc_42C00F ; salta se il serial non è nullo BEGTEXT:0042C003 mov [ebp+var_28], 0FFFFFFFEh ; chiusura dialog e avvio demo BEGTEXT:0042C00A jmp loc_42C108 BEGTEXT:0042C00F ; --------------------------------------------------------------------------- BEGTEXT:0042C00F BEGTEXT:0042C00F loc_42C00F: ; CODE XREF: sub_42BF51+B0j BEGTEXT:0042C00F cmp [ebp+var_C], 0FFFFFFFDh BEGTEXT:0042C013 jnz short loc_42C021 BEGTEXT:0042C015 mov [ebp+var_28], 0FFFFFFFDh BEGTEXT:0042C01C jmp loc_42C108 BEGTEXT:0042C021 ; --------------------------------------------------------------------------- BEGTEXT:0042C021 BEGTEXT:0042C021 loc_42C021: ; CODE XREF: sub_42BF51+C2j BEGTEXT:0042C021 mov eax, [ebp+var_C] BEGTEXT:0042C024 mov byte ptr [eax+ebp-1CCh], 0 BEGTEXT:0042C02C lea eax, [ebp+var_1CC] BEGTEXT:0042C032 push eax BEGTEXT:0042C033 push [ebp+var_30] BEGTEXT:0042C036 lea eax, [ebp+var_8] BEGTEXT:0042C039 push eax BEGTEXT:0042C03A push [ebp+var_2C] BEGTEXT:0042C03D lea eax, [ebp+var_4] BEGTEXT:0042C040 push eax BEGTEXT:0042C041 call ValidatePassword ;cooosa??? BEGTEXT:0042C046 mov [ebp+var_1C], eax BEGTEXT:0042C049 cmp [ebp+var_1C], 0 BEGTEXT:0042C04D jle short loc_42C05C BEGTEXT:0042C04F mov eax, [ebp+var_1C] BEGTEXT:0042C052 call sub_42C183 BEGTEXT:0042C057 jmp loc_42BFD7 BEGTEXT:0042C05C ; --------------------------------------------------------------------------- BEGTEXT:0042C05C BEGTEXT:0042C05C loc_42C05C: ; CODE XREF: sub_42BF51+91j BEGTEXT:0042C05C ; sub_42BF51+FCj BEGTEXT:0042C05C push [ebp+arg_24] BEGTEXT:0042C05F push [ebp+arg_20] BEGTEXT:0042C062 mov eax, [ebp+arg_34] BEGTEXT:0042C065 push dword ptr [eax] BEGTEXT:0042C067 push [ebp+arg_1C] BEGTEXT:0042C06A push [ebp+arg_18] BEGTEXT:0042C06D push [ebp+arg_14] BEGTEXT:0042C070 push [ebp+var_30] BEGTEXT:0042C073 lea eax, [ebp+var_8] BEGTEXT:0042C076 push eax BEGTEXT:0042C077 push [ebp+var_2C] BEGTEXT:0042C07A lea eax, [ebp+var_4] BEGTEXT:0042C07D push eax BEGTEXT:0042C07E call VerifyLicense ;coooooosaaaa??? BEGTEXT:0042C083 mov [ebp+var_1C], eax BEGTEXT:0042C086 cmp [ebp+var_1C], 0 BEGTEXT:0042C08A jnz short loc_42C094 ; deve saltare BEGTEXT:0042C08C mov eax, [ebp+arg_10] BEGTEXT:0042C08F cmp dword ptr [eax], 1 BEGTEXT:0042C092 jz short loc_42C096 BEGTEXT:0042C094 BEGTEXT:0042C094 loc_42C094: ; CODE XREF: sub_42BF51+139j BEGTEXT:0042C094 jmp short loc_42C09F
Davvero gentili i programmatori... Hanno lasciato in chiaro i nomi di due chiamate di libreria che si trovano nella dll Lindolm.dll; oltre a queste due simpatiche funzioni della dll, IDA ce ne comunica altre:
.idata:00FA088C ; .idata:00FA088C ; Imports from LINDOLM.dll .idata:00FA088C ; .idata:00FA088C extrn __imp_CheckSentry:dword ; DATA XREF: CheckSentryr .idata:00FA0890 extrn __imp_CreateDemoLicense:dword .idata:00FA0890 ; DATA XREF: CreateDemoLicenser .idata:00FA0894 extrn __imp_StartSentry:dword ; DATA XREF: StartSentryr .idata:00FA0898 extrn __imp_ValidatePassword:dword .idata:00FA0898 ; DATA XREF: ValidatePasswordr .idata:00FA089C extrn __imp_VerifyLicense:dword ; DATA XREF: VerifyLicenser
Disassemblando la lindolm.dll si trovano decine di nomi interessanti, ma provate ad analizzare una qualunque di queste procedure... C'è da perdersi in mezzo a tutte le call e subroutines varie. Il reversing si prospetta lungo e noioso, per cui optiamo per un molto più rilassante e rapido cracking :-)
Dobbiamo però trovare il modo di evitare il fastidioso jungle e trovare un solido punto di attacco del programma. Ricordate lo schema che riguardava le limitazioni per i vari tipi di licenza del programma? E' chiaro che il programma deve tenere in memoria una variabile per ricordarsi in quale licenza il programma debba girare, e regolarsi di conseguenza per gestire le limitazioni. Inoltre, dovrà anche ricordarsi da qualche parte le limitazioni per ogni tipo di licenza:
Demo | Trial | Super | Hyper | Industrial | Extended | Constraints: 150 | ? | 1000 | 4000 | 16000 | unlimited | Variables: 300 | ? | 2000 | 8000 | 32000 | unlimited | Int variables: 50 | ? | 200 | 800 | 3200 | unlimited | Nonzeros: 2000000 | ? | N/A | N/A | N/A | N/A |
Trovare questa tabella tra i dati del programma potrebbe essere un ottimo punto di partenza. Ancora una volta il softice ci semplifica il lavoro. Avviamo il programma, digitiamo "MAP32 lindow32", ottenendo il seguente output:
Owner Obj Name
Obj# Address Size
Type
LINDOW32 BEGTEXT 0001 017F:00410000 00000000
CODE RO
LINDOW32 DGROUP 0002 0187:004A0000
00000000 IDATA RW
LINDOW32 .bss 0003 0187:00580000
00000000 UDATA RW
LINDOW32 .idata 0004 0187:00FA0000
00000000 IDATA RW
LINDOW32 .edata 0005 0187:00FB0000
00000000 IDATA R0
LINDOW32 .reloc 0006 0187:00FC0000
00000000 IDATA R0
LINDOW32 .rsrc 0007 0187:00FD0000
00000000 IDATA R0
La tabella che stiamo cercando è presumibilmente contenuta nella seconda sezione, che è appunto la sezione dei dati. Stranamente i campi Size sono azzerati, cmq è chiaro che la sezione DGROUP sia ampia 580000-4A0000=E0000 bytes. Dobbiamo adesso cercare in memoria i dati interessati basandoci su ciò che ci è noto di essi, ad esempio il valore 32000 (decimale) = 00007D00 (hex) che è sicuramente contenuto nella tabella. Per cui da softice digitiamo:
s 4A0000 L E0000 00,7D,00,00 <---attenti ai bytes invertiti per la notazione Intel!
A cui softice replica con:
Pattern found at 0187:0057E104 (000DE104)
Bingo! Andando a vedere con IDA a quella locazione e alle locazioni circostanti scopriamo di incontrare proprio i valori che avevamo nella tabella (ho già rinominato le locazioni, raccolto ad array, e convertito tutto in decimale):
DGROUP:0057E0DC Constraints dd 150, 250, 1000, 4000, 16000, 64000 DGROUP:0057E0DC ; DATA XREF: sub_487CE0+19Fr DGROUP:0057E0F4 Variables dd 300, 500, 2000, 8000, 32000, 200000 DGROUP:0057E0F4 ; DATA XREF: sub_487CE0+1ACr DGROUP:0057E10C Int_variables dd 50, 50, 200, 800, 3200, 20000 DGROUP:0057E10C ; DATA XREF: sub_487CE0+1BFr
Abbiamo dunque tre array di sei elementi ciascuno, e guarda caso proprio 6 sono i tipi di licenza consentiti... Adesso che sappiamo dov'è la tabella possiamo analizzare le xref. Andiamo alla prima:
BEGTEXT:00487E7A loc_487E7A: ; CODE XREF: sub_487CE0+AFj BEGTEXT:00487E7A ; sub_487CE0+B7j ... BEGTEXT:00487E7A mov eax, ds:dword_57E0C8 BEGTEXT:00487E7F mov edx, ds:Constraints[eax*4] ;l'xref proviene da qui BEGTEXT:00487E86 mov ds:dword_5801F4, edx BEGTEXT:00487E8C mov edx, ds:Variables[eax*4] BEGTEXT:00487E93 mov ds:dword_58025C, edx BEGTEXT:00487E99 mov ds:dword_E793F0, edx BEGTEXT:00487E9F mov eax, ds:Int_variables[eax*4] BEGTEXT:00487EA6 mov ds:dword_580264, eax
Il programma prende la dword all'offset 57E0C8 e la utilizza come indici per i tre array visti prima... E' chiaro che se poniamo questa variabile a 5 il programma si autoconvincerà di essere registrato con la massima licenza possibile :-)
Rinominiamo la dword_57E0C8 con il nome di current_mode, e osserviamo le sue xreferences:
Up
o BEGTEXT:00487D5A
push offset current_mode
Up o BEGTEXT:00487DEB
push offset current_mode
Up w BEGTEXT:00487E14
mov ds:current_mode,eax
Up r BEGTEXT:00487E7A
mov eax,ds:current_mode
L'ultima xref la conosciamo già; osservando il codice della penultima si nota anche ad una rapida occhiata che si occupa solo di azzerare un po' di variabili. Ci resta solo da analizzare il codice delle prime 2 xref:
BEGTEXT:00487D34 loc_487D34: ; CODE XREF: sub_487CE0+46j BEGTEXT:00487D34 push offset off_4B5420 BEGTEXT:00487D39 push offset dword_57E0D8 BEGTEXT:00487D3E push offset dword_57E0D4 BEGTEXT:00487D43 push offset dword_57E0D0 BEGTEXT:00487D48 lea eax, [ebp+var_14] BEGTEXT:00487D4B push eax BEGTEXT:00487D4C lea eax, [ebp+var_10] BEGTEXT:00487D4F push eax BEGTEXT:00487D50 push offset dword_57E088 BEGTEXT:00487D55 push offset dword_57E0CC BEGTEXT:00487D5A push offset current_mode ;prima xref BEGTEXT:00487D5F mov edx, [ebp+var_8] BEGTEXT:00487D62 push edx BEGTEXT:00487D63 push esi BEGTEXT:00487D64 mov ecx, offset dword_57E084 BEGTEXT:00487D69 mov ebx, offset off_4B5418 BEGTEXT:00487D6E mov edx, offset unk_57E080 BEGTEXT:00487D73 mov eax, offset off_4B5450 BEGTEXT:00487D78 call sub_42BF51 BEGTEXT:00487D7D mov ebx, [esi] BEGTEXT:00487D7F cmp ebx, 1 BEGTEXT:00487D82 jnz loc_487E64 BEGTEXT:00487D88 cmp eax, 0FFFFFFFDh BEGTEXT:00487D8B jnz short loc_487D94 BEGTEXT:00487D8D mov [edi], ebx BEGTEXT:00487D8F jmp loc_487E7A ;questo ci rimanda alla quarta xreference BEGTEXT:00487D94 ; --------------------------------------------------------------------------- BEGTEXT:00487D94 BEGTEXT:00487D94 loc_487D94: ; CODE XREF: sub_487CE0+ABj BEGTEXT:00487D94 cmp eax, 0FFFFFFFEh BEGTEXT:00487D97 jnz loc_487E7A BEGTEXT:00487D9D mov ecx, offset dword_57E084 BEGTEXT:00487DA2 mov ebx, offset off_4B5418 BEGTEXT:00487DA7 mov edx, offset unk_57E080 BEGTEXT:00487DAC mov eax, offset off_4B5450 BEGTEXT:00487DB1 call sub_42C113 BEGTEXT:00487DB6 mov edx, offset off_4B5460 BEGTEXT:00487DBB mov eax, offset off_4B5420 BEGTEXT:00487DC0 call loc_48AE1D BEGTEXT:00487DC5 push offset off_4B5420 BEGTEXT:00487DCA push offset dword_57E0D8 BEGTEXT:00487DCF push offset dword_57E0D4 BEGTEXT:00487DD4 push offset dword_57E0D0 BEGTEXT:00487DD9 lea eax, [ebp+var_14] BEGTEXT:00487DDC push eax BEGTEXT:00487DDD lea eax, [ebp+var_10] BEGTEXT:00487DE0 push eax BEGTEXT:00487DE1 push offset dword_57E088 BEGTEXT:00487DE6 push offset dword_57E0CC BEGTEXT:00487DEB push offset current_mode ;seconda xref BEGTEXT:00487DF0 mov edi, [ebp+var_8] BEGTEXT:00487DF3 push edi BEGTEXT:00487DF4 push esi BEGTEXT:00487DF5 mov ecx, offset dword_57E084 BEGTEXT:00487DFA mov ebx, offset off_4B5418 BEGTEXT:00487DFF mov edx, offset unk_57E080 BEGTEXT:00487E04 mov eax, offset off_4B5450 BEGTEXT:00487E09 call sub_42BF51 BEGTEXT:00487E0E test eax, eax BEGTEXT:00487E10 jz short loc_487E73 ; questo ci rimanda alla quarta xref, BEGTEXT:00487E10 ; quindi al momento del salto la variabile BEGTEXT:00487E10 ; current_mode DEVE essere stata settata. BEGTEXT:00487E12 xor eax, eax BEGTEXT:00487E14 mov ds:current_mode, eax [etc etc...]
In particolare poniamo l'attenzione alla prima parte di codice: contiene una serie di push (tra cui il push offset current_mode che costituiva la prima xreference) e una call; entrando dentro di essa scopriamo che è la stessa precedura che avevamo visto all'inizio e in cui sono contenute le chiamate a ValidatePassword e VerifyLicense!! Eravamo praticamente a due passi dalla soluzione e non ce n'eravamo accorti!... Gli scherzi del jungle ;)
Adesso mi sembra fin troppo chiaro quello che dobbiamo fare: facciamo saltare la call sub_42BF51 all'indirizzo 00487D78, aggiungiamo due righe di codice per settare a 5 la variabile current_mode, e noppare i due jnz dopo la call per essere certi di andare dove vogliamo noi :)
Questo:
BEGTEXT:00487D78 call sub_42BF51 BEGTEXT:00487D7D mov ebx, [esi] BEGTEXT:00487D7F cmp ebx, 1 BEGTEXT:00487D82 jnz loc_487E64 BEGTEXT:00487D88 cmp eax, 0FFFFFFFDh BEGTEXT:00487D8B jnz short loc_487D94 BEGTEXT:00487D8D mov [edi], ebx BEGTEXT:00487D8F jmp loc_487E7A
Deve diventare così:
add esp,2C ;2C = 11d * 4 in quanto dobbiamo fixare lo stack push 5 ;\ pop dword ptr[57E0C8] ;|impostiamo la licenza al massimo ;) jmp 487E7A ;saltiamo il resto del codice "pericoloso" ;))
Effettuiamo le modifiche, eseguiamo e andiamo nell'aboutbox: nessuna traccia di time limit, limitazioni (Contraints, Variables, Int_Variables) sparite.
Spider
Note finali |
Saluti a Delfina con cui ho condiviso il cracking di questo programma.
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 immane che ogni singolo programmatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.
Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.