|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Hookare ntdll.dll
qualcuno ha mai provato a "spiare" le funzioni NtCreateFile() e NtOpenFile() ?
intendo dire scrivendo , nei primi byte di tali funzioni , un salto in una funzione di hook che intercetti tutte le chiamate alle funzioni originali |
![]() |
![]() |
![]() |
#2 |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
nessuno?
|
![]() |
![]() |
![]() |
#3 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
In pratica quello che fanno gli antivirus ? Ho cercato tanto tempo, ma non sono mai riuscito a trovare niente se non un documento MS con un sorgente fatto in assembly...
|
![]() |
![]() |
![]() |
#4 | |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Quote:
io dicevo di fare l'hooking in modo utente,come fanno i RootKit modo utente per nascondere i file che usano,i loro processi e backdoor |
|
![]() |
![]() |
![]() |
#5 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
come vuoi che si faccia scusa, si fa come tutte le altre funzioni... non ho mai provato con NtXxx ma l'ho fatto spesso con molte altre; per le NtXxx è la stessa cosa, anche se sarebbe preferibile scrivere un driver e hookare direttamente la int 2E (se se ne ha la possibilità ovviamente).
|
![]() |
![]() |
![]() |
#6 | |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Quote:
nella funzione hook prima o poi bisogna chiamare la funzione originale,e quindi bisogna prima scrivere i byte originali dove c'è il salto,poi chiamare la funzione,e poi riscrivere il salto ora,supponiamo che il processo abbia più di un thread,e che uno dei thread stia per chiamare una funzione hookata ma viene bloccato dal OS e ne viene schedulato un'altro...quello che è in esecuzione adesso viene eseguito per un po',poi facciamo conto che cominci a scrivere bytes nella funzione da hookare (i soliti byte di salto),e che venga sospeso a metà scrittura...ecco,quando il thread che prima è stato bloccato viene risvegliato,esso eseguirà spazzatura e il processo terminerà,o comunque non farà quello che dovrebbe bisognerebbe sincronizzare l'accesso alla funzione da hookare,non mi sembra un problema banale... ma io non parlo del mio processo,quello chi se ne frega,basterebbe che io usi una sezione critica per chiamare la funzione da hookare,così i miei thread saranno sincronizzati...il problema sono i processi remoti a cui io inietto del codice per spiarlo... insomma la stessa cosa che fanno i RootKit modo utente o altro software malware,sempre modo utente...come fanno a risolvere questo problema?? |
|
![]() |
![]() |
![]() |
#7 | |
Senior Member
Iscritto dal: May 2003
Città: Trieste, Pordenone
Messaggi: 920
|
Quote:
Se vuoi invece metterti a studiare le API native di Windows, allora ti consiglio di cercare gli articoli di Matt Pietrek su MSDN. Una volta teneva una rubrica chiamata "under the hood" che era molto interessante, comunque qualcosa si può già accennare anche qui. In pratica le funzioni di tipo NtBlablabla() e ZwBlblabla() ecc... di ntdll.dll sono le cosiddette Api native di windows (spesso poco o per niente documentate) e servono da wrapper verso le syscall del sistema operativo. Se prendi ntdll.dll e la dai in pasto ad un disassemblatore tipo IDAPro, ti leggerai una sfilza di codice del tipo: Codice:
arg_0 = byte ptr 4 mov eax, 4Ch ; NtOpenDirectoryObject lea edx, [esp+arg_0] int 2Eh retn 0Ch _NtOpenDirectoryObject@12 endp _NtOpenEvent@12 proc near arg_0 = byte ptr 4 mov eax, 4Dh ; NtOpenEvent lea edx, [esp+arg_0] int 2Eh retn 0Ch _NtOpenEvent@12 endp ... In pratica, l'interrupt 2Eh fa' da wrapper tra le routine a ring0 e quelle a ring3. Scommetto che vi ricorda qualcosa... ![]() In Windows NT, però non l'interrupt 2Eh non è l'unico interrupt fornito dal kernel: Codice:
002A IntG32 0008:8013E756 DPL=3 P _KiGetTickCount 002B IntG32 0008:8013E840 DPL=3 P _KiCallbackReturn 002C IntG32 0008:8013E950 DPL=3 P _KiSetLowWaitHighThread 002D IntG32 0008:8013F50C DPL=3 P _KiDebugService 002E IntG32 0008:8013E2D0 DPL=3 P _KiSystemService 002F IntG32 0008:801416F8 DPL=0 P _KiTrap0F ![]() In pratica, le funzioni di ntdll.dll chiamano semplicemente _KiSystemService con diversi valori di eax in base alla sottofunzione (di _KiSystemService) da chiamare. Il DPL indica il livello di privilegio richiesto per poter chiamare quella determinata routine, se è =3 la possiamo chiamare, se è =0 la può utilizzare solo il kernel. ...(in realtà qui ci sarebbero un mare di cose da dire, diciamo che ho semplificato con la mannaia).... Per ravanare più a fondo bisogna scriversi un driver... Si inizia con NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath ) { .... ...e poi si va avanti... ![]()
__________________
buy here |
|
![]() |
![]() |
![]() |
#8 | |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Quote:
ok,quindi la mia funzione hook , quando deve chiamare la funzione originale , invece di chiamarla deve fare semplicemente l'interrupt 0x2E con un certo valore in EAX,tutto qua?? e questo è come aver chiamato la funzione originale? se è così è perfetto,quindi NtCreateFile() potrei hookarla così,ad esempio Codice:
NTSTATUS NtCreateFileHook(...){ NTSTATUS iReturn; //... esamina i parametri,etc. _asm { // PUSHa i parametri sullo stack MOV EAX,0x17 INT 0x2E MOV iReturn,EAX }; return iReturn; } |
|
![]() |
![]() |
![]() |
#9 | |
Senior Member
Iscritto dal: May 2003
Città: Trieste, Pordenone
Messaggi: 920
|
Quote:
![]() http://www.sysinternals.com/Utilities/Filemon.html Ci sono diversi articoli in coda. ![]()
__________________
buy here |
|
![]() |
![]() |
![]() |
#10 | |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Quote:
comunque per capire cosa devo fare devo imparare a scrivere un driver?? se è così tanto vale che faccio un filter driver ![]() oppure potrei fare un'altra cosa: carico una nuova dll che è identica a ntdll,ma cambia il nome del file,e chiamo NtCreateFile() di quella nuova dll...può funzionare? |
|
![]() |
![]() |
![]() |
#11 |
Senior Member
Iscritto dal: May 2003
Città: Trieste, Pordenone
Messaggi: 920
|
Sinceramente soffro un po' di carenze di tempo libero e non riesco a farti degli esempi. Su sysinternals trovi i sorgenti di programmi simili a filemon (anche se non proprio di quello, purtroppo) e varie info.
![]() http://www.sysinternals.com/Information/NativeApi.html http://www.sysinternals.com/SourceCode.html http://www.sysinternals.com/SourceCode/VcMon.html ![]()
__________________
buy here |
![]() |
![]() |
![]() |
#12 | |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Quote:
![]() ci devono essere soluzioni + semplici cavolo...ad esempio quella della dll che ho detto non potrebbe funzionare? oppure avrei un'altra idea:inietto una dll,e in DLL_PROCESS_ATTACH e DLL_THREAD_ATTACH salvo i thread identifiers (TID) da qualche parte usando GetCurrentThreadId(),poi nelle mie funzioni hook uso SuspendThread() passandogli gli handle a tutti i thread del processo forchè quello corrente,faccio il mio lavoro e poi chiamo ResumeThread() tutto questo in una sezione critica,ovvero compreso fra le due chiamate EnterCriticalSection() e LeaveCriticalSection() che ne dici? c'è pericolo di deadlock o altri problemi? |
|
![]() |
![]() |
![]() |
#13 | |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
per sincronizzare l'accesso alla funzione da hookare avevo scritto un articolo su Usenet tempo fa in cui esponevo un sistema di mia invenzione che si basa sull'atomicità delle operazioni di trasferimento di un numero massimo di 32 bit (4 bytes). in sintesi funziona così: prima di scrivere il JMP scrivi un'istruzione RET N (che occupa 3 bytes se ben ricordo, quindi sarebbe un'operazione atomica), poi scrivi gli ultimi 2 bytes del JMP, e poi scrivi i primi 3 bytes del JMP (sono tutte operazioni atomiche); quello che accade è che semplicemente per un piccolissimo istante di tempo la funzione se chiamata semplicemente non farà nulla, ritornerà immediatamente con un valore indefinito in EAX; rarissimi i casi in cui una simile condizione provoca un crash del programma. altrimenti, soluzione decisamente migliore, implementi il sistema dei trampolines come quello delle Detours (scaricatele dal sito di Microsoft Research: sono molto istruttive ![]() Ultima modifica di 71104 : 06-10-2005 alle 22:23. |
|
![]() |
![]() |
![]() |
#14 | |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
![]() EDIT: considera anche l'ipotesi di usare la soluzione della IAT: modificare uno slot nella IAT è un'operazione atomica, quindi non causerebbe nessun problema di sincronizzazione!! ![]() |
|
![]() |
![]() |
![]() |
#15 | |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Quote:
e lui stesso l'API hooking non lo fa scrivendo sull'export directory,ma scrivendo il salto sui primi byte delle funzioni native se non ci credi prova a vedere il sorgente di ntillusion o qualche guida al file hiding e process hiding in windows nt www.syshell.org www.rootkit.com quindi direi che devo usare anch'io lo stesso metodo se voglio spiare un processo rootkit e scoprire che esso usa file nascosti poi per il fatto del thread che viene creato dopo...scusa se io catturo DLL_THREAD_ATTACH la mia dll non viene notificata che il thread è stato creato? se no a cosa serve il messaggio il metodo che dici tu non l'ho capito da come me l'hai spiegato,quando ho tempo leggerò quell'articolo ![]() |
|
![]() |
![]() |
![]() |
#16 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
che ne so io di quello che devi fare, per quello che chiedevi nel post originale la manipolazione della IAT andava benissimo
![]() e comunque non credere che sia una tecnica tanto inusitata, anzi... ![]() per quanto riguarda i thread prima avevo capito male, pensavo che volessi enumerarli e sospenderli tutti; rileggendo bene però penso che comunque fai hai sempre e comunque un piccolo momento di tempo in cui potrebbe venir creato un thread senza che te ne accorgi (o meglio, te ne accorgi dopo): che succede se un thread viene creato proprio mentre stai ciclando sulla tua lista di TID per sospenderli tutti? be', oddio a pensarci bene in effetti si può risolvere sincronizzando la risorsa su cui lavori (cioè la lista dei TID), sempre che la notifca di DLL_THREAD_ATTACH avvenga nel contesto del nuovo thread creato (e non ne sono sicuro), ma ripeto che è inutilmente complicato: penso sia più semplice risolvere il problema di sincronizzazione applicando un trampoline utilizzando la mia tecnica: in tal modo applichi il JMP in maniera atomica, quasi sicuramente indolore, e soprattutto lo fai una volta sola (al massimo due), senza bisogno di togliere e rimettere il JMP tutte le volte. |
![]() |
![]() |
![]() |
#17 | |
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Quote:
e il contesto è quello del thread corrente se no GetCurrentThreadId() non funzionerebbe , mi ritornerebbe un TID sbagliato , che mi sembra una cosa assurda,non credo che MS abbia fatto un errore così grossolano ![]() poi il fatto della dll "copia" caricata con LoadLibrary() per chiamare la funzione originale...ha un problema: il rootkit ha hookato LdrLoadDll() in ntdll.dll,quindi potrebbe fare una bastardata,lui prima di caricare la mia dll controlla le informazioni PE e si accorge che la dll è in realtà un ntdll.dll rinominato...e poi quello che fà lo lascio alla fantasia,magari carica la dll che voglio ma poi la hooka,oppure me ne carica un'altra,...che ne so allora pensando a questa cosa ho provato a fare questo : mi son caricato la dll a mano mappando il file in memoria,poi usando VirtualAlloc(...,PAGE_EXECUTE_READWRITE,...) per allocare tanta memoria quanta ne occupa l'immagine del modulo (quando è caricata in memoria) e poi copiando tutto il contenuto delle varie sezioni del file dentro questa immagine in memoria...poi infine ho chiamato la DllEntryPoint() passandole i parametri HINSTANCE = indirizzo ritornato da virtualalloc, DWORD = DLL_PROCESS_ATTACH e LPVOID=NULL per inizializzare la dll poi quando devo scrivere i byte di salto,se uso gli originali NtProtectVirtualMemory() (o VirtualProtect() ),il rootkit mi intercetta e vede che c'è qualcosa di sospetto,e anche qui potrebbe fare qualsiasi cosa,tipo far fallire la chiamata,oppure "scappare via" terminando il suo processo o non usando + i file nascosti etc. in modo che nessuno possa scoprire che è lui che li usa..e quant'altro...quindi devo usare NtQueryVirtualMemory() etc. della dll caricata a mano ho provato a caricare a mano ntdll , kernel32 e psapi...e con quest'ultima va in crash il programma quando chiamo l'entrypoint...mah non ho idea del perchè ecco,tornando a noi...nella funzione hook io chiamavo la funzione originale in questa dll caricata a mano...e funzionava tutto apparentemente bene con varie funzioni che ho provato...eccetto NtCreateFile() e NtOpenFile()...quando ho hookato notepad.exe , winamp.exe , iexplore.exe , vlc.exe e zonealarm.exe per fare una prova...tutti i processi forchè zonealarm non riuscivano a leggere i file,dava un MessageBox di errore tipo "ID di periferica oltre al valore limite imposto da windows" , o una roba del genere , oppure semplicemente diceva che il file non esiste o è impossibile aprirlo ecco,ho raccontato la mia vita morte e miracoli,e adesso hai capito perchè voglio adottare il metodo "chiamare le vere funzioni originali" i trampolini che dici tu proverò a vederli,ma mi puzza un po',dimmi se nel mio caso può funzionare |
|
![]() |
![]() |
![]() |
#18 | |||
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
![]() se vuoi ti faccio vedere il codice di un mio virus che lo fa (attualmente quel virus ha qualche problema che sto cercando di risolvere). Quote:
l'entry point di questo thread in teoria dovresti anche scriverlo in assembly puro e con anche qualche __emit dal momento che quando lo allochi nell'altro processo non è rilocato e quindi deve essere tutto completamente "position independent", ma di do' una dritta: in Visual C++ 6 puoi scriverlo in C alla condizione che non usi lo statement swicth ![]() Quote:
con i trampolines il JMP lo metti solo una volta in fase di inizializzazione e lo togli in fase di finalizzazione; anzi, quasi quasi ti consiglio proprio di usare le Detours ![]() ![]() PS: girando qua e là per Internet ho visto una volta un PDF che descriveva un sistema uguale a quello dei trampolines, solo che li chiamava semplicemente "stubs". Ultima modifica di 71104 : 07-10-2005 alle 11:34. |
|||
![]() |
![]() |
![]() |
#19 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
mi viene in mente una cosa: per applicare la tecnica dei trampolines è necessario un disassemblatore integrato nel tuo programma; chiaramente non ne puoi realizzare uno, ma è altrettanto assurdo sospendere tutti i threads ogni volta che togli e rimetti un JMP, quindi il mio consiglio è di utilizzare il disassemblatore delle Detours (sempre che non usi le Detours stesse), che è ottimo: è leggero e sicuro (fa anche dei "sanity checks").
|
![]() |
![]() |
![]() |
#20 | |||
Member
Iscritto dal: Apr 2005
Messaggi: 296
|
Quote:
![]() poi per le pagine di memoria fisica non contigue chi se ne frega, quello che conta è che le pagine di memoria VIRTUALE siano contigue,e non potrebbe essere altrimenti,scusa,se no andrebbe in crash il programma se solo faccio un memcpy() o memset() per scrivere su tutta quella memoria...ma questo non succede,quindi sono contigue p.s. se vuoi il codice te lo mando,ma è lungo...e il binding cosa sarebbe ? forse serve a trovare l'indirizzo di una funzione partendo dal suo nome? non serve,io guardo direttamente nella ExportDirectory Quote:
Quote:
|
|||
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 16:40.