2009-07-29 13 views
26

Poiché non ho trovato una risposta to the question asked previously here Sto provando un approccio diverso.Condivisione della memoria tra due processi (C, Windows)

C'è un modo per condividere la memoria tra due processi?

Il secondo processo riceve le informazioni da un'iniezione poiché è un programma legacy che non è più supportato.

La mia idea è di iniettare del codice lì, nella struttura che sto passando al programma iniettato passare l'indirizzo (o qualsiasi altra cosa) alla memoria condivisa in cui si trovano i dati che devo eseguire. Una volta ottenuti i dati, compilerò le mie variabili all'interno del thread inserito.

È possibile? Come?

Codice apprezzato.

EDIT:

penso che non è chiaro quindi mi chiarire. So come iniettare. Lo sto già facendo. Il problema qui è passare dati dinamici all'iniezione.

+0

Che tipo di programma? Windows, GUI, console? –

+0

tutti loro. Posso eseguire da un servizio, una GUI o una console – wonderer

+0

C'è un bel wrapper C++ facile da usare per i file mappati in memoria nel progetto POCO. http://pocoproject.org/download/index.html L'ho trovato dopo aver ripetutamente cercato dolorosamente di usare la roba Boost, che altre persone potrebbero trovare facile da usare, ma ho trovato brutalmente difficile da usare correttamente. –

risposta

9

Puoi provare a memory-mapped file.

This fornisce ulteriori dettagli passo-passo.

+0

Se non si desidera eseguire fino in fondo chiamate Raw32, suggerisco le classi wrapper pre-create del progetto POCO. http://pocoproject.org/download/index.html Molto più leggero e leggibile rispetto a Boost. –

24

Sebbene Windows supporti la memoria condivisa tramite il suo file mapping API, non è possibile iniettare facilmente un mapping di memoria condivisa in un altro processo direttamente, poiché MapViewOfFileEx non accetta un argomento di processo.

Tuttavia, è possibile iniettare alcuni dati allocando memoria in un altro processo utilizzando VirtualAllocEx e WriteProcessMemory. Se dovessi copiare in una maniglia usando DuplicateHandle, quindi iniettare uno stub che chiama MapViewOfFileEx, potresti stabilire una mappatura della memoria condivisa in un altro processo. Dal momento che sembra che ti stia iniettando del codice comunque, questo dovrebbe funzionare bene per te.

In sintesi, è necessario:

  • Creare un anonimo maniglia segmento di memoria condivisa chiamando CreateFileMapping con INVALID_HANDLE_VALUE per hFile e NULL per lpName.
  • Copia questo handle nel processo di destinazione con DuplicateHandle
  • Allocare po 'di memoria per il codice usando VirtualAllocEx, con flAllocationType = MEM_COMMIT | MEM_RESERVE e flProtect = PAGE_EXECUTE_READWRITE
  • Scrive il tuo codice stub in questa memoria, utilizzando WriteProcessMemory. Probabilmente questo stub dovrà essere scritto in assembler. Passa la MANIGLIA da DuplicateHandle scrivendola qui da qualche parte.
  • Esegui lo stub utilizzando CreateRemoteThread. Lo stub deve quindi utilizzare la MANIGLIA ottenuta per chiamare MapViewOfFileEx. I processi avranno quindi un segmento di memoria condivisa comune.

Si può trovare un po 'più facile se il vostro stub carica una libreria esterna - che è, hanno semplicemente chiamare LoadLibrary (trovare l'indirizzo del LoadLibrary viene lasciato come esercizio per il lettore) e fare il vostro lavoro dalla punto di ingresso del dllmain della biblioteca. In questo caso è probabile che l'utilizzo della memoria condivisa denominata sia più semplice di quello di andare avanti con DuplicateHandle.Vedere l'articolo MSDN su CreateFileMapping per ulteriori dettagli, ma, in sostanza, passare INVALID_HANDLE_VALUE per hFile e un nome per lpName.

Modifica: Poiché il problema sta passando i dati e non l'effettiva iniezione di codice, qui ci sono alcune opzioni.

  1. Utilizzare la memoria condivisa di dimensioni variabili. Il tuo stub prende la dimensione e il nome o un handle nella memoria condivisa. Questo è appropriato se hai bisogno solo di scambiare dati una volta. Si noti che la dimensione di un segmento di memoria condivisa non può essere facilmente modificata dopo la creazione.
  2. Utilizzare un named pipe. Il tuo stub prende il nome o un handle per la pipe. È quindi possibile utilizzare un protocollo appropriato per scambiare blocchi di dimensioni variabili, ad esempio scrivere un size_t per la lunghezza, seguito dal messaggio effettivo. In alternativa, utilizza PIPE_TYPE_MESSAGE e PIPE_READMODE_MESSAGE e osserva ERROR_MORE_DATA per determinare dove terminano i messaggi. Questo è appropriato se è necessario scambiare dati più volte.

Edit 2: Ecco un abbozzo di come si potrebbe implementare la maniglia o la conservazione puntatore per il vostro stub:

.db B8   ;; mov eax, imm32 
.dl handle_value ;; fill this in (located at the start of the image + one byte) 
;; handle value is now in eax, do with it as you will 
;; more code follows... 

Si potrebbe anche solo usare un nome fisso, che è probabilmente più semplice.

+0

Come una persona non windows che ha solo un'idea nozionale di cosa sta succedendo qui, dovrei essere un po 'spaventato che questo sia possibile? C'è un processo unix paragonabile per fare questo? –

+0

Sì, questo può essere fatto in Unix. Usa PTRACE_POKEUSER per registrare frob per una chiamata anonimo mmap. Una volta completata la chiamata, utilizzare PTRACE_POKEDATA o mmapping/proc/pid/mem per scrivere il codice. Quindi fare in modo che il codice faccia qualsiasi cosa. – bdonlan

+0

Per chiarire, quanto sopra era per Linux. Altri Unix probabilmente avranno qualcosa di simile. Se vuoi il tuo thread, chiama libpthread dal tuo stub iniettato. – bdonlan

1

Se stai parlando di Windows, il posto di blocco principale è che i processi ciascuno vivono nel loro spazio di indirizzi virtuali. Sfortunatamente non puoi passare i normali indirizzi di memoria in giro da un processo all'altro e ottenere i risultati che ti aspetteresti. (Thread, d'altra parte, tutti vivono nello stesso spazio indirizzo, motivo per cui i thread possono vedere la memoria nello stesso modo.)

Windows ha, tuttavia, uno spazio di memoria condiviso che devi essere molto attento gestire correttamente. Qualsiasi processo che alloca spazio nello spazio di memoria condiviso è responsabile della liberazione di quella memoria in modo esplicito. Questo è in contrasto con la memoria locale, che più o meno svanisce quando il processo muore.

Vedere this MSDN sample article per alcune idee su come utilizzare lo spazio di memoria condiviso per conquistare il mondo. Er, interfaccia con software legacy. O qualsiasi altra cosa :) Buona fortuna, qualunque cosa tu finisca per fare!

+0

Grazie per i commenti. Chiariscono la situazione un po 'di più. Questo articolo in realtà non dice che tipo di API o metodologie utilizzare. – wonderer

+3

L'heap globale è process-local in win32. Usarlo per la memoria condivisa non funzionerà su qualsiasi cosa basata su NT (XP e amici), almeno. – bdonlan

+0

@bdonlan - ?? forse non stiamo parlando della stessa cosa qui. L'heap globale vive nella memoria globale, che è condivisa tra tutti i processi. tutte le allocazioni sono basate su handle, non basate su puntatori, ecc. Penso che potresti avere ragione se stessimo parlando. NET - Non ricordo se la terminologia CLR gestita ha "globale" che significa qualcos'altro. bdonlan, puoi ampliare il tuo commento? Mi piacerebbe assicurarmi di capire di cosa sto parlando :) – Mike

0

È possibile provare a utilizzare Boost.Interprocess per comunicare tra due processi. Ma per iniettare il codice in un software precedentemente non supportato, probabilmente dovrai usare il modo @ bdonlan usando WriteProcessMemory.

+0

Grazie. Puoi elaborare? So come iniettare, non è questo il problema. – wonderer

+0

sto usando writeprocessmemory. Ho solo bisogno di passare informazioni che cambiano le dimensioni a volte – wonderer

1

Hai provato a utilizzare le pipe (per la memoria) o anche la serializzazione (per i tuoi oggetti)? È possibile utilizzare i file per gestire la memoria tra i processi. Gli zoccoli sono anche buoni per ottenere la comunicazione tra i processi.

0

La mappatura della memoria è la strada da percorrere, non è nemmeno necessario creare uno spazio di memoria permanente, il settore della memoria esce dall'ambito quando tutti i processi che lo condividono sono chiusi. Ci sono anche altri modi. Un modo rapido e sporco per trasferire i dati da una app C all'altra è solo per utilizzare il sistema operativo. Alla riga di comando digitare app1 | app2. Ciò fa sì che app2 sia la destinazione di output di app1 o iow un comando printf da app1 lo invii ad app2 (questo è chiamato piping).