Pegasus Mail: MailBox Encryption |
|
|
27/06/2000 |
by "Ritz" |
|
|
Published by Quequero |
|
Bravo ritz, questo � un ottimo esempio di reversing, ovvero ci� che tutti gli studenti UIC dovrebbero essere in grado di fare. |
||
UIC's form |
|
UIC's form |
Difficolt� |
( )NewBies ( )Intermedio (x)Avanzato ( )Master |
In questo tute cercheremo di personalizzarci un pochetto il client mail per win Pegasus Mail (v3.12c) per aumentarne la sicurezza e proteggere la nostra mailbox da occhi un po' troppo indiscreti ;).
NOTA INTRODUTTIVA: se state leggendo questo tute solo perche' volete crackare il prg in questione vi conviene lasciar perdere da subito, visto che la protezione non centra nulla con i byte scritti sotto e che Pegasus mail e' pure freeware.
Introduzione |
Salve a tutti.
Come molti avranno avuto occasione di notare, i vari client mail che girano sotto Windoz
offrono vari livelli di "protezione" (chiamiamola cosi') delle mail in entrata,
a seconda naturalmente del prog che si sta prendendo in considerazione, dove col termine
protezione intendo la capacita' del programma stesso di tenere a bada eventuali curiosi
che volessero vedere cosa ci arriva ogni giorno.
Un esempio di programma che offre una buona protezione e' secondo me Calypso, in quanto
mantiene tutte le mail *cifrate* in un'unico file di mailbox, e chiede una password
all'avvio, in mancanza della quale non parte.
Dall'altro lato, esistono vari altri programmi che invece in quanto a protezione non si
sprecano troppo, e uno di questi e' Pegasus Mail, il quale salva *ogni* mail in entrata
come file a se stante in una data cartella (\mail) lasciando tutto completamente in chiaro
(header compreso). Penso sia superfluo dire che tale prog all'avvio non chiede una
password.
E' vero che tra le sue opzioni avanzate ne esiste una chiamata "Encryption", ma
non penso serva a molto visto che le mail in ogni caso non vengono crittate.
Dopotutto si tratta di un prg freeware (non si puo' aver tutto dalla vita;) ), e dato
allora che gli autori non si sono preoccupati troppo di offrire una certa sicurezza della
mailbox, mi pare una bella idea mettere a posto le cose da soli.
Tool usati e documenti utili |
. SoftICE (a me e' servito non poco per
debuggare la dll)
. TASM
. Hex Workshop
. HIEW
. OpGen by -NeuRaL_NoiSE
. WIN32 API Reference
. "PE-Crypters : uno sguardo da vicino al c.d.
"formato" PE", by Kill3xx
. "The PE file format", by B. Luevelsmeyer
Essay |
PRELIMINARI
Prima di tutto sara' meglio studiare il programma. Configurato un nuovo
account, scarichiamo un po' di posta e usciamo da Pegasus Mail (d'ora in poi PMail).
Andiamo nella sua cartella di installazione di default, entriamo in \Mail e proviamo ad
aprire con un editor di testo i vari file cnm che abbiamo davanti. Ebbene si', ognuno di
essi e' una delle e-mail che abbiamo ricevuto, che come si nota facilmente sono state
salvate totalmente in chiaro (un file per ogni e-mail).
A questo punto abbiamo gia' le idee abbastanza chiare sulla situazione.
Come operare ora? Potremmo agire in 2 modi:
1- Chiedere all'avvio una pass senza la quale il prog non parte.
2- Chiedere all'avvio una chiave di decifratura della mailbox che in precedenza avremo
diligentemente cifrato.
Il problema della soluzione 1 e' che la mailbox stessa rimarrebbe in chiaro una volta
usciti dal prog, a meno di non scrivere un algoritmo di cifratura/decifratura che non
chieda una chiave all'avvio del prg (il che non mi piace troppo).
Se scegliessimo la 2, pero', avremmo un altro problema. Supponendo infatti che un
curiosone immetta la chiave sbagliata, il prg decifrera' la mailbox in modo errato e
quindi le mail non saranno leggibili, ma il prog si avviera' in ogni caso e sara'
possibile scaricare in chiaro la posta dal proprio pop (se la pw di connessione e' stata
salvata dall'incauto proprietario).
Entrambi i casi presentano dei problemi, quindi... uniamo le 2 possibilita'.
Mi spiego meglio.
All'avvio, il programma dovra' chiedere sia una pass per poter essere avviato che una
chiave per poter decrittare le mail. L'intruso per poter leggere la posta che abbiamo
salvato dovra' conoscere entrambi gli elementi. Se infatti scrivera' la pw corretta ma la
chiave sbagliata, la mailbox verra' decrittata in modo errato e quindi sara' illeggilbile,
se invece la chiave e' corretta ma la pw sbagliata, PMail nemmeno si avviera'.
Naturalmente, all'uscita del prg sara' necessario rimanipolare il tutto con la stessa
chiave immessa all'avvio, sia che essa sia giusta, sia sbagliata, in quanto altrimenti si
rischia di rendere la stessa mailbox leggibile da tutti (aprendo i relativi file) in caso
di chiave esatta o, peggio, illeggibile persino da parte del proprietario in caso di
chiave sbagliata (in quanto le mail risulterebbero cosi' manipolate con ben 2 chiavi). Se
non si facesse cosi', un errore nella battitura della stessa o un "intruso" che
conosce la pw potrebbe mandarci tutta la nostra amata posta ad cazzum, il che non e' bene.
Riassumendo, dobbiamo:
1- Chiedere una pw.
2- Chiedere una chiave.
3- Se la pw e' corretta, avviare il prog decrittanto la mailbox tramite la chiave data,
altrimenti uscire.
4- Aspettare la chiusura del prog.
5- Rimanipolare la mailbox con la chiave data all'avvio.
6- Uscire dal prg.
Possiamo fare tutto questo in 2 modi diversi.
1- Tramite un eseguibile.
2- Tramite una dll.
Personalmente, ho provato entrambi i metodi, quello secondo me sicuramente migliore (o,
meglio, + "elegante") e' il 2, che trattero' di seguito, dato anche che per
applicare il metodo 1 basta conoscere tutti i concetti relativi al 2, ma non viceversa.
EXE REVERSING & DLL CODING
Come appenda deciso, per raggiungere lo scopo dovremo creare una dll nostra che abbia
una funzione di encrypt e decrypt (se l'algo e' costituito da semplicissime operazioni
tipo xor le 2 funz possono essere unite). La funzione di decrypt deve essere chiamata
appena PMail viene avviato, quella di decrypt subito prima che il suo processo sia
terminato.
Di conseguenza bisognera' modificare la IT dell'exe stesso per aggiungere la nostra dll
tra i moduli importati e le nostre 2 funz.
E qui sia il tute di Kill3xx che HIEW risultano praticamente indispensabili.
Apriamo winpm-32.exe e osserviamo la IT, o, meglio, la sua parte iniziale (modalita' Hex,
F8, F7, Import). Ecco cosa abbiamo davanti:
.004BA000: 04 A1 0B 00-EC FF 61
05-2C 8D 58 05-7C AD 0B 00 � ��a ,X |�
.004BA010: E8 A1 0B 00-CC A2 0B 00-2C 8D 58 05-2C 8D 58 05 � ̢ ,X ,X
.004BA020: 86 AD 0B 00-DC A2 0B 00-EC A2 0B 00-2C 8D 58 05 � ܢ � ,X
.004BA030: C4 8D 58 05-90 AD 0B 00-04 A3 0B 00-1C A3 0B 00 �X � � �
.004BA040: 2C 8D 58 05-2C 8D 58 05-9D AD 0B 00-E8 A4 0B 00 ,X ,X � �
.004BA050: B4 A6 0B 00-2C 8D 58 05-CC A7 58 05-AA AD 0B 00 �� ,X ̧X ��
.004BA060: BC A6 0B 00-C4 A6 0B 00-2C 8D 58 05-2C 8D 58 05 1/4� Ħ ,X ,X
.004BA070: B2 AD 0B 00-CC A6 0B 00-D4 A6 0B 00-2C 8D 58 05 �� ̦ Ԧ ,X
.004BA080: 68 A6 58 05-BF AD 0B 00-DC A6 0B 00-E4 A6 0B 00 h�X �� ܦ �
.004BA090: 40 98 58 05-60 9A 58 05-CC AD 0B 00-F4 A6 0B 00 @X `X Ì ï¿½ï¿½
.004BA0A0: 04 A7 0B 00-90 A3 58 05-2C 8D 58 05-D9 AD 0B 00 � �X ,X Ù
.004BA0B0: DC A7 0B 00-B4 A8 0B 00-2C 8D 58 05-2C 8D 58 05 ܧ �� ,X ,X
.004BA0C0: E3 AD 0B 00-D0 A8 0B 00-EC A8 0B 00-54 7B 65 05 � Ш � T{e
.004BA0D0: 14 00 62 05-EF AD 0B 00-2C AB 0B 00-6C AD 0B 00 b � ," l�
.004BA0E0: 2C 8D 58 05-2C 8D 58 05-FA AD 0B 00-74 AD 0B 00 ,X ,X �� t�
.004BA0F0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004BA100: 00 00 00 00-04 AE 0B 00-1E AE 0B 00-3A AE 0B 00 (r) (r) :(r)
Questa schermata e' un array di strutture del tipo IMAGE_IMPORT_DESCRIPTOR. Ognuna di tali
strutture occupa 5 dw, e ce n'e' una per ogni modulo importato. Tale tipo di struttura e'
costituito da:
1- OriginalFirstThunk: RVA ad un array di strutture (dw) di tipo IMAGE_THUNK_DATA che
termina con un elemento NULL, ognuna delle quali punta a una funzione importata.
2- TimeDateStamp: non ci interessa, serve per le funzioni bound
3- ForwarderChain: non ci interessa nemmeno questa, serve per le funzioni forwarded.
4- Name: punta al nome del modulo (la cui stringa e' NULL terminated).
5- FirstThunk: array *indispensabile* simile a OriginalFirstThunk tranne per il fatto che
qui gli IMAGE_THUNK_DATA verranno patchati dal loader di Windoz con gli indirizzi delle
rispettive funzioni (l'insieme dei vari FirstHunk una volta patchati costituisce la IAT).
Non metto tutta la IT altrimenti occuperei byte inutili, al massimo guardatevela da HIEW,
da cui potete facilmente verificare i vari IMAGE_IMPORT_DESCRIPTOR.
A questo punto abbiamo gia' capito come si puo' fare ad aggiungere la nostra funzione:
sara' necessario aggiungere un nostro descriptor a quelli gia' esistenti cercando un posto
dove poter mettere i Thunk, il nome del nostro modulo e quelli delle funzioni importate.
Una soluzione potrebbe essere quella di aggiungere 5 dw alla fine dei descriptor esistenti
e usare quelle, bene avviso subito di non farlo:) in quanto se si facesse cosi' sarebbe
necessario patchare (oltre ai descriptor precedenti) *tutti* i thunk (e non sono pochi) e
tutti i vari jmp dword [] nella sezione .text responsabili della chiamata alle varie API
richieste.
Il problema e' che alla fine dei descriptor ci sono le 5 dw NULL che sono indispensabili e
poi iniziano subito gli OriginalFirstThunk. Si potrebbero spostare in su i descriptor, il
problema e' che la IT inizia proprio all'inizio della sezione .idata che la contiene,
quindi non abbiamo spazio. Andiamo alla fine di .idata... non c'e' spazio a sufficienza
nemmeno li'.
Andiamo allora alla fine della sezione .rdata, ecco cosa vediamo
.004B9090: 00 00 00 00-00 00 00 00-00 00 00 00-00
00 00 00
.004B90A0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B90B0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B90C0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B90D0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B90E0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B90F0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9100: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9110: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9120: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9130: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9140: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9150: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9160: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9170: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9180: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9190: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B91A0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B91B0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B91C0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B91D0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B91E0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B91F0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
Hum... niente male, mi sa proprio che i nuovi descriptor li metteremo li';).
--------------------------
PICCOLA NOTA: affinche' la IT sia valida basta che i descriptor costituiscano tutti un
blocco compatto, non e' obbligatorio che poi i thunk, i nomi dei moduli e delle funzioni
occupino posizioni precise, basta naturalmente aggiurnare l'IT RVA nella DataDirectory.
--------------------------
ALTRA PICCOLA NOTA: i vari thunk che puntano al nome della sezione non puntano all'inizio
della stringa del nome, bensi' una word + indietro: tale word serve infatti a specificare
l'ordinal della funzione, ma non sempre e' utilizzata (solo se l'IMAHE_THINK_DATA che la
punta ha il byte + alto acceso). La stringa del nome inoltre e' NULL terminated.
--------------------------
Fatte le piccole note, spostiamo i descriptor esistenti in su, aggiungiamo il nostro,
patchamo i vari RVA, aggiungiamo i nostri thunk, il nostro nome della dll e i nomi delle
funzione da importare e naturalmente aggiorniamo il valore dell'RVA della IT nella DataDir
(si trova 128 byte avanti rispetto all'inizio della Signature.
Fatto questo, possiamo cancellare i vecchi descriptor. Ecco allora come si presenta
l'inizio della IT nel file patchato.
.004B9040: 04 A1 0B 00-EC FF 61 05-2C 8D 58 05-7C
AD 0B 00 � ��a ,X |�
.004B9050: E8 A1 0B 00-CC A2 0B 00-2C 8D 58 05-2C 8D 58 05 � ̢ ,X ,X
.004B9060: 86 AD 0B 00-DC A2 0B 00-EC A2 0B 00-2C 8D 58 05 � ܢ � ,X
.004B9070: C4 8D 58 05-90 AD 0B 00-04 A3 0B 00-1C A3 0B 00 �X � � �
.004B9080: 2C 8D 58 05-2C 8D 58 05-9D AD 0B 00-E8 A4 0B 00 ,X ,X � �
.004B9090: B4 A6 0B 00-2C 8D 58 05-CC A7 58 05-AA AD 0B 00 �� ,X ̧X ��
.004B90A0: BC A6 0B 00-C4 A6 0B 00-2C 8D 58 05-2C 8D 58 05 1/4� Ħ ,X ,X
.004B90B0: B2 AD 0B 00-CC A6 0B 00-D4 A6 0B 00-2C 8D 58 05 �� ̦ Ԧ ,X
.004B90C0: 68 A6 58 05-BF AD 0B 00-DC A6 0B 00-E4 A6 0B 00 h�X �� ܦ �
.004B90D0: 40 98 58 05-60 9A 58 05-CC AD 0B 00-F4 A6 0B 00 @X `X Ì ï¿½ï¿½
.004B90E0: 04 A7 0B 00-90 A3 58 05-2C 8D 58 05-D9 AD 0B 00 � �X ,X Ù
.004B90F0: DC A7 0B 00-B4 A8 0B 00-2C 8D 58 05-2C 8D 58 05 ܧ �� ,X ,X
.004B9100: E3 AD 0B 00-D0 A8 0B 00-EC A8 0B 00-54 7B 65 05 � Ш � T{e
.004B9110: 14 00 62 05-EF AD 0B 00-2C AB 0B 00-6C AD 0B 00 b � ," l�
.004B9120: 2C 8D 58 05-2C 8D 58 05-FA AD 0B 00-74 AD 0B 00 ,X ,X �� t�
.004B9130: 70 91 0B 00-00 00 00 00-00 00 00 00-60 91 0B 00 p' `'
.004B9140: 7C 91 0B 00-00 00 00 00-00 00 00 00-00 00 00 00 |'
.004B9150: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B9160: 43 52 59 50-54 2E 44 4C-4C 00 00 00-00 00 00 00 CRYPT.DLL
.004B9170: A0 91 0B 00-A7 91 0B 00-00 00 00 00-A0 91 0B 00 ' �' '
.004B9180: A7 91 0B 00-00 00 00 00-00 00 00 00-00 00 00 00 �'
.004B9190: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.004B91A0: 00 00 46 75-6E 63 00 00-00 4D 61 69-6C 43 72 79 Func MailCry
.004B91B0: 70 74 00 00-00 00 00 00-00 00 00 00-00 00 00 00 pt
Adesso rimane da fare solo un'ultima cosa: dobbiamo aggiungere in coda ai jump dword []
presenti alla fine della sezione .text quelli relativi alle nostre funzioni importate, in
modo che alla fine risulti cosi'
.004AA48C: FF2544AD4B00 jmp d,[0004BAD44]
.004AA492: FF2548AD4B00 jmp d,[0004BAD48]
.004AA498: FF254CAD4B00 jmp d,[0004BAD4C]
.004AA49E: FF2550AD4B00 jmp d,[0004BAD50]
.004AA4A4: FF2554AD4B00 jmp d,[0004BAD54]
.004AA4AA: FF2558AD4B00 jmp d,[0004BAD58]
.004AA4B0: FF255CAD4B00 jmp d,[0004BAD5C]
.004AA4B6: FF2560AD4B00 jmp d,[0004BAD60]
.004AA4BC: FF2564AD4B00 jmp d,[0004BAD64]
.004AA4C2: 50 push eax
.004AA4C3: 6AFF push 0FF
.004AA4C5: 2574AD4B00 and eax,0004BAD74 ;" K�t"
.004AA4CA: DC4000 fadd q,[eax][00000]
.004AA4CD: FF257C914B00 jmp d,[0004B917C]
.004AA4D3: FF2580914B00 jmp d,[0004B9180]
Dove jmp d,[0004B9180] salta al thunk corrispondente a MailCrypt, mentre jmp d,[0004B9180]
salta a quello di Func (la quale cmq e' solo una dimostrazione che noi non useremo).
Molto bene, ora per quanto riguarda il discorso IT abbiamo finito. Per chiamare una delle
nostre funzioni bastera' da un punto qualsiasi del codice fare una call a 4AA4CD o 4AA4D3,
a seconda rispettivamente che si vogliano chiamata Func o MailCrypt.
Detto questo, passiamo alla creazione vera e propria della dll. I src completi li trovate
nell'allegato, nella spiegazione non li incollero' tutti.
All'avvio il prg chiamera' la funzione MailCrypt, che quindi dovra' creare una modal
dialog box (per le differenze tra modal, modeless, approfondimenti vari sulle dialog box e
cosi' via rimando ai tute di Iczelion) dove poter immettere pw e key. Nel mio esempio pw e
key vanno inserite nella stessa edit box, non perche' non avevo voglia di crearne 2:) ma
per il fatto che in tal modo possiamo fare in modo ad ex che se viene usato un nick o una
stringa di una certa lunghezza una parte serva per la pw e l'altra per la key, oppure che
i byte pari siano una cosa e quelli dispari un'altra, e cosi' via... insomma mi sembra una
buona scelta.
Prima di tutto allora ci serve uno script rc per definire le risorse, dove dovremo mettere
la dialog, un'edit box, un bottone, un testo da scrivere subito prima della casella dove
inserire il testo (del tipo "Key", anche se sappiamo che non e' una semplice
key) e se vogliamo pure un'icona.
Creato il file, possiamo iniziare a scrivere la dll vera e propria. Ecco di seguito alcuni
passi + improtanti dei src.
----------==========----------
PUBLICDLL MailCrypt
PUBLICDLL Func
ICON_SMALL equ 0
----------==========----------
Questo sara' necessario metterlo prima della sezione .data, come si capisce facilmente
serve a indicare le funzioni esportate dalla dll stessa. Sopra ho messo anche ICON_SMALL
equ 0 (che servira' per l'icona) visto che in W32.inc non l'ho trovata, cmq nei src ho
aggiunto la voce al file inc.
----------==========----------
filename db
'c:\pmail\mail\*.cnm',0
Key db
30 dup(00h)
path db
'c:\pmail\mail\',0
dllname db 'Crypt.dll',0
dummy dd 0
sizemail dd 0
databuffer dd 0
nomifile dd 0
chkdw dd 0
dummyb dd 0
counti db 0
count db
0
FileStruct WIN32_FIND_DATA <?>
----------==========----------
Qui troviamo alcuni data che serviranno in seguito. filename servira' per cercare i file
delle mail (cnm), FileStruct punta a una struttura che ci servira' quando dovremo cercare
i file, Key e' il testo inserito (pw + key), databuffer e nomifile serviranno come
puntatori a buffer allocati con VirtualAlloc, per il resto e' tutto molto semplice.
----------==========----------
.code
DllEntry Proc hInstDLL:HINSTANCE, reason:DWORD, rsvd:DWORD
mov eax, TRUE
ret
DllEntry Endp
----------==========----------
Questa e' la funzione di entrypoint della dll, la si puo' chiamare come si preferisce,
essa prende 3 parametri (di cui cmq il 3� e' riservato). Alla fine del codice asm sara'
poi necerrario scrivere end <nome_funzione_di_entrypoint>.
hInstDLL e' il module handle della dll stessa, reason puo' assumere 4 valori diversi:
- DLL_PROCESS_ATTACH: quando la dll e' iniettata per la prima volta nell'address space del
processo.
- DLL_PROCESS_DETACH: quando la dll e' scaricata dall'address space del processo.
- DLL_THREAD_ATTACH: quando il processo crea un nuovo thread.
- DLL_THREAD_DETACH: quando un thread del processo viene distrutto.
Se in eax viene resituito TRUE la DLL continuera' nell'esecuzione, altrimenti non verra'
caricata.
----------==========----------
MailCrypt Proc checkbyte:DWORD
push checkbyte
pop chkdw
cmp dword ptr chkdword, 23h
jnz copacabana
call GetModuleHandleA, offset dllname
mov _hInst, eax
xor eax, eax
mov ax, IDD_DIALOG1
call DialogBoxParamA, _hInst, eax, NULL, offset
DlgProc, NULL
ret
----------==========----------
Ed ecco qui la nostra bella funzioncina. Come vedete essa riceve un parametro, checkdw. Ho
deciso di far cosi' per una ragione molto semplice: sebbene abbia messo come esempio 2
funzioni diverse nella dll e le abbia inserite entrambe nella IT dell'exe, in questo
esempio ne utilizzeremo solo una, visto che il processo di cifratura e' estremamente
banale (infatti poi sta a ognuno il compito di implementarlo a dovere, altrimenti questo
si chiamerebbe tool, non tutorial di everse engineering), e quindi dovremo passare alla
stressa funzione parametri diversi a seconda che vogliamo decrittare la mail perche' il
prog e' appena avviato o vogliamo rimanipolarla con la chiave inserita all'inizio se
stiamo uscendo dal prg stesso. Nel caso sopra, se il parametro passato, chkdword, e' 0x23,
allora dovremo chiedere la chiave di decrypt, altrimenti significa che il prg e' terminato
e dobbiamo ricifrare tutto.
Per prendere la key (se il prg e' stato appena avviato) chiamiano prima di tutto
GetModuleHandleA per ricevere l'handle della dll (attenzione che il parametro passato non
deve essere NULL come per gli exe, altrimenti ci viene restituito l'handle del modulo
chiamante e non della dll), quindi visualizziamo la modal box con DialogBoxParamA, che
quindi passa l'esecuzione a DlgProc, che avra' il compito di esaminare i messaggi che
arrivano e comportarsi di conseguenza. In particolare, quando viene premuto il tasto
"OK" verra' chiamata la funzione Crypt, cuore del prg vero e proprio (wow che
bella espressione).
----------==========----------
Crypt proc _hDlg:dword
call GetDlgItemTextA, _hDlg, IDC_EDIT1, offset Key,
32h
cmp dword ptr [Key+5], 'ztiR'
jz ecchime
call EndDialog, __hwnd, NULL
call ExitProcess
copacabana:
xor ecx, ecx
mov edi, offset FileStruct
beach:
mov byte ptr [edi+ecx], 0
inc ecx
cmp ecx, 100
jl beach
mov byte ptr counti, 0
----------==========----------
Il codice qui si capisce molto facilmente, viene preso il testo, quindi i char 6, 7, 8 e 9
vengono confrontati con la dw "Ritz" (e la fantasia dilaga), se coincidono si
prosegue con la key vera e propria, altrimenti il prg va direttamente al creatore.
Avrete capito che qui avviene un check della pw. Come sempre l'esempio e' estremamente
banale, l'algo per il check ognuno lo sviluppa come meglio crede, un check del genere non
e' degno nemmeno di WinZip, ma e' solo un esempio... come sempre, largo alla fantasia.
Se il check passa si saltano via copacabana e beach, questo perche' esse servono solo
quando il prg termina la sua esecuzione e si deve ricifrare la mailbox, infatti esse sono
solo addette al riazzeramento del buffer che contiene la struttura che serve per trovare i
file. Si salta infatti qui:
----------==========----------
ecchime:
call VirtualAlloc, NULL, 10000, MEM_COMMIT,
PAGE_READWRITE
mov nomifile, eax
add nomifile, 14
xor eax, eax
xor ecx, ecx
xor ebx, ebx
xor edx, edx
call FindFirstFileA, offset filename, offset
FileStruct
mov ebx, nomifile
sub ebx, 11
ancora:
inc count
add ebx, 11
mov ecx, 11
mov esi, offset [fd_cFileName+FileStruct]
mov edi, ebx
repz movsb
call FindNextFileA, eax, offset FileStruct
test eax, eax
jnz ancora
sub counti, 11
girazzo:
add counti, 11
mov ebx, nomifile
add ebx, counti
sub ebx, 14
mov ecx, 14
mov esi, offset path
mov edi, ebx
repz movsb
mov edx, nomifile
add edx, counti
sub edx, 14
call CreateFileA, edx, GENERIC_READWRITE, NULL,
NULL, OPEN_EXISTING, NULL, NULL
cmp eax, INVALID_HANDLE_VALUE
jnz tutto_ok
call MessageBoxA, NULL, offset err_open_txt, offset
err_open_cap, MB_ICONSTOP
call EndDialog, __hwnd, NULL
call ExitProcess
tutto_ok:
mov dword ptr handlez, eax
----------==========----------
Ho usato VirtualAlloc per riservare lo spazio dove vengono accodati i nomi dei file,
questo sia per rendere la dll + piccola, sia perche' in questo modo si puo' riservare lo
spazio che si vuole (in 10k stanno moltissimi nomi accodati) senza avere il problema di
non averne abbastanza.
VirtualAlloc, infatti, puo' riservare una zona di memoria nel virtual address space del
processo chiamante. Ecco la sintassi.
LPVOID VirtualAlloc(
LPVOID lpAddress, // indirizzo della regione da
riservare
DWORD dwSize, // grandezza della regione (in
byte)
DWORD flAllocationType, // tipo di allocazione
DWORD flProtect // tipo di protezione
);
Il 1� par se lasciato a NULL dice a Win di determinare da solo la regione da allocare. Il
2� par indica in byte la grandezza della regione, il 3� il tipo di allocazione (con
MEM_COMMIT la regione viene allocata in modo da poter essere utilizzata subito), il 4�
par indica che tipo di accesso desideriamo.
Il valore di ritorno e' un puntatore alla regione allocata.
Una volta che la regione non ci serve + bastera' liberarla con VirtualFree.
Allocato lo spazio necessario, bisogna scrivere la routine che trova uno ad uno tutti i
file cnm e li accoda lasciando tra un nome e l'altro un byte NULL; questo e' stato
possibile utilizzando 2 particolari API, FindFirstFileA e FindNextFileA.
Eccone di seguito la sintassi.
HANDLE FindFirstFile(
LPCTSTR lpFileName, //
puntatore al nome file da cercare
LPWIN32_FIND_DATA lpFindFileData // puntatore alle info di ritorno
);
BOOL FindNextFile(
HANDLE hFindFile, //
handle di ricerca
LPWIN32_FIND_DATA lpFindFileData // puntatore alle info di ritorno
);
La prima cerca in una dir un file il cui nome corrisponda a quello passato nel 1�
parametro (nella dll lpFileName e' una stringa del tipo 'c:\pmail\mail\*.cnm', da notare
che vengono accettati i caratteri jolly), mentre il 2� punta a una particolare struttuta
di questo tipo:
typedef struct _WIN32_FIND_DATA { // wfd
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
TCHAR cFileName[ MAX_PATH ];
TCHAR cAlternateFileName[ 14 ];
} WIN32_FIND_DATA;
Di cui a noi interessa cFileName, che quindi si trova a 44 byte (0x2C) dall'inizio della
struttura stessa (si tratta di una stringa NULL-terminated), visto che a sua volta
FILETIME e' una truttura del tipo
FILETIME struct
ft_dwLowDateTime DWORD 0
;low-order 32 bits
ft_dwHighDateTime DWORD 0
;high-order 32 bits
FILETIME ends
Per quanto riguarda FindNextFileA, invece, essa ha bisogno dell'handle di ricerca
restituito da FindFirstFileA e del solito puntatore per le info di ritorno. Quando non
trova + file, restituisce NULL.
Per quanto riguarda copacabana, essa sara' utile nel decrypt per riazzerare la struttura
FIND_DATA.
Fatto questo sara' necessario, dopo aver aperto uno a uno i file, leggerli, decrittarli e
sovrascriverli con le solite API CreateFileA, GetFileSize (per allocare il buffer
necessario contenere i dati), ReadFile, SetFilePointer, WriteFile e CloseHandle, ecco la
parte di codice interessata:
----------==========----------
call GetFileSize, dword ptr handlez, NULL
mov dword ptr sizemail, eax
call VirtualAlloc, NULL, eax, MEM_COMMIT,
PAGE_READWRITE
mov databuffer, eax
call ReadFile, dword ptr handlez, databuffer,
dword ptr sizemail, offset dummy, NULL
mov ecx, dword ptr sizemail
mov dl, byte ptr [Key]
mov esi, databuffer
xora:
xor byte ptr [ecx+esi], dl
dec ecx
test ecx, ecx
jnz xora
mov dword ptr dummy, 0
call SetFilePointer, handlez, NULL, NULL, FILE_BEGIN
call WriteFile, handlez, databuffer, dword ptr
sizemail, offset dummy, NULL
call CloseHandle, handlez
call VirtualFree, databuffer, sizemail, MEM_DECOMMIT
dec count
jnz girazzo
call VirtualFree, nomifile, 10000, MEM_DECOMMIT
ret
Crypt Endp
----------==========----------
Da notare l'elementare operazione di decrypt (se e' degna di tale nome) che semplicemente
xora ogni byte di ogni file col 1� char inserito.
Quanto il file e' stato riscritto si chiude l'handle relativo e (tramite count) se tutti i
file sono a posto si esce dalla call, altrimenti si passa al file successivo.
Per quanto riguarda invece la funzione di decrypt, in questo caso essa e' contenuta in
MailCrypt, solo che inizia da copacabana, quindi essa semplicemente rimanipola tutta la
mailbox nella stessa maniera iniziale e, una volta finito, torna all'exe chiamante, questo
e' possibile farlo solo in *questo* caso, se le operazioni di encrypting fossero state +
complicate si sarebbe dovuto scrivere una procedura apposita di decrypt (come ho gia'
detto)... spero almeno che facciate cosi';).
Prima di compilare la dll sara' necessario scrivere un file def che contenga le funzioni
che vogliamo esportare
---------- Crypt.def ----------
LIBRARY Flaf
EXPORTS MailCrypt Func
------------- EOF -------------
Bene... anche la dll e' stata scritta, ora basta semplicemente modificare l'exe in modo
che appena si avvia il prg (diciamo pure all'entrypoint:) ) e prima di tutte le chiamate a
ExitProcess (che per nostra fortuna sono solamente una) venga chiamata la nostra funzione
MailCrypt, stando attenti a pushare 0x23 all'avvio e un qualsiasi valore != 23 alla fine,
lo spazio lo trovate dove volete, qui non penso siano necessarie spiegazioni, ecco cmq la
situazione di winpm-32.exe patchato completamente:
.004AA4CD: FF257C914B00 jmp d,[0004B917C]
.004AA4D3: FF2580914B00 jmp d,[0004B9180]
.004AA4D9: 0000 add [eax],al
.004AA4DB: 6A23 push 023
.004AA4DD: E8F1FFFFFF call .0004AA4D3 -------- (1);MailCrypt
.004AA4E2: A117B14A00 mov eax,[0004AB117]
.004AA4E7: E9196BF5FF jmp .000401005 -------- (2);Si torna all'inizio
.004AA4EC: 0000 add [eax],al
.004AA4EE: 6A00 push 000
.004AA4F0: E8DEFFFFFF call .0004AA4D3 -------- (3);MailCrypt
.004AA4F5: 6A00 push 000
.004AA4F7: E86CF8FFFF call .0004A9D68 -------- (4);ExitProcess
.004AA4FC: 0000 add [eax],al
All'inizio avviene un jmp a 4AA4DB, alla fine un jmp a 4AA4EE. Sarebbe meglio anche
aggiungere pure l'istro a 4AA4E2 che e' stata sovrascritta all'entrypoint dal jmp 4AA4DB.
Non resta che crittare la mailbox, patchare l'exe, implementare come meglio si desidera la
dll, lanciare l'exe e divertirsi mentre come per magia nessuno riesce piu' a trovare gli
url di quelle 10 foto che ogni giorno la vostra amata ml porno vi invia;).
Fine.
Non mi pare il caso di dilungarsi su come ottenere lo stesso risultato tramite un exe, la
cosa e' molto meno funzionale, almeno a parer mio, bisognerebbe eseguire il nostro exe,
crittare la mail, avviare il processo di winpm-32.exe, aspettare che finisca, rimettere
tutto a posto e uscire... la dll mi sembra un modo + pulito di operare.
Considerazioni finali e saluti |
Non penso proprio che vi siate divertiti troppo a leggere questo tute;) cmq chi e'
arrivato in fondo avra' capito (se ce ne fosse ancora bisogno) che non sempre (o, meglio,
quasi mai) i programmi sono come li vogliamo noi, quindi per quanto possibile cercate di
far fare al software quello che *voi* volete. Se una funzione di un prg non vi piace e
serve soltanto a rallentarlo, toglietela, se vi piacerebbe poter usufruire di una funzione
non implementata, aggiungetela voi, insomma il reverse engineering serve proprio a questo,
abbiamo a disposizione programmi veramente potenti per far cio', da mostri come IDA a
prog. apparentemente piu' semplici come HIEW, senza il quale pero' ad esempio il lavoro
sulla IT sarebbe stato mooolto piu' difficile (provate voi a farlo solo con HexWorkShop) e
che ci permettono di fare praticamente quello che vogliamo, senza dover limitarci al
solito cambiamento jz/jnz/jmp/nop... personalmente lavori di questo tipo devo ammettere
che mi interessano piu' del puro cracking delle varie protezioni dei prgz, salvo
naturalmente casi particolari.
Detto questo, passiamo ai dovuti saluti finali.
Innanzi tutto devo ringraziare enormemente Kill3xx, per il fatto che ha sempre una
risposta a ogni domanda (e non gliene faccio poche) ed e' pure sempre estremamente
disponibile a starmi a sentire... in questa situazione, in particolare, per quanto
riguarda la sistemazione della IT e per l'utilissimo testo indicato all'inizio di questo
tute (gran parte delle info sulla IT sono state prese da li'). Grazie di tutto killo:).
Una grande tnx anche a Yado per i vari suggerimenti dati (auguri anche per il crypter).
Un saluto poi va a Quequero, [aLT255], TiN_MaN, LittleJohn, BlackDruid, +MaLaTTiA,
NeuRaL_NoiSE, Brigante, cod, xOA, AndreaGeddon, Int19, GuZuRa (il 1� risolutore del mio
crkme), Spin0ne, GR!SU (che non sento da un po'), ZeroByte, BUG, NikDH etc etc etc.
Byz all!!
Ritz
Disclaimer |
UIC's page of reverse engineering, scegli dove andare: |
Home Anonimato Assembly CrackMe ContactMe Forum Iscrizione |
Lezioni Links Linux NewBies News Playstation |
Tools Tutorial Search UIC Faq |
UIC |