View Full Version : anti-API monitor: si può?
non so se avete presente quei programmi tipo APIMon del PSDK di Microsoft, che servono a loggare tutte le chiamate API effettuate da un programma monitorato; quei programmi si basano sulla tecnica dei trampolines, che trovate egregiamente implementata nelle librerie Detours di Microsoft Research (una delle poche cose che zio Bill ci concede gratis), oppure su una tecnica simile ma più semplice che consiste nel piazzare/rimuovere dinamicamente il JMP incondizionato all'inizio del codice target secondo le necessità (ora scusate se non entro molto in dettaglio, ma l'ora... :D); entrambe le tecniche hanno pro e contro e si possono usare a seconda delle necessità.
ora mi chiedevo se fosse possibile realizzare un sistema che impedisse il monitoraggio delle chiamate a una certa funzione, partendo dal presupposto che un ipotetico monitor abbia installato una istruzione JMP near assoluta ai primi 5 bytes del codice della funzione monitorata.
l'idea che avevo avuto io si basa sul fatto che le API di Windows, che come convenzione di chiamata usano una macro definita come __stdcall, iniziano tutte con gli stessi primi 3 bytes: PUSH EBP
MOV EBP,ESP
di conseguenza avevo pensato di realizzare un stub contenente queste due istruzioni che poi chiamasse l'indirizzo effettivo della funzione più 3; in tal modo se è stato installato un JMP, la CPU eseguirà il codice disallineato saltando a metà del JMP: in alcuni casi semplicemente i 2 bytes rimanenti salteranno e la CPU riprenderà la normale esecuzione (il log non avverrà), mentre in altri la CPU eseguirà codice senza senso che probabilmente prima o poi manderà il processo in crash. se invece il JMP non è stato installato, la funzione viene eseguita normalmente.
esiti di questo genere a me andrebbero benissimo, potrei dire di aver ideato il mio sistema "anti - API monitor", ma ho un banale problema di implementazione C: io avevo dichiarato lo stub come segue: typedef DWORD (WINAPI *APIFUNC)();
__declspec(naked) DWORD WINAPI Stub(APIFUNC pfn) {
__asm {
pop eax
add eax,3
push ebp
mov ebp,esp
jmp eax
}
}
in tal modo basta chiamare la funzione API di turno non direttamente, bensì tramite la funzione Stub; l'indirizzo effettivo della API come vedete viene passato come argomento a Stub (quindi viene spinto nello stack, ma poi viene subito rimosso; non badate per ora al fatto che lo stub è un po' pesante, credo si possa ottimizzare, era solo una cosa temporanea).
fin qui ok, ma il problema sorge proprio quando devo chiamare lo stub; come faccio banalmente in C a fare il push dei parametri della funzione API? in un primo momento mi era venuto spontaneo di scrivere erroneamente così: Stub(GetMessage(&msg, NULL, 0, 0)); // esempio di chiamata a GetMessage che però ovviamente non va bene; io dovrei fare in modo che il compilatore generi nell'ordine:
- i push dei parametri della funzione API
- il push dell'indirizzo finale della API (e questo mi crea un altro problema meno banale che espongo di seguito)
- il call allo stub piuttosto che alla API
il problema meno banale di cui sopra è che l'indirizzo che il compilatore usa per generare il CALL alla funzione API non sempre corrisponde all'indirizzo effettivo dell'inizio del codice della funzione, anzi, non ci corrisponde quasi mai: nella maggior parte dei casi i compilatori (non chiedetemi perché, perché non l'ho mai capito) generano un CALL ad una entry in una tabella di JMP che a loro volta rimandano alle rispettive "funzioni target"; quindi al problema della chiamata della funzione API aggiungiamoci anche il fatto che dovrei fare questa "indirezione" per così dire...
anybody got some good idea? :)
buona notte :ronf: :D
[...] partendo dal presupposto che un ipotetico monitor abbia installato una istruzione JMP near assoluta ai primi 5 bytes del codice della funzione monitorata. [...] chiedo venia: qui temo di aver detto una cosa errata; riconsultando il reference mi accorgo che il JMP near assoluto esiste solo in forma indiretta... le Detours usano la versione near relative, che inizia con 0xE9 e infatti è la versione che meglio si adatta allo scopo discusso nel topic.
up!
non dovrò mica uppare per tutta la settimana...? :stordita:
Se stub fosse una funzione a parametri variabili (attenzione che dovresti descrivere anche i parametri)...potresti passare i parametri direttamente a Stub e fare il push dei parametri all'interno di Stub... Un po' come si fa con la printf...
ci avevo pensato, ma mi sa che se uso l'ellissi il compilatore mi costringe a usare __cdecl come convenzione di chiamata per Stub... :(
a me serve necessariamente __stdcall, cioè mi serve la stessa della funzione da chiamare, altrimenti poi quando la funzione fa il suo RET mi ripulisce lo stack, dopodiché quando esco da Stub il caller tenta di fare un'altra pulizia...
ultimi aggiornamenti: se uso l'ellissi posso anche specificare __stcall come convenzione, ma il compilatore ignora e usa __cdecl.
inoltre il codice dello stub era errato; questo sarebbe quello giusto: __declspec(naked) DWORD WINAPI Stub(APIFUNC pfn) {
__asm {
pop ecx
pop eax
push ecx
add eax,5
mov eax,eax
push ebp
mov ebp,esp
jmp eax
}
}
mi ero dimenticato che quando entro in Stub la prima cosa che trovo nello stack non è il primo parametro, è l'indirizzo di ritorno... :p
inoltre ho scoperto che per qualche oscuro motivo le funzioni API non iniziano con il push di ebp, ma con una inutilissima mov eax,eax... di conseguenza il codice che posso skippare viene portato a 5 bytes, e questa cosa mi cade a pennello perché così salto l'intero jmp ad una ipotetica routine di intercettazione :D
il codice viene eseguito normalmente e il log non avviene :Prrr:
sarebbe bello trovare una soluzione al mio problema: avrei progettato un anti-API monitor niente male :D (nessuno mi sa aiutare? :cry: )
dovrei solo avere l'accortezza di usare lo stub solo per le API che effettivamente iniziano con quei 5 bytes: penso che siano la maggior parte, ma se così non fosse posso sempre creare un altro stub, o altri 2.
hmmm... forse ci sono: si tratterebbe di una soluzione che va bene solo nel mio caso, ma che risolverebbe contemporaneamente entrambi i miei problemi.
va bene solo nel mio caso perché la soluzione va applicata prima della rilocazione del modulo su cui sto lavorando, e non sono sicuro che possa funzionare, ma proverò e tra qualche gg farò sapere.
nel frattempo se avete altre idee proponete plz thx :D
niente da fare, quello che avevo pensato non si può fare.
il fatto è che una soluzione potrebbe essere quella di utilizzare lo Stub con un cast, ma vorrei evitare di fare un cast per ogni funzione API che uso :stordita:
mi serve una soluzione più comoda :cry:
ehm, ma perché in questo thread parlo solo io? :stordita:
forse il primo post era troppo lungo da leggere? :stordita:
comunque stavolta penso di aver realmente trovato la soluzione; prima provo ad applicarla e poi la posto, per chi interessasse (pochini vedo... :stordita: )
cdimauro
18-08-2005, 08:13
Io ti leggo con interesse, anche se personalmente non perderei tempo su queste cose... :p
Io ti leggo con interesse, anche se personalmente non perderei tempo su queste cose... :p O_______________________O la trovi una perdita di tempo?????????
non andiamo affatto d'accordo allora!!! :D
a me questa cosa piace un sacco ;) e tante altre simili anche
cdimauro
18-08-2005, 11:59
Una protezione, per quanto ben congegnata, prima o poi verrà scardinata.
A meno di roba come Palladium, ma in questo caso non avresti comunque bisogno di proteggere il tuo software... :p
Una protezione, per quanto ben congegnata, prima o poi verrà scardinata.
A meno di roba come Palladium, ma in questo caso non avresti comunque bisogno di proteggere il tuo software... :p
Sono d'accordo. Che senso ha cercare di nascondere ste cose? Ho ti vergogni di quello che hai scritto, oppure sei un fan della filosofia "security through obscurity". :p
ciao ;)
cdimauro
18-08-2005, 12:59
Non vedo cosa ci sia di male in questa "filosofia": io la apprezzo particolarmente, specialmente in certi contesti. ;)
Non vedo cosa ci sia di male in questa "filosofia": io la apprezzo particolarmente, specialmente in certi contesti. ;)
<ot>Trovo quella "filosofia" sbagliata. Non mi piace nascondere il codice tutto qui. Trovo inutile perdere tempo a criptare codice o perdere la testa per impedire ad altri di sapere quali funzioni sto usando attraverso strani macchinamenti partoriti durante una notte di luna piena con uno strano allineamento dei pianeti.</ot>
ciao ;)
Una protezione, per quanto ben congegnata, prima o poi verrà scardinata. ci sono protezioni estremamente difficili da "scardinare": lo puoi fare solo se sai come fare. certo, alla fine si tratta solo di un discorso relativo: lo scopo non è quello di creare una protezione "incrakkabile", ma il più possibile difficile da crakkare. e con quella che sto congegnando io ti ci voglio... ;)
Sono d'accordo. Che senso ha cercare di nascondere ste cose? Ho ti vergogni di quello che hai scritto, oppure sei un fan della filosofia "security through obscurity". :p ne' l'uno ne' l'altro: sto semplicemente programmando uno spyware :D
e non mi venire a dire che allora è la prima: sono fierissimo del software che sto scrivendo!!! :D
mi affascinano molto le problematiche che sto affrontando e sono molto appassionato al lato tecnico del mio lavoro ;)
<ot>Trovo quella "filosofia" sbagliata. Non mi piace nascondere il codice tutto qui. Trovo inutile perdere tempo a criptare codice o perdere la testa per impedire ad altri di sapere quali funzioni sto usando attraverso strani macchinamenti partoriti durante una notte di luna piena con uno strano allineamento dei pianeti.</ot> be', arriverà anche per te il giorno in cui gradirai di essere pagato per il lavoro che fai: se mai programmerai un tool che desidererai proteggere e rendere closed e magari shareware, avrai la necessità di creare la classica versione limitata che si blocchi dopo N giorni.
dicono che in questi casi il modo migliore di agire non sia quello di bloccare dopo N giorni, ma di togliere del tutto il codice per abilitare determinate funzionalità; non credere che questo rappresenti un problema per un vero cracker: non ci si mette nulla a creare un crack che, una volta avviato il tuo programma ed entratoci con la solita CreateRemoteThread, risponda al comando Save nel quale con una compilazione condizionale tu avevi disabilitato la finestrella "Save as...".
ancora potresti rispondermi che l'autore potrebbe togliere non semplicemente la visualizzazione della finestra, ma l'intero codice per il salvataggio, o di qualche altra funzionalità: nei casi in cui la quantità di codice che il cracker deve "reinserire" diventi eccessiva, si può fare in due modi:
1) il cracker "reinventa" il codice (nel caso del comando Save inventa un suo formato; nel caso specifico questo implica che debba essere riprogrammato anche il comando Open e simili); oppure, soluzione spesso più semplice:
2) il cracker preleva il codice mancante da una versione completa del software.
in poche parole quello che voglio dire è che un cracker si può trovare di fronte a problemi più difficili, come ad es. il non conoscere l'esistenza di un simpatico stub che impedisce il monitoraggio dele chiamate API :D
esistono anche cose più perfide: tempo fa mi è stata insegnata una tecnica interessante che devo ancora capire bene a fondo: la perturbazione dello stack; ti dico solo che rende semplicemente impossibile il debugging del programma in ring 3...
be', arriverà anche per te il giorno in cui gradirai di essere pagato per il lavoro che fai: se mai programmerai un tool che desidererai proteggere e rendere closed e magari shareware, avrai la necessità di creare la classica versione limitata che si blocchi dopo N giorni.
In genere tendo a farmi pagare in base alle ore che ho impiegato per sviluppare. Ho sempre fornito anche i codici sorgenti a prodotto finito. Fino ad ora praticamente tutti hanno deciso di richiamare me ogni volta che volevano una modifica al programma. pagandomi. Se avessi venduto licenze sarei morto di fame da un bel pezzo.
ciao ;)
In genere tendo a farmi pagare in base alle ore che ho impiegato per sviluppare. Ho sempre fornito anche i codici sorgenti a prodotto finito. Fino ad ora praticamente tutti hanno deciso di richiamare me ogni volta che volevano una modifica al programma. pagandomi. Se avessi venduto licenze sarei morto di fame da un bel pezzo. oè! guarda che gli shareware non sono mica una mia invenzione, eh... :D
oè! guarda che gli shareware non sono mica una mia invenzione, eh... :D
Lo so. Io semplicemente mi guadagno da vivere in modo diverso. Preferisco investere il tempo a scrivere codice per un requisito del programma piuttosto che il codice per impedire ad un ipotetio cracker di scopiazare il progamma di gestione del inventario della societa Xadoom. :p
ciao ;)
cdimauro
19-08-2005, 08:30
<ot>Trovo quella "filosofia" sbagliata. Non mi piace nascondere il codice tutto qui. Trovo inutile perdere tempo a criptare codice o perdere la testa per impedire ad altri di sapere quali funzioni sto usando attraverso strani macchinamenti partoriti durante una notte di luna piena con uno strano allineamento dei pianeti.</ot>
ciao ;)
Non esiste una filosofia "sbagliata": dipende sempre dagli obiettivi che ti poni e dalle esigenze che hai.
Per farti un esempio pratico, alcune multinazionali preferisco non brevettare alcuni algoritmi perché anche un reverse engineer si perderebbe cercando di tirarli fuori analizzando i transistor che ne implementano le funzionalità.
La loro esigenza primaria è quella di non permettere ad altri di capire come funzionano e quindi di svilupparne di analoghi. In questo caso è più conveniente per loro non brevettare una tecnologia, e quindi fornire informazioni ai concorrenti, piuttosto che farlo, essere sì tutelati, ma offrire su un piatto d'argento idee e risultati di ricerche costati chissà quanto tempo e risorse.
Io sposo perfettamente la linea di pensiero di 71104, da questo punto di vista, ma non dico che la filosofia "open" sia intrinsencamente sbagliata.
cdimauro
19-08-2005, 08:34
ci sono protezioni estremamente difficili da "scardinare": lo puoi fare solo se sai come fare. certo, alla fine si tratta solo di un discorso relativo: lo scopo non è quello di creare una protezione "incrakkabile", ma il più possibile difficile da crakkare. e con quella che sto congegnando io ti ci voglio... ;)
Già, ma dovresti sapere che esistono dei debugger che simulano anche il funzionamento delle pipeline del processore, se c'è qualche software che usa particolare codice automodificante basato su questa tecnica, se necessario. :p
Secondo me c'è troppa differenza: gli hacker / cracker hanno a disposizione i migliori strumenti per lavorare, ma lo stesso non vale per chi invece deve sviluppare delle protezioni.
cdimauro
19-08-2005, 08:39
esistono anche cose più perfide: tempo fa mi è stata insegnata una tecnica interessante che devo ancora capire bene a fondo: la perturbazione dello stack; ti dico solo che rende semplicemente impossibile il debugging del programma in ring 3...
Me ne sono accorto perché qualche anno fa avevo notato un'utilissima funzione che permetteva di allocare "allegramente" memoria dallo stack, facendo un po' di "contorsionismi". :asd:
Poi però, a causa di un bug, facendo tracing mi sono ritrovato un pezzo di codice che la usava ed eseguendo lo step... BOOM! Dov'è finito l'IP? :asd: Il debugger s'era completamente incartato... :asd: :asd: :asd:
Non esiste una filosofia "sbagliata": dipende sempre dagli obiettivi che ti poni e dalle esigenze che hai.
Non tirare sempre in ballo la filosofia open. Qui non centra niente. :p
Io stavo semplicemente facendo notare che trovo inutile perdere tempo a fare ste cose perchè si tratta di progettare, scrivere, testare e debuggare codice che non ha nulla a che fare con il programma.
Se uno di questi giorni 71104 si dovesse trovare a voler debuggare il suo programma e ha solo il binario in quel momento voglio vedere poi come fa con tutte le protezzioni che ha messo. :p
ciao ;)
Se uno di questi giorni 71104 si dovesse trovare a voler debuggare il suo programma e ha solo il binario in quel momento voglio vedere poi come fa con tutte le protezzioni che ha messo. :p se sono così fesso da perdermi il sorgente di quel mostro... :D
se sono così fesso da perdermi il sorgente di quel mostro... :D
Intanto comincia a fare dei backup. Che non si sa mai :tie:
ciao ;)
aggiornamenti: sto lavorando alla mappatura del mio bel modulo PE; utilizzo i file mapping e le struct e le macro dichiarate in WINNT.h per lavorare col formato PE mi stanno tornando utilissime.
solo non capisco come mai la struct IMAGE_BASE_RELOCATION abbia un utilissimo campo... commentato!!! :confused: :confused: :confused:
che faccio, lo scommento? non è mai troppo elegante modificare headers di librerie...
per quanto riguarda la soluzione che avevo pensato, si applicherà quando passerò a lavorare su .idata: consiste nel modificare le importazioni in modo tale che puntino tutte ad una tabella di mini-stubs ciascuno col seguente codice: MOV EAX,0x________
JMP stubMain
dove 0x________ è l'indirizzo originariamente contenuto nella IAT, e stubMain è un'etichetta dove è contenuto il seguente codice: ADD EAX,5
PUSH EBP
MOV EBP,ESP
JMP EAX
geniale, no? :D
che faccio, lo scommento? non è mai troppo elegante modificare headers di librerie... l'ho decommentato :asd:
cdimauro
20-08-2005, 08:55
Non tirare sempre in ballo la filosofia open. Qui non centra niente. :p
C'entra, c'entra... ;)
Io stavo semplicemente facendo notare che trovo inutile perdere tempo a fare ste cose perchè si tratta di progettare, scrivere, testare e debuggare codice che non ha nulla a che fare con il programma.
Se per programma intendi soltanto l'applicazione che deve usare l'utente per soddisfare i suoi bisogni sì. Ma oltre ai bisogni degli utenti ci sono anche quelli dei programmatori che devono mangiare.
Personalmente non perderei tempo in queste cose, come ho detto, ma capisco le motivazioni di 71104...
Se uno di questi giorni 71104 si dovesse trovare a voler debuggare il suo programma e ha solo il binario in quel momento voglio vedere poi come fa con tutte le protezzioni che ha messo. :p
ciao ;)
Non m'è mai capitato di debuggare miei programmi senza sorgenti. Quelli degli altri sì, ma per altri motivi... :asd: :p
cdimauro
20-08-2005, 08:56
l'ho decommentato :asd:
E funziona ancora?!? :eek:
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.