NewBie01
From UIC
active85k NewBie01
Contents |
| Infos | |
|---|---|
| Author: | Active85k |
| Email: | active85k@hotmail.com |
| Website: | Home page |
| Date: | 14/11/2002 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | Commenti, se volete |
Introduzione
Ecco qua un tutorial di quelli che vi piacciono! Sarà il più preciso possibile nella spiegazione ;)
Tools
SoftICE v4.5
IDA Disassembler (beh... secondo me è migliore del W32Dasm... anzi... non solo secondo me, vero Andre? :)
Una buona API reference (Win32.hlp... o qualsiasi altra :)
Visual C++ (per scrivere il KeyGen)
Link e Riferimenti
Notizie sul programma
Uno dei tanti crackme che ci sono sulla UIC! Siccome è per NewBie, è molto semplice da reversare. Un po' di assembly e scriveremo un bel KeyGen! ;)
Essay
Evia! Si parte! Questo tutorial è per newbie, quindi, sarà moooooolto noioso e pieno di spiegazioni! Quindi, mettetevi sotto e leggete! ;) Vediamo come si reversa un crackme di active85k! Innanzitutto, dovete avere il SoftICE (d'ora in poi SICE) attivato. Apriamo il nostro programma e vediamo di che si tratta. Il classico! Un nome e un codice da inserire! Ci sono tre pulsanti. Sappiamo bene che, se premiamo 'Register', il programma ci manderà a quel paese senza farsi tanti scrupoli. Il pulsante 'Exit' non ho capito bene a che serve, quindi rimane il tasto 'Info' (nei crackme leggete sempre le info prima di iniziare, potrebbero essere molto importanti). Beh... tutto sommato, questo qua, non credo ci dia grandi informazioni... anzi... ci dice che non possiamo patchare il programma (sarebbe stato meglio non leggerlo :)! E vabbè! Iniziamo col reversing! Prima di tutto dobbiamo iniziare a capire il metodo che il programma utilizza per ritirare il nome. In Windows ci sono vari modi per ritirare il testo da un campo. I programmi devono usare uno di questi. Le api possibili sono:GetDlgItemText, GetWindowText e SendMessage (mandando un messaggio del tipo WM_GETTEXT). E' facilmente intuibile che il programma è stato creato con una finestra di dialogo, quindi, viene spontaneo provare ad intercettare la GetDlgItemText. Apriamo il SICE (Ctrl+D) e settiamo un breakpoint sull'api che abbiamo scelto (bpx GetDlgItemTextA la "A" finale singifica ANSI, dovrebbe essere tutto chiaro :) Una volta settato il breakpoint, dobbiamo uscire da SICE (ancora Ctrl+D) e provare il crackme. Inseriamo un nome a caso (io ci metto "active85k") e un seriale a caso e premiamo 'Register' per vedere se il SICE poppa. Niente da fare! Evidentemente non è stata utilizzata la GetDlgItemText. Dobbiamo provare con GetWindowText. Quindi, dopo aver eliminato il breakpoint di prima (bc * dentro SICE), dobbiamo rifare lo stesso procedimento di prima cambiando l'api (bpx GwtWindowTextA). Reinseriamo un nome a caso (ci metto sempre "active85k") e un codice a caso e premiamo nuovamente 'Register'. Eccolo qua! Il SICE poppa! Come potete capire, siamo all'interno della GetWindowText, ossia siamo dentro la procedura che ritira il nome dal campo! Ma a noi non importa di come faccia per prendere il nome, l'importante è che alla fine lo prenda! Quindi, per uscire dalla chiamata, premiamo F11 in SICE, e ci troviamo, così, nella procedura principale. A questo punto dobbiamo vedere che cosa ha ritirato di bello questa chiamata. Per fare questo, dovremmo analizzare il codice, ma prima ci serve un po' di Win32 API Reference. Non vi scomodate, penserò io a mostrarvi la sintassi della GetWindowTextA.
HWND hWnd, // handle della finestra o del controllo contenente il testo
LPTSTR lpString, // indirizzo del buffer che riceverà il testo
int nMaxCount // dimensione massima (in byte) del testo che verrà catturato
);
I parametri sono tre e sono abbastanza facili da capire. Il risultato di questa chiamata sarà la lunghezza effettiva del testo catturato (escluso il carattere 00 che interrompe la stringa). Adesso che sappiamo dove mettere le mani, andiamo a vedere che cosa succede nel codice assembly, commentando un'istruzione alla volta. In SICE, siamo arrivati ad avere questa situazione (scusate se non scrivo gli opcodes, ma mi è giunta voce che Quequero non vuole):
0177:0040109F PUSH 004030E2 lpString
0177:004010A4 PUSH DWORD PTR [00403125] hWnd
0177:004010AA CALL USER32!GetWindowTextA
Da quello che abbiamo visto, la chiamata, ritira il testo contenuto nella finestra "00403125" e lo mette all'interno del buffer che si trova in 004030E2. I caratteri ritirati, al massimo, saranno C8 (C8 è un numero esadecimale che corrisponde al decimale 200). Se tutto è andato come si deve, in 004030E2 dovrebbe esserci o il nome o il serial che abbiamo inserito. Per vedere di che si tratta, steppiamo col SICE di nuovo fino a che non superiamo la chiamata a GetWindowText. Una volta superata (cioè dopo che il testo è stato preso), digitiamo d 004030E2 per vedere che cosa abbiamo raccolto! Come avevamo previsto, il testo contiene il nome che abbiamo inserito. Siamo sicuri, quindi, che questa è la chiamata che ci interessa. Prendiamo nota dell'indirizzo in cui ci siamo fermati (l'indirizzo è quel numero che si trova tra 0177 e l'istruzione), nel nostro caso "0040109A", e apriamo il disassembler per disasmare il crackme. Quando il disassembly è finito, dobbiamo recarci nella posizione che abbiamo annotato col comando "g" (si aprirà poi una finestralla dove dovrete inserire l'indirizzo di cui avete preso nota). Finalmente siamo sul posto! Dando uno sguardo veloce, ci rendiamo conto che la generazione del codice è davvero banale! Analizziamo adesso il codice del disassembler (ho rinominato qualcosa per farvi capire meglio):
push 0C8h ; nMaxCount
push offset Nome ; lpString
push hWnd ; hWnd
call GetWindowTextA ;Ritira il codice e lo mette in "Nome"
cmp eax, 6 ;Il nome ritirato è più corto di 6?
jl short @@ERRORE ;Si: salta ad errore / No: continua
cmp eax, 3Eh ;il nome è più lungo di 3Eh?
jg short @@ERRORE ;Si: salta ad errore / No: continua
xor ecx, ecx ;Azzera ECX (ecx diventa contatore)
@@STEP01:
mov al, byte ptr Nome[ecx] ;Copia in AL l'ECXesimo carattere del nome
cmp al, 0 ;se AL è uguale a zero (cioè se il nome è finito)...
jz short @@STEP02 ;...allora passa allo step successivo. Altrimenti continua
xor al, cl ;Xora il carattere del nome con la sua posizione
add al, cl ;Aggiunge al carattere la sua posizione
xor al, byte ptr ds:a0123456789abcd[ecx] ;Xora AL con l'ECXesimo char di una stringa
mov byte ptr RegCode[ecx], al ;muove il char ottenuto all'interno del codice finale
inc ecx ;aumenta di 1 il contatore ECX (cioè passa al carattere successivo)
jmp short @@STEP01 ;ritorna al primo step per l'analisi successiva
@@STEP02:
mov byte ptr RegCode[ecx], 0 ;Mette fine alla stringa generata
push 0C8h ; nMaxCount
push offset unk_0_403000 ; lpString
push dword_0_403129 ; hWnd
call GetWindowTextA ;Ritira un altro testo (sicuramente il serial che abbiamo inserito)
push offset RegCode ; lpString2 pusha il regcode calcolato nello step1
push offset unk_0_403000 ; lpString1 pusha il codice che abbiamo inserito noi
call lstrcmpA ;e li confronta!
cmp eax, 0 ;Le due stringhe sono uguali?
jz loc_0_401068 ;Si: crackme registrato / No: salto ad errore
jmp @@ERRORE
Adesso che abbiamo commentato il codice, vediamo di esporlo più a parole nostre ;) Prima abbiamo ritirato il nostro nome. ECX è il contatore (cioè segna la posizione del carattere che stiamo esaminando). Prima di tutto, il programma, muove il carattere in esame in AL. Questo viene xorato con la sua posizione all'interno del nome (quindi xor AL, CL). Dopo ciò, al valore ottenuto, viene aggiunto il numero che indica la sua posizione. Adesso c'è una parte nuova: il valore ottenuto viene xorato con l'ECXesimo carattere di un indirizzo che non conosciamo! Bene: se premiamo invio su quella stringa, IDA ci catapulta sul suo contenuto! Come possiamo vedere, questa stringa, contiene prima tutti i numeri, poi le lettere minuscole e poi quelle maiuscole. Quindi, dobbiamo copiare questa stringa che verrà poi inserita nel nostro programma. Adesso siamo pronti per scrivere il nostro KeyGen (vi riporto solo le righe necessarie per la generazione del codice perché mi sembra eccessivo postare tutto il sorgente del programma). Per farlo utilizzeremo il Visual C++ per Windows.
char StrName[61];
char StrSerial[61];
const char Values[61] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX";
L = GetDlgItemText(hWnd, CampoNomeID, (LPSTR) StrName, 61);
if((L > 5) & (L < 0x3E))
{
for(C=0; C < L; C++)
StrSerial[C] = (((StrName[C] ^ C) + C) ^ Values[C]);
StrSerial[L] = 0;
SetDlgItemText(hWnd, CampoSerialID, (LPSTR) StrSerial);
}
return 0;
"CampoNomeID" e "CampoSerialID" sono i due numeri che identificano due componenti EDIT che dovete inserire nel vostro programma. StrSerial ed StrName sono due stringhe di 61 caratteri al massimo. Non possono averne di più perché i valori con cui vengono xorati sono 61. La SetDlgItemText scrive il serial finale in un altro componente EDIT. Adesso basta copiare il serial ottenuto nel crackme e premere 'Register'. Il crackme è stato registrato! ;)
Note Finali
Spero di essermi spiegato bene. Come crackme è molto facile da reversare. Adesso tocca a voi! Mettetevi al lavoro e codate il più possibile! ;)
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.