UltraEdit32 |
||
Data |
by "AndreaGeddon" |
|
17/04/2001 |
Published by Quequero |
|
|
Mmmmm Andrè, hai fatto uno sproloquio, un tutorial di 2000 pagine per spiegare ASPack che è una cazzatella.....Ma non ti vergogni? Ma con quale faccia mi mandi ancora i tutorial? Hihihihihihi E che pretendi che sia tutto rosa è fiori? "Bravo qua, Bravo la" eh no! Ogni tanto devo pure dirti che non va bene senno poi ti monti la testa ecc....ecc.... Thomas Milian avrebbe detto: "Ah gigè, ma quante cazzo ne voi sapè? Ohhhhhh! :P hihihihihh |
...e in strani eoni anche la morte può morire. |
.... |
|
.... |
Difficoltà |
( )NewBies (x)Intermedio (x)Avanzato ( )Master |
Ecco un altro manual unpacking: questa volta il bersaglio è UltraEdit32 protetto con AsPack, in più ci sarà l'eliminazione del time limit e nag screen.
Introduzione |
Tools usati |
URL o FTP del programma |
Notizie sul programma |
Essay |
Sezione | VSIZE | VOFFSET | RSIZE | ROFFSET | FLAGS |
.text | 000CB000 | 00001000 | 00059200 | 00000400 | C0000040 |
.rdata | 00025000 | 000CC000 | 00008400 | 00059600 | C0000040 |
.data | 00018000 | 000F1000 | 00003600 | 00061A00 | C0000040 |
.rsrc | 00035000 | 00109000 | 0000EA00 | 00065000 | C0000040 |
.aspack | 00003000 | 0013E000 | 00002E00 | 00073A00 | C0000040 |
.data | 00001000 | 00141000 | 00000000 | 00076800 | C0000040 |
e segnamoci anche l'entry point: 13E001 (VA = 0053E001)
Vediamo che l'entry point non punta alla prima sezione, cioè alla text, ma finisce nella penultima sezione, la AsPack. Quindi abbiamo tutte le carte in regola per un file packato. Inoltre la sezione .aspack ci fa identificare subito il packer :-). Come al solito NON ci scarichiamo l'UnAsPack da Protools, ma ci faremo tutto a mano. Come vedremo il lavoro non sarà affatto difficile. Come al solito partiamo dal presupposto che faremo decriptare il file a runtime e poi ce lo salveremo con icedump. Per fare ciò dobbiamo iniziare a steppare dall'entry point del loader, cioè dalla riga 0053E001. Per qualche strano motivo il Sice Loader non mi poppa quando carico il file, quindi per breakare sull'entry point mettiamo il classico CC all'offset corrispondente all'EP nel file fisico, cioè all'offset 73A01. Ricordatevi che il byte originale a quella locazione è 60h. Ora settiamo il BPINT 3 in softice e lanciamo il programma. Ecco il softice poppato sull'entry point del programma. Ora però non vogliamo eseguire il CC, quindi dobbiamo ripristinare il byte originale dell'entry point, lo facciamo con il comando
e eip 60
così mettiamo l'originale PUSHAD al posto del nostro INT 3. Okei, ora ci dobbiamo steppare tutto il packer.... naaaaaaaaaaaa. Che ce frega! Dalla precedente tabella (e anche dal map32) vediamo che la sezione di codice, la .text, si estende dalla riga 00401000 alla riga 004CC000. Quindi per arrivare all'original entry point del programma settiamo un bel breakpoint on range su tutta la sezione, cioè:
BPR 00401000 004CC000 RW if eip < 004CC000
abbiamo aggiunto la condizione che l'eip deve essere contenuto nella sezione di codice, così evitiamo di breakare innumerevoli volte ad ogni accesso del loader alla sezione di codice per il decriptaggio. Ora lasciate eseguire il programma con F5. Notiamo che ci mette molto più tempo a eseguirsi: è normale! Il bpr condizionato pesa parecchio. Cmq dopo alcuni secondi il softice dovrebbe poppare alla linea
00401000 RET
non fatevi ingannare! Questo non è l'original entry point! Infatti eseguite il ret e tornerete alla sezione del loader. Non so perchè breaka qui, cmq non fa niente, lasciamo di nuovo esguire il programma, aspettiamo qualche secondo... tada!! Ora il softice poppa nella seguente zona:
0048E7F5
push ebp
| il softice ci porta qui
0048E7F6 mov ebp, esp
|
creazione stack privato per la funzione
0048E7F8 push 0FFFFFFFFh
0048E7FA push offset 004DDAB8
0048E7FF push offset 004937F0 |
abbiamo subito una istallazione
0048E804 mov eax, large fs:0 |
repentina di un exception handler
0048E80A push eax
|
0048E80B mov large fs:0, esp |
0048E812 sub esp, 58h
0048E815 push ebx
0048E816 push esi
0048E817 push edi
0048E818 mov [ebp-18h], esp
0048E81B call ds:GetVersion | chiamata a GetVersion
tipico stile del compilatore C che usa MFC :-). Questo vuol dire che il codice è decriptato e funzionante, quindi il compito del loader è già terminato. Allora possiamo salvarci il tutto! Possiamo usare IceDump per dumparci su disco le sezioni decriptate, ma poi dovremmo fare un bel lavoro di taglia & cuci, riallineamento del PE e cazzi vari... non ne ho voglia! Facciamo così: mentre siamo alla riga 0048E7F5 usiamo il comando "a", e ci farà immettere del codice a partire dalla linea dell'EIP, quindi noi assembliamo un bel
0048E7F5 JMP 0048E7F5
così il prog jumperà in continuazione sul suo entry point come uno scemo :-). L'opcode di questo se ben ricordo è EBFE, quindi prima di assemblare il tutto salvatevi i due bytes originali (che sono 55 8B). Ora che avete assemblato l'auto jump potete uscire dal softice. Il programma non si avvierà chiaramente, perchè rimane bloccato sul suo EP. Abbiamo fatto questo per lasciare preservato il file originale, così siamo sicuri che dopo il dump non abbiamo la sezione data compromessa. Ora apriamo il PEditor, nella lista dei task scegliamo quello dell'ultraedit e facciamo un DUMP FULL. In questo modo il PEditor si ricalcola tutto l'allineamento del PE e non dobbiamo farlo noi :-). Ora abbiamo il nostro bel DUMPED.EXE di 1.288 kb contro i 474 kb del file originale. Bella compressione. Ora eseguiamo il nostro dumped e... crash! Beh non potevamo sperare che andasse diversamente. Per prima cosa l'EP è sempre quello del Loader, e non va bene: dobbiamo sostituirlo con l'EP che abbiamo trovato poco fa, cioè 0048E7F5. Ora con l'hex editor dobbiamo andare all'offset dell'entry point per ripristinare i bytes che noi abbiamo sostituito con l'autojump. Usiamo l'FLC e l'offset dell'EP sarà 8E7F5. Che bello lavorare con i file dumpati!! Oki rimettete a posto il 55 8B. Riproviamo ad eseguire il programma... tadaaaa! Funziona! FERMI LI'!! Non abbiamo finito!! Come no? Il file funziona?! Si funziona, ma provatelo a far funzionare su un altro PC... beh se non avete questa possibilità allora vi anticipo io che non funzionerà. Si tratta di magia nera??? No :-). Semplicemente la IT è manomessa (e te pareva), però il packer è così fesso che cmq i FirstThunk li ha lasciati validi. Ora i FirstThunk sono gli EP delle funzioni importate e sono stati dumpati dalla VOSTRA memoria, il che vuol dire che sul vostro PC il programma funziona, perchè quando lo eseguite gli indirizzi corrispondono sempre alle funzioni (per lo meno al 99%! c'è sempre la possibilità che il win riallochi in qualche altro modo le vostre api), solo che in un altro pc gli indirizzi vengono mappati in genere ad un altro indirizzo, indi CRASH! Come risolviamo questo inconveniente? Ricostruendo la IT! :-). Beh dopo essere passato per safedisc devo dire che questa IT è una passeggiata. Cmq vediamo di capire come agire. Innanzitutto dobbiamo valutare l'entità della manomissione. Prendiamo al solito il PEditor, andiamo nella sezione directory: abbiamo l'RVA dell' IT pari all'offset 13F248. Già qui si accende una lampadina: questo offset si trova nella sezione AsPack, quindi non è l' IT originale del programma, ma è l' IT del loader. Ora visualizziamo le Imports col PeDitor: vediamo che i moduli sono risolti correttamente ma le funzioni importate no. Inoltre vedete che il campo degli OriginalFirstThunk è azzerato per ogni modulo, mentre il campo del ForwarderChain è settato al relativo forwarder. Questo vuol dire che il file dumpato non ricalcola a runtime i FirstThunk di ogni funzione, ma usa gli indirizzi già presenti nella IAT per accedere alle funzioni importate. Quello che vogliamo fare noi è di ricostruire la IT in modo da forzarla a ricalcolare la IAT. Per fare questo però ci servono gli OriginalFirstThunk che non abbiamo. Nel file non ve n'è traccia: a runtime devono essere usati però! Quindi andiamo cerchiamo il punto in cui vengono eliminati, e prima dell'eliminazione ce li salviamo. Prima di tutto diamo uno sguardo alla IT attuale... ma dove sta? In genere è la sezione rdata che dovrebbe contenere le info sulla IT, cosa che in questo caso possiamo confermare dal fatto che la call a GetVersion chiama un puntatore contenuto proprio nella rdata ( [004CC344] ). Quindi andiamo con il nostro HexEditor a cercare nel file nella sezione rdata e vediamo cosa ci troviamo. La sezione si trova all'offset CC000, e subito troviamo un array di puntatori del tipo BFxxxxxx. Okei, questi sono i FirstThunk. Ora posizioniamo il cursore all'inizio del file e cerchiamo la stringa "kernel32", scartiamo la prima volta che viene trovata, scartiamo la seconda e arriviamo alla terza: qui la troviamo incapsulata in un mare di nomi di funzioni, siamo all'offset EEED4. Quindi qui abbiamo i nomi di funzione belli in chiaro. Quello che ci manca sono gli OriginalFirstThunk, cioè l'array con i puntatori ai nomi delle funzioni. Possiamo cercarli, ma la cosa risulterebbe alquanto pesante, senza contare che potremmo non trovarli. Quindi possiamo scegliere la via più intelligente: sapendo dove vengono messi i FirstThunk possiamo monitorizzare gli accessi in scrittura ai FirstThunk e vedere da dove li calcola (e per calcolarli deve necessariamente ricorrere agli OriginalFirstThunk!). Dunque, quello che facciamo è semplicemente di steppare all'entry point del loader del programma originale (non del dump), quindi settiamo un bel
BPM 004CC000 W
così vediamo quando ci va a scrivere i FirstThunk, così possiamo fare un pò di backtrace e tanare gli OrigFirstThunk. Ora lasciate correre il programma... avremo un pop alla linea
0053E185 REPZ MOVSD
okei, c'è un movimento di dwords che ha come destinazione (edi) la locazione 004CC000. Eseguite questo REPZ e quello successivo, e adesso avrete un array di puntatori del tipo 000Fxxxx. Questo è un puntatore RVA, quindi aggiungiamogli l'image base, e ora guardiamo a cosa punta: già! Punta all'indirizzo
004F027C in cui si trova la stringa RegQueryValueExA. Quindi ora abbiamo l'IT con gli OriginalFirstThunk. Se lasciamo di nuovo correre il programma col BPM attivo popperemo sulla riga
0053E37E
dalla quale vengono messi in 004CC000 i FirstThunk sovrascrivendo gli OriginalFirstThunk. Okei, quindi ora abbiamo trovato gli OriginalFirstThunk, non ci resta che dumparceli quando dalla riga 0053E185 abbiamo eseguito i due REPZ. Quindi riarrivate lì e ora usiamo icedump:
/DUMP 004CC000 25000 c:\uedit.it
abbiamo salvato 25000h bytes a partire dalla locazione 004CC000 sul file c:\uedit.it, praticamente abbiamo dumpato l'intera sezione rdata prima della sua manomissione. Ora apriamo l'hexeditor, apriamo il file uedit.it e copiamone tutto il contenuto, poi apriamo il dumped.exe, andiamo all'offset CC000, selezioniamo 25000h bytes, cancelliamoli e incolliamoci i bytes appena copiati, così abbiamo sostituito la sezione fisica nel file. Ma abbiamo finito? Non acora. Di nuovo così com'è il file non funziona: ci manca di riaggiustare i descrittori dei moduli importati. Ho cercato di trovare i descrittori originali, ma non li ho trovati, quindi sovrascriveremo quelli esistenti della sezione .aspack. Prima però dobbiamo farci una mappa degli OriginalFirstThunk: non sappiamo infatti il loro ordine e i loro address, quindi partiamo ad esaminare da CC000. Gli OriginalFirstThunk sono contenuti in un array terminato da una NULL dword, quindi vediamo tutti gli OrigFirstThunk finchè troviamo 4 bytes azzerati, così vuol dire che abbiamo trovato i limiti degli OrigFirstThunk di un modulo, ma di che modulo? Andiamo a vedere a cosa puntano! Per esempio il primo OrigFirstThunk a CC000 è 000F027C e punta al nome RegQueryValueExA (come abbiamo anche visto prima in memoria), e tale funzione è esportata da wsock32.dll, quindi è di questo modulo che stiamo parlando. Procediamo analogamente per ogni gruppo di OriginalFirstThunk, fino a farci la seguente tabella:
MODULO | FROM | TO | INDICE |
kernel32.dll | CC1C0 | CC460 | 5° modulo nella iat |
imm32.dll | CC1AC | CC1BC | 4° modulo nella iat |
wsock32.dll | CC830 | CC884 | 10° modulo nella iat |
ssce4332.dll | CC48C | CC4E0 | 7° modulo nella iat |
user32.dll | CC4E4 | CC81C | 8° modulo nella iat |
gdi32.dll | CC060 | CC1A8 | 3° modulo nella iat |
comdlg32.dll | CC888 | CC8AC | 11° modulo nella iat |
winspool.drv | CC820 | CC82C | 9° modulo nella iat |
advapi32.dll | CC000 | CC038 | 1° modulo nella iat |
shell32.dll | CC464 | CC488 | 6° modulo nella iat |
comctl32.dll | CC03C | CC055 | 2° modulo nella iat |
per i moduli wsock32 e comctl32 potreste avere qualche problema: troverete dei puntatori del tipo 8000xxxx, e questi a che puntano? A nulla! L'OriginalFirstThunk è un puntatore a 31 BIT che punta all'indirizzo della funzione importata, però se il 32° BIT è settato (come in questo caso), allora l'OriginalFirstThunk non rappresenta un puntatore al nome della funzione, ma rappresenta l'indice della funzione esportata dal modulo (la parte xxxx). Quindi le funzioni non vengono cercate tramite il loro nome ma tramite il loro indice. Allora come facciamo a sapere a che modulo appartengono? nel caso di comctl32 è solo il primo OriginalFirstThunk ad importare by index, quindi usate gli altri per capire di che modulo si tratta, nel caso di wsock32 tutti i puntatori sono by index: beh, per esclusione lo azzeccate lo stesso :-). Ora abbiamo delimitato i confini degli array di OriginalFirstThunk e ne abbiamo stabilito l'ordine, quindi possiamo finalmente andarci a progettare i nostri descrittori della IT:
MODULO | OriginalFirstThunk | Time/Date Stamp | Forwarder Chain | Name RVA | FirstThunk |
kernel32.dll | C0 C1 0C 00 | 00 00 00 00 | 00 00 00 00 | 08 F2 13 00 | C0 C1 0C 00 |
imm32.dll | AC C1 0C 00 | 00 00 00 00 | 00 00 00 00 | 38 F3 13 00 | AC C1 0C 00 |
wsock32.dll | 30 C8 0C 00 | 00 00 00 00 | 00 00 00 00 | 42 F3 13 00 | 30 C8 0C 00 |
ssce4332.dll | 84 C4 0C 00 | 00 00 00 00 | 00 00 00 00 | 4E F3 13 00 | 84 C4 0C 00 |
user32.dll | E4 C4 0C 00 | 00 00 00 00 | 00 00 00 00 | 5B F3 13 00 | E4 C4 0C 00 |
gdi32.dll | 60 C0 0C 00 | 00 00 00 00 | 00 00 00 00 | 66 F3 13 00 | 60 C0 0C 00 |
comdlg32.dll | 88 C8 0C 00 | 00 00 00 00 | 00 00 00 00 | 70 F3 13 00 | 88 C8 0C 00 |
winspool.drv | 20 C8 0C 00 | 00 00 00 00 | 00 00 00 00 | 7D F3 13 00 | 20 C8 0C 00 |
advapi32.dll | 00 C0 0C 00 | 00 00 00 00 | 00 00 00 00 | 8A F3 13 00 | 00 C0 0C 00 |
shell32.dll | 64 C4 0C 00 | 00 00 00 00 | 00 00 00 00 | 97 F3 13 00 | 64 C4 0C 00 |
comctl32.dll | 3C C0 0C 00 | 00 00 00 00 | 00 00 00 00 | A3 F3 13 00 | 3C C0 0C 00 |
stiamo riusando la IT del loader all'offset 13F248. Il campo NameRVA è già a posto, il time/date stamp e il forwarder chain va azzerato, per gli OriginalFirstThunk dobbiamo metterci i valori trovati nella tabella precedente. Noterete che i FirsThunk li abbiamo fatti coincidere con gli OriginalFirstThunk. Normalmente sono 2 array distinti, ed è meglio che lo siano, ma qui ho usato lo stesso array tanto per non stare a fare taglio & cucito ancora. In questo modo il PeLoader del winskif legge dall'array gli OriginalFirstThunk e poi lo sovrascrive con i FirstThunk. Ora possiamo avviare il programma e... funziona di nuovo! E stavolta funziona su tutti i PC. Ora ci rimane solo la parte di cracking vera e propria: eliminare il time limit! Confesso che la cosa è alquanto stramba... il programma chiede un seriale per essere registrato, ho provato a seguire i calcoli sul seriale, ho provato a breakare sul registry.... niente. Ho guardato che file controlla, e a parte qualche file temporaneo ho notato l'apertura del relativo file .reg che contiene il seriale, ma anche qui seguendo la lettura del file etc non ho trovato nulla di strano, ed infine la mia attenzione è caduta sul file c:\windows\uedit32.cfg. Sono andato ad esaminare questo file e non c'è niente di anormale. A proposito, c'è anche qualche file .ini che viene letto, in particolare l'uedit32.ini che contiene la voce
Days to Expire = xx
dove xx rappresenta i giorni rimanenti. Inutile dire che non basta cambiare questo valore per eliminare il time limit! Vabbè, torniamo all'uedit32.cfg: editatelo con un editor esadecimale (magari proprio con uedit!) e vediamo che ci sono una serie di byte apparentemente senza senso. I primi quattro byte rappresentano una sorta di signature, poi c'è la stringa "v8.00". Ora se breakate con CreateFileA e monitorizzare la lettura da questo file, troveremo molti calcoli proprio con la stringa in questione. Allorchè ho provato a cambiare la stringa in "v6.00", avvio il programma e... non scade più! Provate a scrivere anche altri numeri e non scade più! Per iniziare l'eliminazione del timelimit avevo portato avanti la data in modo da far scadere i 45 giorni, e quindi il prog non si avviava, ora invece si avvia sempre e qualunque sia la data mi dà sempre 45 giorni rimanenti! Mah... Quindi possiamo utilizzare il programma all'infinito. Volendo potreste eliminare anche la nag iniziale, provate ad usare CreateWindow e ShowWindow, o anche SetTimer.
Ciauz
AndreaGeddon
Note finali |
Saluto tutti gli amici della UIC, saluto Neural Noise che è una mano santa! Saluto anche il mitico Killo e anche LittleJohn che è sceso anche lui tra noi i crack-it! Anche Acid_Leo che mi ha scritto il tute sul LeimCrypt :-) Infine il Que non può mancare!!! Anche gli amici di AuroraOS ;-) Byeee
Disclaimer |
Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.
Capitoooooooo????? Bhè credo di si ;))))