UltraEdit32
AsPack? UnAssPack!

Data

by "AndreaGeddon"

 

17/04/2001

UIC's Home Page

Published by Quequero


Non è morto ciò che può vivere in eterno...

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.

....

Home page: http://www.andreageddon.com
E-mail: [email protected]
irc.azzurra.it   #crack-it
 

....

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.


UltraEdit32
AsPack? UnAssPack!
Written by AndreaGeddon

Introduzione

AsPack, il fratellino più piccolo di AsProtect (o viceversa? boh). Beh comunque ho AZPR packato con AsProtect, appena lo faccio mi levo il dubbio :-) (AsProtect è decisamente il fratellone :P NdQue)

Tools usati

SoftIce
IceDump
WDasm
un HexEditor
PEditor

URL o FTP del programma

www.ultraedit.com

Notizie sul programma

E' un bellissimo Editor Esadecimale, ha tantissime funzioni, quasi mi dispiace doverlo reversare, ma il time limit è proprio noioso...(SPARONEEEEEEEEEEE NdQue)

Essay

Lanciamo il programma e abbiamo una orrenda nag screen che ci ricora gentilmente che abbiamo 45 giorni a disposizione per registrare il programma. Bene, un banale time limit! Disassembliamo il programma e qualcosa non va... diamo uno sguardo alle sezoni del programma:
 
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 ;))))