PE-Packers/Crypters : Manual unpacking - parte 2
PREMESSA
LE INFORMAZIONI CHE TROVATE ALL'INTERNO DI QUESTO FILE SONO PER PURO SCOPO DIDATTICO.
L'AUTORE NON INCORAGGIA CHI VOLESSE UTILIZZARLE PER SCOPI ILLEGALI.
DIFFICOLTA'
scala : *=Novizio, **=Apprendista, ***=Esperto, ****=Guru
target: ***
TOOLS USATI
* SoftIce 3.25
* PROCDUMP 1.5
* ULTRAEDIT 6.10
* MASM 6.14
LETTERATURA
"Peering Inside the PE: A Tour of the Win32 Portable Executable File Format" (M. Pietrek), Microsoft Systems Journal 3/1994
"The Portable Executable File Format from Top to Bottom" (Randy Kath), MSDN
"The PE file format" (B. Luevelsmeyer), reperibile sulla rete
"Windows 95 Programming Secrets" (M. Pietrek), IDG BOOKS, 1995
"Window Advanced Programming" (J. Ritcher), Microsoft Press, 1997
"Win32 Exception handling for assembler programmers" (Jeremy Gordon), 1998, reperibile sulla rete
"Intel Architecture Software Developer’s Manual Volume 3: System Programming Guide",1997, reperibile sulla rete
INTRODUZIONE
yeah sono in vacanzaaa ;))
Prima di iniziare voglio pero' essere esplicito con voi: non ho nessuna intenzione di replicare il manuale di Procdump per cui mi limitero' a descrivere i comandi e le opzioni piu' importanti e tralasciero' cose come descrivere il process monitor, o il significato di ciascun campo / listview / dialog... credo che se state leggendo questo tutorial siate gia' piu' che autosufficienti per queste cose ;)
PROCDUMP INTERNALS
Procdump puo' essere scomposto in vari moduli / modalita' operative: process monitor, dumper, pe editor, pe rebuilder, unpacker, bhrama server. Come vi ho gia' anticipato analizzeremo solamente l'unpacker e il bhrama server, questo xche' ritengo che ormai sappiate come utilizzare il dumper, l'editor, il process monitor, ecc. Quello che mi preme piuttosto e' chiarire il contesto in cui vanno utilizzate le varie opzioni di unpacking e soprattutto, il xche' di si debba utilizzare l'una invece dell'altra, ragionando anche sull'implementatazione stessa di ProcDump. Innanzitutto va detto che Procdump opera x il 90% del tempo a ring3 questo xche' le fondamenta su cui poggia sono , se escludiamo l'opzione del tracer a ring0, l'API di debug: sia le funzioni di dumping che l'engine principale sono realizzati servendosi della ToolHelp32/PSPAPI o di funzioni come ReadProcessMemory, SetThreadContext, WaitDebugEvent,ecc.. Le implicazioni di questo modo di operare sono molto importanti visto che ,come vedremo, determinano i limiti stessi di Procdump.
Ma procediamo con ordine e analizziamo la modalita' piu' importante, l'unpacker: in questa modalita' Procdump opera come un vero e proprio debugger a ring3.. il processo viene creato con il flag DEBUG_PROCESS.. quindi viene attivato loop WaitForDebugEvent ContinueDebugEvent.. questo permette di trappare tutte le exception che il processo child genera prima che vengano gestite da eventuali filtri di eccezione / terminazione locali. Immagino che quelli piu' attenti fra di voi abbiano gia' collegato quest'ultima affermazione con l'opzione Ignore Faults: esatto .. se si verifica un'eccezzione in un processo sottoposto a debug, la prima azione che Windows compie e' notificare il debugger segnalando un debug event... e' responsabilita' del debugger decidere se gestire quest'eccezzione, nota come first chance, o restituire immediatamente il controllo all'applicazione. Se "Ignore Faults" e' ON, Procdump trappa solo le eccezzioni di tipo EXCEPTION_BREAKPOINT (Int03) che sono state generate in seguito ai comandi bp* dello script attivo. Questo avviene verificando se l'EIP dell'eccezzione corrisponde all'indirizzo del breakpoint attivo. Ma quando e' necessario attivare quest'opzione ? semplice quando il loader utilizza meccanismi come la SEH per traferire il controllo all'interno del codice,o per verificare la presenza di sIce (exp. classico l'interfaccia int03 "BHCK") o in generale di debuggers / tracers. Se non lasciassimo al programma la possibilita' di gestire queste situazioni attraverso i suoi exception filters locali quest'ultimo con ogni probabilita' andrebbe incontro a morte prematura dato che Procdump non saprebbe certo come gestirli.
Un'altra importante conseguenza di utilizzare la debug API x l'unpacker engine e' che Procdump necessita di un cosidetto "predump" per poter ricostruire la IT...mi spiego meglio : in Windows 9x, quando ad un processo e' attaccato un debugger, se utilizziamo GetProcAddress per ritrovare l'entry point di una funzione da una DLL shared di sistema, al posto di ottenere l'indirizzo effettivo otteniamo invece quello di uno stub creato da WinZoz in un'area shared (>0x80000000). La ragione di questo assurdo comportamento dipende dal fatto che alla M$ hanno pensato bene che essendo kernel32,user32,ecc. condivisi x tutti processi non era carino che un debugger a r3 potesse steppare nel codice o cmq pokicchiarci (che bel termine vero? ;). Dato che il 99% dei packers/cryters utilizza GetProcAddress quando risolve le imports e' chiaro che se l'IT rebuiler utilizza la IAT durante l'unpacking senza opportuni accorgimenti non sara' in grado di ricostuire una IT valida (sull'engine Phoenix ne parleramo piu' in dettaglio tra un po'). Il predump puo' poi essere statico (= "external predump") o dinamico ("predump after X"):
- per statico si intende che dobbiamo fornire al rebilder un dump che contenga una IAT corretta, anche se gia' fixata, in modo che questo possa attraversare i vari image_thunk_data e ricostruire gli array first_thunk... sostanzialmente e' lo stesso modo di operare di makePE.
- per dinamico invece significa che procdump lancera' il programmma in modalita' non debug e attendera' X msec prima di sospendere il thread principale ed eseguire lo scan della IAT: X ovviamente deve essere tarato in modo che nel momento in cui si sospende il thread la IT o la IAT siano 1) raggiungibili 2) non trashate.. nel caso X == 0 Procdump attendera' che siamo noi a confermare l'inizio del rebuild. Il maggior problema di questa implementazione e' che durante la fase di predump non e' possibile utilizzare gli scripts e quindi neutralizzare quei packers/ crypters che contengano codice anti-rebuild (inserimento di stubs,ecc.), la qual cosa, come vedremo nel caso clinico che vi sottoporro' ;) [petite 2.1] , si rivela molto limitativa. Le opzioni "EIP confirmation" e "Multiple layer confirmation" servono invece ad offrire un'ulterirore occasione x decidere, una volta entrati in STEP mode, quale EIP utilizzare come EP ,ma IMHO sono ormai obsoleti considerato che ora il linguaggio script disponde dei comandi OBJ e EIP. Ultima opzione che si presenta nel group box dedicato all'unpacker e' "Trace API" : se selezionamo quest'opzione Procdump utilizzera' la versione a Ring0 del tracer (VXDBODY.VXD x w9x e VXDBODY.KMD x NT), tracer che nelle intenzioni dovrebbe consentire di neutralizzare i metodi ADT piu' classici (EFLAGS->TF, int1 / int3 traps, ecc.). Ho utilizzato il condizionale non a caso: il fatto e' che in realta' il codice non e' esattamente stabile e/o completo, il che purtroppo ne rende l'impiego sostanzialmente inutile (senza contare che i crash sono praticamente garantiti).
[ nota a margine : Procdump maschera la sua presenza quale debugger attraverso l'azzeramento del campo DebugContext nel TIB (Thread Information Block), il classico FS:[20h] per farla breve. Benche' questo sistema funzioni per la maggior parte dei crypters classici,non e' che un pagliativo... purtroppo e' la natura stessa di Procdump quale debugger a r3 ad esporlo pesantemente ai detectors (FindWindow,IsDebuggerPresent, pushfd pop eax test ah,01, parent PDB check,ecc.) quindi tenenete conto x evitare sorprese.]
Passiamo ora alle opzioni del rebuiler: le opzioni "Recompute ObjectSize" e "Optimize PE structure" mi paiono chiare e sono del resto spiegate esaurientemente nel "manuale"... qualke parolina in piu' merita "Check Header Sections": attivando questa opzione Procdump verifica che le pagine presenti nel range occupato dall'immagine (cosi' come riportato nella section table) siano tutte presenti e leggibili.. immagino vi starete chiedendo: "xche' mai non dovrebbero esserlo?" dunque quest'opzione e'nata per contrastare quei crypter (mi risulta lo faccesse solo la prima ver del crypter dei PC e PEShield.. but who know..) che giocando sul fatto che ProcDump utilizza ReadProcessMemory, modificavano il PE alterando SizeOfImage o la VSize delle sections in modo che fosse maggiore o minore dello spazio fisicamente okkupato, cosa che si traduceva in una lettura errata di ReadProcessMemory nel caso in cui di quelle pagine non fosse ancora stato fatto il commit o non fossero proprio allocate. Dato che questo trick non e' decisamente gradito a WinNT :) per via del differente funzionamento del VMM (vi ricordate ne abbiamo gia' parlato...), e' difficile che dobbiate incontrare ancora appz che ne fanno uso.
L'opzione "Rebuild header" e' stata introdotta solo di recente: lo scopo e' di forzare Procdump a ripristinare i campi vitali del PE header che potrebbero essere stati cancellati (NumberOfSection,SizeOfHeaders,ecc) invece di limitarsi ad un dump passivo dell'header.. ovviamente quest'operazione si basa su criteri euristici, assumendo valori come standard in ogni PE, analizzando la section table e la DataDirectory (in verita' non ho ancora analizzato bene il codice relativo, ma cmq non ho trovato chiamate a VirtualQueryEx che potrebbero far pensare ad un'analisi dell'address space nel tentativo di ricostuire il layout dell'image...) x cui non e' affatto scontato che l'header cosi' ricostruito sia effettivamente corretto... controllatelo cmq.
Ok, veniamo adesso alla parte piu' importante: l'IT rebuilder (Phoenix). Il significato delle prime due opzioni mi pare auto-eplicativo.. passiamo oltre : come gia' saprete i packers/crypters piu' recenti ridirigono DataDir->IT_RVA xche' punti alla propria mini-IT in modo da importare staticamente le funzioni di cui necessitano e gestendo poi, con un proprio imports loader, la IT table originaria.. sappiamo anche che si possono verificare due ipotesi:
1) la IT (intesa come comprensiva di image_imports_descriptors,ecc.) dopo l'unpack e' ancora presente in memoria anche se non "raggiungibile" attraverso il PEHeader
2) la IT originale e'compattata in una struttura gestita internamene dal crypter o cmq copiata in un buffer separato e distrutta una volta fixata la IAT
in entrambi i casi pero' una cosa e' sicura (almeno fin'ora ;) la IAT non e' stata rilocata e si trova nella posizione originale.. questo xche', in caso contrario, sarebbe necessario rilocare tutte le chiamate alle func importate presenti nel codice dell'appz. Ancora, cosa ci impedisce di utilizzare la IT del caso 1) ? semplice i vari FirstThunk sono stati fixati e non contengono piu' gli rva x gli image_import_by_name e/o ordinals. Bene l'opzione "Rebuild import table" cerca di porre rimedio al caso 1).. come? semplice Procdump tenta euristicamente di trovare la IAT scannando il codice alla ricerca di un jump [dword] (opcode FF25) ,quindi legge dword.. se questa contiene un address valido x uno di moduli caricati (usa ToolHelp32/PSAPI) lo confronta in successione con quelli restituiti da GetProcAddress x ogni funzione di ogni modulo... se corrisponde sa di aver trovato un array FirstThunk.. quindi percorre i vari thunks a ritroso compiendo le stesse operazioni e costruendo una mappa interna FirsThunk_rva:Modulo:API che poi utilizza x ricostuire gli elementi di ogni FirsThunk->image_thunk_data.. Procdump provvedera' anche ad aggiornare la DataDirectory... semplice no? =)
[ nota a margine: l'uso di GetProcAddress e' stato introdotto nella v. 1.5 (prima era utilizzato uno scan Modulo->ET->AddressOfFunctions) ed e' simile a quello utilizzato da Virogen / PC e Titti / Blizzard nel loro PERebuilder.. date un'occhiata ai sorgenti di questo.. e' una buona lettura.. ( btw io avrei suggerito un'altro sistema con VirtualQueryEx.. se avete visto i miei srcs di PESpy sapete cosa voglio dire) ]
ovviamente il rebuild puo' funzionare solo se gli image_import_descriptors non sono stati trashati. Nel caso in cui non sia cosi', come nel 2), abbiamo la possibilita' di specificare un "Full Import rebuild".. ovvero ProcDump utilizzera' lo stesso procedimento ma questa volta ricreara' anche gli image_import_descriptors,ecc. in una IT nuova che sara' aggiunta in fondo all'exe dumpato.
Uhmm.. se siete arrivati a leggere fino qui' (lo so' avete pazienza da vendere ;) vi starete sicuramente chiedendo a che pro questa lunga parentesi tecnofila su come e' implementato Procdump... dunque... nel 90% dei casi a nulla =) visto che potete anche limitarvi ad utilizzare script / plugin che altri hanno scritto.. tuttavia nell'altro 10% dei casi potreste incontrare un crypter non ancora supportato da Procdump , che, nemmeno a farlo apposta, contiene codice anti-trace/dump.. beh in questo 10% credo vi torni utile conoscere come funziona Procdump e quali punti deboli possono esser stati sfruttati.
PROCDUMP : SCRIPTS
Gli script sono senz'altro una delle caratteristiche piu' importanti di Procdump. Senza di essi Procdump non potrebbe gestire l'unpacking automatico x tutta la moltitudine di packers/crypters che supporta. Ma qual'e' lo scopo degli script e sopratutto il loro funzionamento? lo scopo e' semplice: guidare Procudump attraverso il codice del loader fino a fargli raggiungere indenne l'OEP.. cio' significa' gestire secondo necessita' eventuale codice anti-trace/dump, encryption, layers, e quant'altro possa impedire a Procdump di fare il suo sporco lavoro =)
Il funzionamento com'e' ormai assodato si basa sulla DebugApi.. e piu' precisamente sull'uso di R/W*ProcessMemory e sopratutto Set/GetThreadContext. In pratica ogni istruzione BPxx si traduce in un int3 (questo spiega l'avvertenza di settare I3HERE = OFF in sICE) inserito nel codice del appz... questo che genera un'eccezzione, che viene trappata dal loop WaitDebugEvent che decodifica la prossima istruzione dello script, la quale a sua volta puo' tradursi in un'alterazione del codice o del context del thread (MOVE,REPL) oppure nell'impostazione di un'altro breakpoint.. cosi' finche' non si entra in STEP mode, al che' si passa definitivamente il controllo al tracer e da questo al dumper. Per esaminare le potenzialita' (e i limiti) ho deciso di utilizzare come target il classico notepad.exe compresso con Petite 2.1.
Iniziamo coll'esaminare il codice del loader di Petite 2.1 nelle sue parti essenziali (i dead listings completi li trovate in allegato):
B800C04000 MOV EAX,0040C000 ; hardcoded entrypoint EIP
6A00 PUSH 00
6812624000 PUSH 00406212 ; use SEH to transfer control
64FF3500000000 PUSH DWORD PTR FS:[00000000] ; to the next layer (2)
64892500000000 MOV FS:[00000000],ESP
vi ricordate che tutorial precedente vi dicevo che l'installazione di un exception frame e' da considerarsi sospetta.. eccone un riprova... petite 2.1 utilizza proprio la SEH per trasferire il controllo al layer successivo una volta che tutta l'immagine e' stata decompressa. La cosa avviene piu' o meno in questo modo: Petite decomprime l'immagine per blocco / sezioni successivi, compresi il blocco con i layer successivi.. quindi esegue un'ulteriore invocazione della funzione di unpacking ma con parametri nulli in modo da generare una violazione di accesso... quando questa si verifica l'esecuzione e' trasferita da WinZoz all'exception handler, EIP = 0x00406212 in questo caso, dove al momento dell'eccezzione si trova la seguente call:
E84F000000 CALL 00406266 ; xHandler gateway
che a sua volta trasferisce il controllo al terzo layer quello in cui vengono gestite imports, base relocations, TLS, ecc. ok ora se volessimo scrivere la prima parte dello script ci troveremmo di fronte ad alcuni piccoli problemi:
1) l'address 00406212 non e' caricato in alcun registro e il linguaggio script di Procdump non offre la possibilita di leggere un address dal codice/stack
2) l'address dell'handler e' dipendente dal target quindi BPX non e' utilizzabile
3) il codice a quell'indirizzo non e' in chiaro sin dal caricamento ma viene decompresso dal primo layer, quindi se mettiamo un BP prima che cio' avvenga questo sara' sovrascritto..
problemi insormontabili? naaa.. ci vuole solo quel po' di malizia nel pensare che, se anche il codice non prevede una determina azione, possiamo sempre pensarci noi ;) inserendo il codice seguente possimo caricare in eax l'address del primo handler nella exception chain:
mov eax,fs:[00]
mov eax,[eax+4]
tradotto in script:
; cerchiamo il pattern corrispondente al codice da sovrascrivere, ovvero:
; 85C0 TEST EAX,EAX
; 0F8420FFFFFF JZ 0040C0CE
L1=LOOK 85,C0,0F,84,20,FF,FF,FF
; rimpiazziamolo con il nostro
L2=REPL 67,64,A1,00,00,8B,40,04
; e quindi mettimo un breakpoint dopo 3 esecuzioni di fnDecrypt
; ovvero quando in genere viene decompressa la "call xHandler"
L3=ADD 8
L4=BPC 3
; ed infine un BP all'address contenuto in EAX = xHandler
L5=BPR EAX
et voila'.. a questo punto siamo in grado far raggiungere a Procdump il layer2...
bastera' quindi :
L6=WALK
e ci troveremo all'inizio del layer3... good! Ora quello che ci preme e' impedire che il loader nel risolvere le imports crei i suoi stubs: osservando il codice ci rendiamo subito conto che il modo migliore e' patchare questo snippet:
FF4C2428 DEC DWORD PTR [ESP+28] ; stub randomizer
7D25 JGE 00406467
8B542424 MOV EDX,[ESP+24]
L7=OBJR
L8=LOOK 7D,25,8B
L9=REPL EB
perfetto ora il codice dovrebbe sempre saltare la creazione degli stubs. Se osservate i dead listings noterete come Petite 2.1 si premuri anche di cancellare i nomi delle funzioni importate (quelli dei moduli sono gia' stati rimossi e copiati in una table separata dal packer) e i fields FirstThunk x ogni image_import_descritor.. e' evidente che i programmatori hanno voluto cautelarsi contro Procdump e il suo import rebuilder. Poco sotto il codice che gestisce le imports c'e' quello x l'handling della base relocation.. tutto assolutamente familiare se avete letto i precedenti tutorial =) , va solo notato che anche qui troviamo un semplice stratagemma x complicare il rebuild: ogni record della relocation directory e' wipato dopo l'uso.
So fa so good... ora quello che ci interessa e' raggiungere il quarto layer: anche qui pero' abbiamo lo stesso problema del secondo layer2.. il codice presente nel layer4 e' decrittato dal seguente codice:
3119 XOR [ECX],EBX ; use crc as decryption key
315904 XOR [ECX+04],EBX ; for the 4th layer's code
315908 XOR [ECX+08],EBX
31590C XOR [ECX+0C],EBX
59 POP ECX
315C1101 XOR [EDX+ECX+01],EBX ; and "goto layer4" call
vabbeh poko male.. il nostro breakpoint precedente ci assicura che il codice sia gia' decrittato nel momento in cui Procdump esegue la line L9.. possiamo allora semplicemente impostare un'altro BP e precisamente su questo snippet:
33C0 XOR EAX,EAX
B960030000 MOV ECX,00000360 ; sizeof loader layers (2-3)
LA=LOOK FD,33,C0,B9
LB=ADD 8
LC=BP
e quindi eseguire la call che ci porta al layer4:
E8915B0000 CALL 0040C102
LD=WALK
ora non resta che ottenere l'OEP e passare il controllo al tracer... che ragionando sul codice di petite:
61 POPAD
669D POPF ; restore register & flags
83C40C ADD ESP,0C ; stack cleanup
E9F04EFFFF JMP 00401000 ; jmp to OEP
ci porta a scrivere le seguenti linee dello script:
LE=OBJR
LF=LOOK 83,C4,0C,E9
L10=ADD 3
L11=BP
L12=WALK ; esegui jmp EOP
L13=EIP ; assumi l'EIP corrente (dopo il jmp)
L14=STEP ; come entry point x il dump
non ci resta che impostare le options,aggiungerlo nel file script.ini e il nostro primo script puo' dirsi completo:
Recompute object size = ON
Optimize PE structure = ON
Full Import rebuild = ON
Predump After = ON = 0ms
Ignore Faults = ON
tutto assolutamente lineare non vi sembra ? =) immagino starete esclamando "yeah, il mio primo script.. proviamolo subito..."... ok! lanciamo Procdump... target il nostro notepad.exe, click su UNPACK, selezioniamo il nostro script, confermiamo il predump... lo script si esegue perfettamente... good... ci appare la dialog di save.. very good... salviamo ed esaminiamo velocemente il file nel PE editor: EP = 1000, ecc...ottimo.. lo lanciamo baldanzosi e...... si pianta!! "o kill3xx chettufai?" tranquilli =) era preventivato. Siete stati cosi' fortunati che il vostro primo script, apparentemente perfetto,e' anche un esempio dei limiti di Procdump... che culo vero? ;). La ragione e' semplice e gia'la conoscete: Procdump ricostruisce la IT in fase di predump ma come sappiamo in fase di predump gli script non sono attivi, ne consegue che, se anche il nostro script preveda la neutralizzazione degli stubs, in realta' questo avviene quando oramai Procdump ha gia' ricostruito internamente la IT. Soluzioni ? nessuna, o meglio, nessuna che utilizzi gli script. Potremmo usare sIce durante il predump e fixare a mano il "jg" nel codice del loader ma non mi pare una soluzione elegante. =)
PROCDUMP : BHRAMA SERVER
Dalla versione .1.4, data la sempre maggiore ostilita' verso Procdump dei crypters e packers, e visti i limiti degli script, Procdump mette a disposizione un nuovo modo di operare il Bhrama Server e i plugin/client. Un plugin altro non e' che un loader in cui gestiamo con nostro codice quello che in Procdump avremmo realizzato con uno script, ovvero:
1) eliminare eventuali tricks anti-dump (i.e x petite2.1 gli stubs)
2) attendere che il codice si totalmente decrittato
3) raggiungere l'OEP e comunicarlo a Prodump in modo che lo utilizzi come EP x il rebuild.
Una volta che abbiamo raggiunto l'OEP possiamo sospendere il main thread del programma target e comunicare con Procdump attraverso il Bhrama server: questo e' un Dialog che funge da server esponendo un protocollo di IPC ben definito e basato su WM_COPYDATA. I servizi che ci mette a disposizione il Bhrama server sono gli stessi che potremmo utilizzare dal Process Monitor di Procdump.. ovvero FULL e PARTIAL DUMP. Le strutture utilizzate x i vari service sono ben ducumentate nel file Bhrama.txt e nella directory omonima trovate anche due esempi (w32asm e c) dello skeletro di un plugin. Detto questo passo ad illustrarvi l'idea alla base del plugin x Petite 2.1 che ho realizzato. L'obiettivo e' ovvio: neutralizzare gli stubs: il sistema un po meno visto che l'esecuzione del loader e' multilayer e il passaggio fra questi avviene attraverso la SEH. Qualcuno potrebbe essere tentato di usare la DebugAPI visto che le exception vengono notificate prima al debugger che all'appz.. ma in tal caso ci ritroveremmo con il probelma degli stubs che crea WinZoz. L'intuizione che ho avuto e' la seguente: se sostituiamo l'indirizzo dell'exception handler originale con un nostro handler, il cui codice e' stato iniettato nell'address space del processo, saremmo noi ad avere il controllo quando si verifichera' l'eccezzione, e di consegueza avremmo accesso ai layer2 e al layer3.. da questo punto in poi possiamo utilizzare un mini tracer attraverso l'installazione di un final exception handler (che vi ricordo e' process wide.. SetUnhandledExceptionFilter) e sfuttando l'accesso al CONTEXT del thread settare i seguenti bp:
- int3 x raggiungere il layer3
- HW bp sul "jg" dello stub randomizer
- HW bp sulla "call _layer4"
- EFlags.TF in modo eseguire la call _layer4 (equivalente al WALK di Procdump)
gli HW breakpoint sono realizzati utilizzando la copia locale dei debug registers che viene mantenuta x ogni Thread Context.
Quando i BP genereranno altrettante exception, queste, non essendo gestite da Petite, dovranno necessariamente essere notificate al nostro handler e noi , in tal modo, avremmo il totale controllo sull'esecuzione/codice del loader di Petite. Ancora: quando ci troveremo nel layer4 calcoleremo l'EIP dell'OEP e lo notificheremo alla nostra IPC server window che provvedera' a sospendere il main thread del programma e ad invocare il service FULL DUMP del Bhrama server. Per quel che riguarda l'iniezione del codice ho optato x modificare il codice dell'EP del target inserendovi uno stub x mappare un memory mapped. Questo MMF contiene tutto il codice da iniettare, compreso quello che si occupa ripristinare il codice originale e riprende l'esecuzione di questo. Non mi dilungo oltre a commentare ogni singola linea xche' ci vorrebbe troppo spazio e questo tute e' gia lungo di per se'... voglio pero' sottolinere come la combinazione di exceptions e manipolazione del context (specialmente EIP, ESP, Dr0..3, Dr7) sia davvero uno strumento flessibile e potente (eheh probabilmente oltre la stessa volonta' dell M$ ;): la potete utilizzare x andare a r0 (in w9x),x anti-debug,x un tracer, SMC code,ecc.. Il resto del codice (che troverete in allegato) riguarda il setup del MMF e codice di contorno che credo sia autoesplicativo.
NOTE FINALI
Bene siamo finalmente giunti alla fine: spero che questi tutorial sul PE abbiano contribuito a farvi interessare a questa intrigante materia. Vi annuncio fin'ora che non credo che ne scrivero' ancora, almeno finche' non ci sara' qualkosa di nuovo sotto il sole. Prima di congedarmi pero' i soliti saluti di rito =) :
Along3x,Alor,Deamon (dove minkia sei finito ??? =),Genius,GuyBrush,Little-John,Insanity, Kry0,+Malattia,Neural_Noise,MoonShadow,Pe-WoW,Pusillus,T3X,Quequero,xAONINO,Yan-orel, War-lock e a tutti quelli che frequentano #crack-it e chi mi sono dimenticato.. tnx *.* =)