2009-08-03 7 views
8

Desidero incorporare un'utilità della riga di comando nell'applicazione C#, in modo che possa acquisire i suoi byte come matrice ed eseguire l'eseguibile senza mai salvarlo sul disco come separato file (evita di memorizzare l'eseguibile come file separato ed evita di dover scrivere file temporanei ovunque).Come eseguire un eseguibile non gestito dalla memoria anziché dal disco

Non riesco a trovare un metodo per eseguire un eseguibile dal proprio flusso di byte. Windows richiede che sia su un disco o esiste un modo per eseguirlo dalla memoria? Se Windows richiede che sia su disco, c'è un modo semplice nel framework .NET per creare un disco/file virtuale di qualche tipo e mappare il file allo stream di memoria dell'eseguibile?

+0

è possibile utilizzare un'utilità come imdisk – Martin

risposta

1

Creare un RAMdisk o eseguire il dump del codice in memoria e quindi eseguirlo sono entrambe possibili, ma soluzioni estremamente complicate (possibilmente di più nel codice gestito).

Ha bisogno di essere un eseguibile? Se lo impacchettate come assembly, potete usare Assembly.Load() da un flusso di memoria: un paio di linee di codice banali.

Oppure, se davvero deve essere un eseguibile, cosa c'è di sbagliato nella scrittura di un file temporaneo? Ci vorranno poche righe di codice per scaricarlo in un file temporaneo, eseguirlo, attendere che esca e quindi eliminare il file temporaneo - potrebbe non uscire nemmeno dalla cache del disco prima di averlo cancellato! A volte la soluzione semplice e ovvia è la soluzione migliore.

+0

Un eseguibile è solo un mucchio di byte e non vedo alcun motivo per cui un sistema operativo dovrebbe interessarsi se i byte provengono dal disco o dalla memoria, a condizione che entrambi i tipi di posizioni possano essere bloccati (e possono). Il sistema operativo sembra deporre se un file eseguibile si trova in un file system, perché? Se riusciamo a memorizzare i file delle mappe, perché non fare facilmente l'inverso registrando un percorso UNC univoco a un file virtuale supportato solo da un'area di memoria bloccata? Windows 7 non è ancora in grado di montare un'immagine ISO su un'unità virtuale in modo nativo senza software di terze parti, anche se tutta la roba di Microsoft è distribuita come immagini ISO. – Triynko

+0

Non penso di poter impacchettare una utility da riga di comando non gestita di terze parti compilata in C++ come un assembly che può essere usato con Assembly.Load. L'unica cosa sbagliata nella scrittura di file temporanei è che non penso che dovrebbe essere necessario, e mi richiede di trovare una directory temporanea e garantire l'accesso in scrittura, che è anche inutile. Ci sono solo tutti questi passaggi non necessari che potrebbero causare problemi che sto cercando di evitare, ma il sistema operativo e il framework .NET stanno rendendo difficile farlo. – Triynko

+0

Sono d'accordo con te. Penso solo che sarà difficile trovare qualcosa di così facile da implementare e testare come scrivere un file temporaneo. –

2

Dai un'occhiata alla sezione "In memoria" di questo documento. Renditi conto che è da una prospettiva di iniezione DLL remota, ma il concetto dovrebbe essere lo stesso.

Remote Library Injection

+1

Interessante, ma sto cercando un modo per usare qualcosa come Process.Inizia, passando una matrice di byte anziché un nome di file. Non mi piace la loro giustificazione per non avviare processi dalla memoria poiché "i programmi antivirus non riescono a scansionare programmi che non esistono mai sul disco" ... che sbirro. Se avessero creato il sistema operativo per eseguire i programmi in modo sicuro, la regola "deve originare su disco" non sarebbe necessaria. – Triynko

+0

Cosa intendi? Non esiste una regola del genere. È solo un dato di fatto che gli scanner antivirus (che non sono scritti da MS) diventano sospettosi ogni volta che un processo inizia improvvisamente ad eseguire codice auto-modificante. Mi sembra un comportamento appropriato, indipendentemente dal sistema operativo su cui è in esecuzione lo scanner. Se non si desidera affidarsi agli antivirus per questo tipo di protezione, ecco perché Windows ha integrato DPE per molti anni. –

+0

Il framework .NET applica una regola implicita secondo cui "il codice eseguibile deve essere originato sul disco" fornendo overload di Process.Start che alla fine accettano solo un nome file come puntatore al codice eseguibile. Non accetterà né un array di byte gestito né un puntatore a byte non gestiti che contengono codice eseguibile. – Triynko

11

si sta chiedendo molto a basso livello, funzionalità specifiche per la piattaforma da attuare in un alto livello, ambiente gestito. Tutto è possibile ... ma nessuno ha detto che sarebbe stato facile ...

(a proposito, non so il motivo per cui si pensa la gestione dei file temp è onerosa Il BCL lo fa per te:. http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename.aspx)


  1. Assegna memoria sufficiente per contenere l'eseguibile. Ovviamente non può risiedere nell'heap gestito, quindi, come quasi tutto in questo esercizio, è necessario PInvoke. (Raccomando C++/CLI, in realtà, in modo da non guidare te stesso troppo pazzo). Prestare particolare attenzione ai bit dell'attributo che si applicano alle pagine di memoria allocate: correggerli e aprire una falla di sicurezza aperta o interrompere il processo tramite DEP (ad esempio, si arresta in modo anomalo). Vedere http://msdn.microsoft.com/en-us/library/aa366553(VS.85).aspx

  2. Individuare l'eseguibile nella libreria di risorse dell'assembly e acquisire un pinned handle.

  3. Memcpy() il codice dall'area bloccata dell'heap gestito al blocco nativo.

  4. Libero il GCHandle.

  5. Chiamare VirtualProtect per impedire ulteriori scritture al blocco di memoria eseguibile.

  6. Calcolare l'indirizzo della funzione Main dell'eseguibile all'interno dello spazio di indirizzi virtuali del processo, in base all'handle ottenuto da VirtualAlloc e l'offset all'interno del file come mostrato da DUMPBIN o strumenti simili.

  7. Posizionare gli argomenti della riga di comando desiderati nello stack. (Windows Stdcall convention). Eventuali puntatori devono indicare le regioni native o bloccate, ovviamente.

  8. Salta all'indirizzo calcolato. Probabilmente il modo più semplice per usare _call (linguaggio assembly inline).

  9. Pregate Dio che l'immagine eseguibile non abbia salti assoluti in essa che sarebbero stati risolti chiamando LoadLibrary nel modo normale. (A meno che, naturalmente, non vogliate implementare nuovamente il cervello di LoadLibrary durante il passaggio n. 3).

  10. Recupera il valore di ritorno dal registro @eax.

  11. Chiama VirtualFree.

I passaggi 5 e 11 devono essere eseguiti in un blocco finale e/o utilizzare il modello IDisposable.


L'altra opzione principale sarebbe quella di creare un RAMdrive, scrivere l'eseguibile lì, eseguirlo e pulirlo. Questo potrebbe essere un po 'più sicuro poiché non stai cercando di scrivere codice auto-modificante (che è comunque difficile, ma soprattutto quando il codice non è nemmeno tuo). Ma sono abbastanza certo che richiederà ancora più chiamate API della piattaforma rispetto all'opzione di iniezione dinamica del codice - tutti che richiedono C++ o PInvoke, naturalmente.

+1

Guardando indietro a tutti quei passi e preghiere, spero che sia chiaro perché la regola del "codice deve essere sul disco" è così onerosa. Poiché il codice eseguibile viene alla fine caricato in memoria, dovrei essere in grado di eseguirlo direttamente dalla memoria, o caricarlo da disco in memoria e quindi eseguirlo. Il corrente .Le API NET mi richiederebbero di prendere il codice in memoria, scriverlo su disco, lavorare con un sistema di gestione file temporaneo, solo per poterlo leggere di nuovo in memoria, dove era già in primo piano! Questo sta solo dimostrando cosa succede quando avvolgi una vecchia tecnologia in abiti nuovi e gli dai un nuovo nome. – Triynko

+1

Inoltre, questa funzionalità "di basso livello, specifico per piattaforma" è già presente nel framework .NET gestito ad alto livello come "Process.Start". Il problema è che l'unico tipo di puntatore che accetta per i byte del codice eseguibile è un nome file, il che implica che un disco è l'unico codice posto che dovrebbe originare. – Triynko

+0

Non penso proprio che le autorizzazioni per i file debbano mai venire nel mix e, sfortunatamente, con i file temporanei. Vedere il commento su MSDN per Path.GetTempFilename: in ambienti con diritti bassi, ad es. in alcune configurazioni ASP.NET, questa funzione fallirà con un'eccezione di sicurezza ... perché deve trovare la directory temporanea e questo sta leggendo "Ambiente" ... richiede EnvironmentPermission per l'accesso illimitato alle variabili di ambiente. Enumerazione associata: PermissionState.Unrestricted – Triynko

-1

Questo non è consentito in Vista +. È possibile utilizzare alcune chiamate API Win32 non documentate in XP per farlo, ma era rotto in Vista + perché si trattava di un enorme buco di sicurezza e le uniche persone che lo utilizzavano erano scrittori di malware.

+1

Beh, è ​​ridicolo. Un flusso di byte è un flusso di byte indipendentemente da come lo guardi o da dove proviene. Forzare quei byte a venire da FILE piuttosto che MEMORY da eseguire non ha alcuno scopo. Malware? Sul serio? Dammi una pausa ... quindi devono solo prima scriverlo su un file per eseguirlo. Stai dicendo che c'era un buco di sicurezza nell'API (Ok, immagino), o stai dicendo che c'è un buco di sicurezza nell'idea di eseguire il codice da un flusso di memoria di byte piuttosto che da un flusso di byte di file (Sicuramente NON). – Triynko

+0

Non importa, e non è ridicolo. Per esempio; come convalidare in modo corretto e sicuro la firma di un'immagine eseguibile se il file non è su disco? Come funzionano i driver del filtro ora che stai eseguendo da un'immagine di memoria? In che modo le immagini di supporto funzionano ora che stai alimentando un flusso di memoria piuttosto che un nome di file? Questi sono solo alcuni, ma hai ancora un milione di casi d'angolo, come avere a che fare con le Opzioni di esecuzione dei file di immagine, le incoerenze con il debug, ecc. È davvero banale scrivere semplicemente il file, si tratta di budella molto complicata OS. –

+0

Convalidare la firma leggendo i byte dal blocco di memoria anziché i blocchi del disco! Non ci dovrebbe essere una differenza; è un design scadente. I driver dei filtri sono irrilevanti, poiché stiamo parlando di codice già in esecuzione, richiedendo l'avvio di un altro codice specifico e nessun filtro dovrebbe interferire con quel codice. Se hai davvero bisogno di filtri, il sistema operativo potrebbe fornire hook di basso livello per consentire ai filtri di scansionare la memoria appena prima che sia protetta e l'esecuzione abbia inizio. Ancora una volta, non c'è nulla di speciale sui dati presenti su un disco, è tutta un'architettura scadente. – Triynko