2011-01-24 15 views
11

Estoy trabajando con Visual Studio 2005.¿Compila un programa C++ con solo dependencia de kernel32.dll y user32.dll?

Quiero compilar un programa simple que funcionará con cualquier versión de Windows de 32 bits independientemente de la versión de biblioteca de tiempo de ejecución de C++ instalada.

Este programa llamará a las funciones GetModuleHandle y GetProcAddress sin ninguna otra función de llamadas, y luego saldrá, cuando el código de salida sea la dirección de la función.

Cómo compilar un programa en C++ con solo dependencia de kernel32.dll y user32.dll, sin ninguna biblioteca de tiempo de ejecución de C++?

+1

+1 Este es el epítome de una buena pregunta SO. –

+0

¿Cuál es el propósito de este programa, si puedo preguntar? –

+0

Estoy implementando la inyección de código de un proceso de 64 bits a un proceso de 32 bits, y necesito un programa de 32 bits para encontrar la dirección de algunas funciones. – DxCK

Respuesta

5

Establezca /NODEFAULTLIB en las opciones de su proyecto. En las versiones más nuevas de Visual C++, también deberá desactivar las comprobaciones de desbordamiento de pila, ya que estas hacen que el compilador inserte automáticamente las llamadas a las funciones de la biblioteca.

EDITAR: Si realmente quiere decir "ejecutar en CUALQUIER versión de Windows de 32 bits", también tendrá que usar editbin para cambiar el campo de versión del subsistema en el encabezado PE. De lo contrario, está restringido a (IIRC) Windows 2000 y posterior cuando compila con el enlazador VC++ 2005, y las versiones más nuevas de VC++ son incluso peores (requieren XP de manera predeterminada). Windows 2000 es 5.0, le gustaría especificar 3.5 o menos para permitir todas las versiones de NT además de Win9x.

+1

Si bien quieres especificar '/ nodefaultlib', pero a sí mismo solo te dará' errores externos 'no resueltos. La clave real es usar su propio punto de entrada para eliminar dependencias en la biblioteca. –

+0

@Jerry: supongo que podría nombrar su punto de entrada de acuerdo con lo que busque el enlazador de forma predeterminada ('wCRTWinMain' o similar), pero estoy de acuerdo en que el uso de'/entry' es más claro. –

+0

Nunca lo he intentado, así que supongo que podría funcionar, pero no puedo decirlo con certeza (sin pruebas, es difícil decir qué magia podría utilizar el enlazador/invocar/depender). Independientemente de si usa '/ entry:' para especificar de qué se trata, sin embargo, tendrá que definir el punto de entrada de todos modos. –

5

Deberá definir su propio punto de entrada en lugar de usar main o WinMain. Su punto de entrada es una función vacía que no toma argumentos. Debe especificar su nombre al vinculador con /entry:funcName (donde funcName se reemplaza por el nombre que le dio a la función que desea usar como punto de entrada).

Al hacer esto, también deberá especificar el subsistema al vinculador, como en /subsystem:console. Normalmente deduce el subsistema según el nombre de la función que encuentra (es decir, main -> consola, WinMain -> Windows), pero cuando utiliza su propio punto de entrada, debe especificarlo explícitamente. Aunque probablemente no desee con mucha frecuencia, puede especificar el subsistema explícitamente incluso cuando no especifica su propio punto de entrada, por lo que (por ejemplo) puede usar main como punto de entrada a un programa del subsistema de Windows, o WinMain como el punto de entrada a un programa de consola.

+1

Además, el punto de entrada debe declararse 'APIENTRY' (==' __stdcall'), y debe usar 'ExitProcess()' en lugar de regresar de él. –

+0

@Brian: Eso no es lo que dice MSDN sobre el valor de retorno --http: //msdn.microsoft.com/en-us/library/f9t8842e (v = VS.80) .aspx –

+1

@Brian: el regreso funciona bien . Normalmente tampoco lo declaro con 'APIENTRY' o' __stdcall', simplemente compilo con '/ Gz'. OTOH, lo que estás aconsejando probablemente sea * mejor * incluso si no es realmente necesario. –

0

Comprueba las minúsculas libs. También estático link.

+0

Técnicamente es una respuesta ya que está haciendo una sugerencia que puede ser lo que DxCK necesita para comenzar/finalizar su proyecto. Sin embargo, podría ser necesario para dar cuerpo. –

1

No estoy seguro de por qué todos aconsejan no utilizar la biblioteca estándar . Este método supone que desea que su código se ejecute en Windows 2000 o posterior y no le importa perder soporte para Win 9x. Aún puede usar la biblioteca estándar C/C++. Puede usar la opción /MT en las páginas de generación de código C/C++ de su proyecto, que se vincularán estáticamente en la biblioteca estándar.

Sin embargo, dos notas, la primera de mí: la idea de tener una biblioteca estándar enlazada dinámicamente es que cualquier error en él será reparado por Windows Update (en teoría). Si vincula la biblioteca de forma estática, debe redistribuir su aplicación para corregir errores estándar de la biblioteca. Por lo tanto, no se recomienda.

En segundo lugar, del artículo de MSDN en compiler options:

Precaución No mezcle estáticos y dinámicos versiones de los bibliotecas en tiempo de ejecución. Tener más de una copia de las bibliotecas de tiempo de ejecución en un proceso puede causar problemas, porque los datos estáticos en una copia no se comparten con la otra copia. El vinculador impide enlazar con versiones dinámicas estáticas y dentro de un archivo .exe, pero aún puede terminar con dos (o más) copias de las bibliotecas en tiempo de ejecución. Por ejemplo, una biblioteca de enlace dinámico vinculada con las versiones estáticas (no-DLL) de las bibliotecas en tiempo de ejecución pueden causar problemas cuando se usa con un archivo .exe que se vinculó con la versión dinámica (DLL) de las bibliotecas de tiempo de ejecución . (También debe evitar la mezcla de los depurar y no depuración versiones de las bibliotecas en una proceso.)

En resumen, hacer esto puede causar confusión si se intenta construir en otros componentes vinculados contra un dinámicamente biblioteca estándar enlazada.

Por supuesto, el otro inconveniente es que esto hará que su ejecutable sea más grande también.

Editar: el resultado, en depends.exe, se ve así: (por supuesto, estoy usando Windows de 64 bits, que solo está disponible para XP y posterior ... si quieres saber cómo se ve esto como en las ventanas de 32 bits, imagina si el 64 s no estuviera allí!).

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

+0

"No estoy seguro de por qué todos aconsejan no usar la biblioteca estándar". Sí, eso fue exactamente lo que estaba pensando. +1. – wj32

+0

Me alegra que no haya sido solo yo. También lo intenté usando el profiler 'depends.exe' para asegurarme de que las libs estándar no se llamen dinámicamente. Por si acaso. –

+0

Tal vez porque la biblioteca estándar depende de funciones introducidas en una versión particular de Windows, lo que contradice los requisitos de la pregunta. Y la pregunta también decía "sin ninguna biblioteca de tiempo de ejecución de C++". –

0

En realidad no es necesario User32.dll o bien, los únicos que realmente no se puede eliminar son Kernel32.dll y Ntdll.dll - los que se inyectan en el espacio de proceso por PsCreateProcess (es decir, la mitad del núcleo de cómo el kernel crea un nuevo proceso).

+0

No, kernel32 no está mapeado por "PsCreateProcess", que por cierto no existe. kernel32 es cargado por LdrpInitializeProcess en ntdll, en modo de usuario. La única DLL que no puede eliminar es ntdll. – wj32

+0

Tal vez debería ser PspCreateProcess, por lo que "no existe". Oh bien. –