2011-01-24 21 views
11

Sto lavorando con Visual Studio 2005.Compilare un programma C++ con dipendenza solo su kernel32.dll e user32.dll?

Voglio compilare un semplice programma che funzionerà con qualsiasi versione di Windows 32 bit indipendentemente da quale versione di libreria di runtime C++ installata.

Questo programma chiama le funzioni GetModuleHandle e GetProcAddress senza altre chiamate di funzione e quindi esce quando il codice di uscita è l'indirizzo della funzione.

Come compilare un programma C++ con dipendenza solo da kernel32.dll e user32.dll, senza alcuna libreria di runtime C++?

+1

+1 Questo è l'epitome di una buona domanda SO. –

+0

Qual è lo scopo di questo programma, se posso chiedere? –

+0

Sto implementando l'iniezione di codice da un processo a 64 bit a un processo a 32 bit e ho bisogno di un programma di supporto a 32 bit per trovare l'indirizzo di alcune funzioni. – DxCK

risposta

5

Impostare /NODEFAULTLIB sotto le opzioni del progetto. Nelle versioni più recenti di Visual C++, devi anche disattivare i controlli di sovraccarico dello stack, poiché questi fanno sì che il compilatore inserisca automaticamente le chiamate alle funzioni della libreria.

MODIFICA: Se si intende realmente "eseguire su QUALSIASI versione di Windows a 32 bit", sarà anche necessario utilizzare editbin per modificare il campo della versione del sottosistema nell'intestazione PE. Altrimenti ci si limita a (IIRC) Windows 2000 e versioni successive quando si costruisce con il linker VC++ 2005, e le versioni più recenti di VC++ sono ancora peggiori (per impostazione predefinita si richiede XP). Windows 2000 è 5.0, è necessario specificare 3.5 o giù di lì per consentire tutte le versioni di NT oltre a Win9x.

+1

Mentre si vuole specificare '/ nodefaultlib', ma esso stesso vi darà solo errori' esterni non risolti'. La vera chiave sta usando il tuo punto di ingresso per eliminare le dipendenze dalla libreria. –

+0

@Jerry: Penso che potresti nominare il tuo entry-point in base a qualunque cosa il linker cerchi per impostazione predefinita ('wCRTWinMain' o simile), ma sono d'accordo che l'uso di'/entry' è più pulito. –

+0

Non l'ho mai provato, quindi suppongo che potrebbe funzionare, ma non posso dirlo con certezza (senza test, è difficile dire quale magia il linker potrebbe usare/invocare/dipendere). Indipendentemente dal fatto che tu usi '/ entry:' per specificare di cosa si tratta, tuttavia, dovrai comunque definire il punto di ingresso. –

5

Avrai bisogno di definire il proprio punto di ingresso, invece di utilizzare main o WinMain. Il tuo punto di ingresso è una funzione vuota che non accetta argomenti. Devi specificare il nome del linker con /entry:funcName (dove funcName viene sostituito dal nome che hai assegnato alla funzione che desideri utilizzare come punto di ingresso).

Quando si esegue questa operazione, è necessario specificare il sottosistema sul linker, come in /subsystem:console. Si deduce normalmente il sottosistema in base al nome della funzione che trova (vale a dire, main -> Console, WinMain -> Windows), ma quando si utilizza il proprio punto di ingresso, è necessario specificare in modo esplicito. Anche se probabilmente non si vuole, molto spesso, è possibile specificare il sottosistema in modo esplicito anche quando non si specifica il proprio punto di ingresso, in modo (per esempio) è possibile utilizzare main come punto di ingresso per un programma per Windows sottosistema, o WinMain come punto di ingresso per un programma di console.

+1

Inoltre, il punto di ingresso deve essere dichiarato 'APIENTRY' (==' __stdcall'), e devi usare 'ExitProcess()' invece di ritornare da esso. –

+0

@Brian: Non è ciò che MSDN dice sul valore restituito --http: //msdn.microsoft.com/en-us/library/f9t8842e (v = VS.80) .aspx –

+1

@Brian: il ritorno da esso funziona correttamente . Normalmente non lo dichiaro con 'APIENTRY' o' __stdcall' - Mi limito a compilarlo con '/ Gz'. OTOH, quello che stai suggerendo è probabilmente * migliore * anche se non è realmente necessario. –

0

Controllare le piccole librerie. Anche collegamento statico.

+0

Tecnicamente è una risposta dato che sta facendo un suggerimento che potrebbe essere ciò che DxCK ha bisogno per iniziare/finire il suo progetto. Tuttavia potrebbe fare con il rimpolpare. –

1

Non sono sicuro del motivo per cui tutti consigliano di non utilizzare la libreria standard . Questo metodo presuppone che tu voglia che il tuo codice sia eseguito su Windows 2000 o successivo e non preoccuparti di perdere il supporto per Win 9x. È comunque possibile utilizzare la libreria standard C/C++ - È possibile utilizzare l'opzione /MT in/pagine C++ Codice generazione, che collegheranno nella libreria standard C statico del progetto.

Tuttavia, due note, la prima da me: l'idea di avere una libreria standard collegato dinamicamente è che tutti i bug nel otterrà patch da Windows Update (in teoria). Se si collega la libreria in modo statico, è necessario ridistribuire l'applicazione per correggere i bug della libreria standard. Quindi non è consigliato.

In secondo luogo, dal l'articolo di MSDN sulla compiler options:

Attenzione Non mescolare statica e versioni dinamiche dei runtime librerie. Avere più di una copia delle librerie di runtime in un processo può causare problemi, perché statici dati in una copia non è condiviso con l'altra copia. Il linker impedisce voi dal collegamento con sia statica che versioni dinamiche all'interno di un file exe, ma è ancora possibile finire con due (o più ) copie dei runtime librerie. Ad esempio, una libreria di collegamento dinamico collegato con le statiche (non-DLL) versioni del runtime librerie possono causare problemi quando viene utilizzato con un file exe che è stato collegato con la dinamica (DLL) versione di le librerie di runtime . (Si dovrebbe anche evitare di mescolare i di debug e non di debug versioni delle librerie in uno processo.)

In breve, facendo questo può causare confusione se si tenta di costruire in altri componenti collegati contro un dinamico libreria standard collegata.

Ovviamente, l'altro lato negativo è che questo renderà anche il tuo eseguibile più grande.

Modifica: il risultato, in depends.exe, è simile a questo: (ovviamente, sto usando Windows a 64 bit, che è disponibile solo per XP e versioni successive ... se vuoi sapere che cosa sembra come nelle finestre a 32 bit, immagina se gli 64 non fossero lì!).

depends.exe program showing only one dynamic dependency, kernel32.dll

+0

"Non sono sicuro del motivo per cui tutti consigliano di non utilizzare la libreria standard." Sì, era esattamente quello che stavo pensando. +1. – wj32

+0

Sono contento che non fosse solo io. Ho anche provato con il profiler 'depends.exe' per assicurarmi che le librerie standard non vengano chiamate dinamicamente. Nel caso in cui. –

+0

Forse perché la libreria standard dipende dalle funzioni introdotte in una particolare versione di Windows, che contraddice i requisiti della domanda. E la domanda diceva anche "senza libreria di runtime C++". –

0

In realtà non è necessario User32.dll sia, gli unici che veramente non può rimuovere sono Kernel32.dll e Ntdll.dll - quelli sono iniettati nel vostro spazio di elaborazione da PsCreateProcess (vale a dire la metà del kernel di come il kernel crea un nuovo processo).

+0

No, kernel32 non è mappato da "PsCreateProcess", che tra l'altro non esiste. kernel32 viene caricato da LdrpInitializeProcess in ntdll, in modalità utente. L'unica DLL che non è possibile rimuovere è ntdll. – wj32

+0

Forse dovrebbe essere PspCreateProcess, motivo per cui "non esiste". Oh bene. –

Problemi correlati