Newsgroup: it.comp.programmare.win32
Titolo: Lanciare Immagine Eseguibile in Memoria (C/C++)

Salve a tutti quanti :)
 Programmo in C/C++ per Win32 e ho la necessita' di lanciare un file
eseguibile direttamente in RAM, dopo averlo opportunamente creato (in
pratica e' l'immagine di un qualsiasi file .EXE, solo che si trova in RAM
anziche' su disco).
 So che esistono le varie WinExec, CreateProcess, ShellExecute, ecc.... che
servono per lanciare programmi, ma non sono riuscito a trovare nessun
esempio che possa aiutarmi nel mio problema (mi e' sembrato che le suddette
funzioni non facciano quanto richiesto, o sbaglio ?).
 Mi basterebbe anche sapere solo il nome dell'eventuale API che risolve il
problema, o dove cercare .... insomma, qualsiasi cosa :)
Grazie, U D A.
--------------------------------
Inviato via 
http://usenet.libero.it


mi sa che devi per forza scrivere il file su disco e poi lanciarlo con
createprocess o simili
Pela

 funzioni non facciano quanto richiesto, o sbaglio ?).
Ho paura che dovrai scrivere un loader oppure (perchè usare il formato EXE
(PE) quando hai carta bianca?) inventarti un formato, allocare della
memoria, scriverci del codice, rilocarlo come vuoi tu, agganciare le
funzioni come vuoi tu, ed eseguirlo con CreateThread() o CreateThreadEx()
oppure in qualche altro modo.
Kiuhnm


 hmm ... tempo fa (quasi 2 anni) avevo letto che si poteva fare la cosa, ma
solo su WinNT e che c'era un'apposita API; anziche' il nome del file
accettava un (void*)buffer (o analogo)
 Al limite pensavo: potrei creare una sorta di "file virtuale" (un file che
sta in memoria anziche' su disco) e lanciarlo ?
Cioe' far credere al SO di lanciare un eseguibile nel solito modo ma che
pero' non si trova su disco (anche se "lui" crede che lo sia); in giro ho
letto che qualcosa di simile sono le "named pipes" ma non sono sicuro, ci ho
capito poco.
 Per quanto riguarda il formato sono obbligato ad usare i .EXE.
 Cmq vi ringrazio per l'interessamento .... almeno ho avuto conferma che e'
una strada poco percorribile :)
Ciao, U D A.


 sta in memoria anziche' su disco) e lanciarlo ?
Un metodo da cracker(!) potrebbe essere quello di "raggirare" la API
CreateProcess.
Questa funzione probabilmente userà (anzi quasi sicuramente...comunque
verificalo col SoftIce...io non ho molto tempo in questi giorni...)
CreateFile e ReadFile per aprire e leggere l'eseguibile.
Tutto quello che devi fare è sostituire le funzioni CreateFile e ReadFile
con delle tue funzioni fittizie!
Le tue funzioni emuleranno la lettura da file leggendo però direttamente
dalla RAM. Non dovrebbe essere troppo difficile scriverle!
Per sostituire le due API dovrai modificare l'indirizzo Export Table del
kernel32, però mi viene un dubbio: vuoi che il kernel32 usi la sua ET per
chiamare le sue stesse funzioni???
Non penso. Quindi anzichè modificare l'ET, metti dei bei "jmp your_func"
all'inizio di CreateFile e ReadFile. La tua funzione deve essere di tipo
WINAPI (in modo da usare la stessa convenzione dello stack usata dalle API).
(Ovviamente la cosa va fatta distintamente per CreateFile e ReadFile ovvero
usa jmp a funzioni diverse!)
Quando la tua API_fittizia ritorna, sarà come se l'API vera fosse ritornata
quindi non devi gestire lo stack manualmente o fare altre cose simili:
l'unica cosa che ti serve è quel "jmp [OFF32]".
Spero di essere stato abbastanza chiaro.
Kiuhnm

Piccola dimenticanza...
Visto che Windows è multitasking, è meglio modificare il kernel32 in maniera
più accorta.
Chiama CreateFile specificando un nome di file tipo "12904396598234". Le tue
API fittizie emularanno quelle vere soltanto se a CreateFile aprire chiesto
di aprire questo file. Se il filename non è quello, dovrà eseguire la
CreateFile originale, ecc...
Può essere fatto in questo modo:
CreateFile
jmp    FakeCreateFile
.
.
.
WINAPI FakeCreateFile(...params...)
{
    if (FileName == "234345345345")
    {
        // emulazione....
    }
    else
    {
        DeleteJmp();        // cancella il jmp in CreateFile ripristinando
il codice originale
        int ret = CreateFile(...params...)
        InsertJmp();        // inserisce nuovamente il jmp
        return ret;
    }
}
Chiaro?
Altra cosa!
Il kernel32 (così come le altre librerie) è copy on write quindi se
modifichi il kernel32 (per aggiungere/rimuovere i 2 jmp) direttamente
(usando i puntatori) la modifica influirà su ogni processo. Se invece usi
WriteProcessMemory(), Windows si accorgerà della modifica e, prima di
modificare il Kernel32, eseguirà una copia di tale pagina e modificherà la
copia. In questo modo solo il tuo processo (cioè quello da cui chiami
WriteProcessMemory()) vedrà i 2 jmp.
Tutti gli altri processi vedranno un kernel32 "normale" (si fa per dire,
eheheh) e quindi potrai evitare tutto il macello che ho illustrato in questo
messaggio. Tuttavia potrebbero esserci imprevisti. Per es. CreateProcess()
potrebbe leggere l'ultima parte dell'EXE nel contesto dell'EXE stesso, ma
non penso proprio. Da quello che so (un giorno controllerò, se avrò voglia)
il loader copia gli header dell'exe in memoria e poi li legge direttamente
dalla RAM. Il resto vien da sè col meccanismo della paginazione.
Kiuhnm

 file accettava un (void*)buffer (o analogo)
se vuoi farti veramente del male, posso dirti come si fa in Windows NT
-- 
 < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
     Don't stand, REACT!      version 0.0.19. C, C++ and ASM developers
                              and beta testers are welcome!

 your_func" all'inizio di CreateFile e ReadFile.
Non in Windows 95&family. Questa è una ricetta per un crash garantito. 
Le DLL (almeno quelle standard) sono condivise tra tutti i processi, e 
*non* in copy-on-write (che non è nemmeno supportato, mi pare). E' uno 
dei motivi per cui la libreria Detours di Microsoft Research (molto 
meglio che mettersi a piazzare jmp direttamente) funziona solo su 


 li legge direttamente dalla RAM.
perchč tenerti questo dubbio? scarica i sorgenti di ReactOS (sito in 
firma), verifica per conto tuo. CreateProcess funziona cosě:
 - inizializzazione
 - apri il file eseguibile
 - crea una sezione ("file mapping") per l'eseguibile
 - chiudi il file
 - crea un processo basato sulla sezione di cui sopra
 - chiudi la sezione
 - scrivi i parametri (environment, riga di comando, ecc.) nel processo
 - riserva lo stack per il primo thread
 - alloca la prima pagina di stack, metti il page guard sulla pagina
   successiva
 - scrivi un indirizzo di ritorno falso (0xDEADBEEF) e il base address
   del PEB come primo parametro nello stack del processo
 - crea il primo thread per il nuovo processo
 - fine
A questo punto la patata bollente č nelle mani del kernel, che vede che 
il primo thread del processo č stato creato, e (ovviamente dopo aver 
allocato il TEB) gli mette in coda un'APC puntata ad una funzione 
interna di NTDLL, che:
 - inizializza i dati del PE Loader
 - carica le DLL necessarie all'EXE principale
 - inizializza le DLL, chiamando il loro entry point
 - crea lo heap principale
 - ritorna
(controlla pure: lo stack frame della chiamata iniziale all'entry point 
di una DLL č sempre qualcosa del tipo:
<entry point della DLL>
ntdll!LdrpRunInitializeRoutines
ntdll!LdrpInitializeProcess
ntdll!LdrpInitialize
ntdll!KiUserApcDispatcher)


 Non in Windows 95&family. Questa è una ricetta per un crash garantito.
In Win98/SE funziona alla perfezione e comunque anche se la modifica fosse
globale non sarebbe certo un problema.
Kiuhnm

 perchè tenerti questo dubbio? scarica i sorgenti di ReactOS (sito in
Perchè non posso fare tutto nella vita....e poi sinceramente non me ne frega
neanche tanto altrimenti mi sarei informato. Non mi piace lavorare in Ring 3
e lo faccio il meno possibile.
Programmo in Ring 0 ed evito perfino di usare i servizi offerti da VMM e
altri Vxd.
Insomma uso Windows giusto come trampolino di lancio...
Comunque adesso, grazie a te, so qualcosa di nuovo senza aver perso troppo
tempo a cercare le info...
Kiuhnm

 modifica fosse globale non sarebbe certo un problema.
ah no? appena il tuo programma esce, gli altri iniziano ad andare in 
crash. Fai come Pietrek, piuttosto: cerca spazi vuoti in una delle 
sezioni di kernel32, e scrivi là dentro il codice della callback


 perso troppo tempo a cercare le info...
non č mai tempo perso


 sezioni di kernel32, e scrivi là dentro il codice della callback
Io veramente avevo usato un file mappato in memoria sempre presente anche
all'uscita del mio programma. Non mi piace trovare buchi nel kernel32 (anche
se ci sono): è sempre un ripiego e preferisco metodi più generici (lo so che
detto da me suona strano).
E poi avevo modificato anche l'IT di alcuni moduli...
Kiuhnm

 non è mai tempo perso
No, infatti 'sta volta m'è andata bene :-)))
Kiuhnm

 presente anche all'uscita del mio programma.
come hai fatto a creare un oggetto permanente in Windows 95?


 meandri di Windows e modificare qualcosa qua e là...
e allora 'zzi tuoi :-) te la sei cercata, non lamentarti
(a proposito, questo significa che posso usarti come cav^H^H^Hpunto di 
riferimento per una serie di informazioni sulle interiora di Windows 
95?)


 come hai fatto a creare un oggetto permanente in Windows 95?
Non uso il 95!!!
Uso il 98/SE!!!
Se nel 95 funziona il trucchetto dell'IDT o LDT, si può usare un servizio
VMM per allocare della memoria globale e poi usare quella...
Kiuhnm

 95?)
NON USO WINDOWS 95!!! BASTA!!!
Spero che per cav^H^H^H non intendessi "cavia"...
E comunque quando disassemblo Windows non vado mai oltre quello che mi
serve. Per esempio, tempo fa mi serviva forzare Windows a caricare un file
exe pe al BaseAddress indicato da me. Però ho esaminato tutto a basso
livello! Chiamate a _PageAllocate, ecc... ed è anche per questo che non
avevo notato CreateFileMapping :-)
E comunque l'uso di ReadFile è assurdo...non ha senso...dovevo essere un po'
fuso....
Kiuhnm

 che mi serve.
vabbč, qualcosa avrai imparato, o parti da zero ogni volta?
