¿Puedo usar el comstackdor C ++ de Visual Studio 2010 con C ++ Runtime Library de Visual Studio 2008?

Tengo una aplicación que necesita operar en Windows 2000. También me gustaría usar Visual Studio 2010 (principalmente debido al cambio en la definición de la palabra clave auto ). Sin embargo, estoy un poco comprometido porque necesito que la aplicación pueda operar en sistemas operativos anteriores, a saber:

  • Windows 2000
  • Windows XP RTM
  • Windows XP SP1

La biblioteca de tiempo de ejecución de Visual Studio 2010 depende de la API EncodePointer / DecodePointer que se introdujo en Windows XP SP2.

Si es posible usar la biblioteca de tiempo de ejecución alternativa, ¿romperá este código que se basa en las características de C ++ 0x agregadas en VS2010, como std::regex ?

La solución de Suma parecía bastante prometedora, pero no funciona: los __imp__*@4 necesitan ser indicadores de funciones, en lugar de las funciones mismas. Lamentablemente, no sé cómo hacer que Visual C ++ escupe un puntero con ese tipo de generación de nombres … (bueno, __declspec(naked) combinado con __stdcall hace el truco, pero entonces no sé cómo emitir un puntero).

Si está bien utilizar un ensamblador en tiempo de comstackción, la solución es bastante trivial: ensamble el siguiente código con FASM y vincule con el archivo de objeto producido, y prest – sin referencias EncodePointer / DecodePointer en el archivo ejecutable:

 use32 format ms coff section ".data" data public __imp__DecodePointer@4 __imp__DecodePointer@4 dd dummy public __imp__EncodePointer@4 __imp__EncodePointer@4 dd dummy section ".text" code dummy: mov eax, [esp+4] retn 4 

La solución más sencilla es simplemente configurar Platform Toolset en la configuración del proyecto en VS2010 a v900, que utilizará las bibliotecas y el comstackdor de Visual Studio 2008. Esto también significa que usted pierde las características de C ++ 0x como auto , pero para ser honesto, trabajar con algunas typedef es probablemente más fácil que construir su propia versión del CRT u otras soluciones más complicadas. Alternativamente, solo use VS2008! No sé si hay otras características de C ++ 0x que son críticas para su aplicación, sin mencionar, aparte de std::regex , que creo que todavía está en el conjunto de herramientas v900 en el espacio de nombres del informe técnico 1 ( std::tr1::regex ).

Solo por la impresión que tengo, podría predecir que la inconveniencia de hacer que las bibliotecas VS2010 se ejecuten en XP SP1 es mayor que la comodidad de las características de C ++ 0x, por lo que, en general, no valdría la pena.

No puede usar 2008 CRT, pero puede evitar que las nuevas funciones DecodePointer / EncodePointer se vinculen desde el kernel. Es bastante fácil reemplazar las nuevas funciones con stubs.

Uno podría intentar seguir: coloque un código como este en su fuente main.cpp:

 extern "C" { void *__stdcall _imp__DecodePointer(void *x) {return x;} void *__stdcall _imp__EncodePointer(void *x) {return x;} }; 

Lo anterior no funciona. Si bien la idea básica es sólida, la ejecución debe ser un poco diferente. Como se describe por snemarch en el comentario y en otra respuesta , __imp__ no puede ser la llamada a la función, solo el puntero a ella. Como parece que no es posible generar el puntero directamente por el comstackdor, debe ensamblar el siguiente código con MASM y vincularlo con el archivo de objeto producido.

 .model flat .data __imp__EncodePointer@4 dd dummy __imp__DecodePointer@4 dd dummy EXTERNDEF __imp__EncodePointer@4 : DWORD EXTERNDEF __imp__DecodePointer@4 : DWORD .code dummy proc mov eax, [esp+4] ret 4 dummy endp end 

Los símbolos de un proyecto tienen preferencia contra cualquier símbolo de las bibliotecas. Las bibliotecas DLL se vinculan usando partes .lib, que contienen solo “vectores” __imp__ “saltando a las funciones reales. Al reemplazar __imp__ “vectores” no toca el enlace DLL, reemplaza la parte .lib. He verificado que ya no existe ninguna dependencia del exe en DecodePointer / EncodePointer.

Fondo

La biblioteca enlazada estáticamente solo trae funcionalidad utilizada a la aplicación. Es posible encontrar qué función CRT particular traer en esas nuevas API utilizando salida de progreso detallado linker:

 Found __imp__EncodePointer@4 Referenced in LIBCMT.lib(crtmboxw.obj) Referenced in LIBCMT.lib(invarg.obj) Referenced in LIBCMT.lib(handler.obj) Referenced in LIBCMT.lib(onexit.obj) Referenced in LIBCMT.lib(cmiscdat.obj) Referenced in LIBCMT.lib(tidtable.obj) Referenced in LIBCMT.lib(hooks.obj) Referenced in LIBCMT.lib(winsig.obj) Referenced in LIBCMT.lib(rand_s.obj) Found __imp__DecodePointer@4 // ... same list, only order differs ... 

Esto muestra que las nuevas API se utilizan en algunos de los CRT para proporcionar más seguridad para algunas funciones que se considera que proporcionan vectores de ataque frecuentes.

Con un poco de esfuerzo, sería posible usar LoadLibrary / GetProcAddress para proporcionar la verdadera funcionalidad donde se encuentra el sistema operativo, pero no creo que realmente traiga algo. Las funciones de tiempo de ejecución que utilizan DecodePointer / EncodePointer realmente no necesitan proporcionar ninguna encoding, todo lo que necesitan es la encoding simétrica. Realmente no necesita la seguridad mejorada (el tiempo de ejecución de VS 2008 tampoco se lo daría).

Espero que no haya otros obstáculos esperándote: no tengo acceso al sistema Win2k o XP pre SP2, por lo tanto no puedo probar. Si hay indicadores de encabezado de exe que impiden incluso intentar ejecutar el exe en dichos sistemas, deberían ser fáciles de cambiar.

Como Visual Studio viene con soporte para MASM (ver propiedades del proyecto -> Personalizaciones de comstackción …) la siguiente traducción del código de snemarch a MASM podría ser útil:

 .model flat .data __imp__EncodePointer@4 dd dummy __imp__DecodePointer@4 dd dummy EXTERNDEF __imp__EncodePointer@4 : DWORD EXTERNDEF __imp__DecodePointer@4 : DWORD .code dummy proc mov eax, [esp+4] ret 4 dummy endp end 

Y recuerde configurar Linker-> System-> Minimum Required Version a 5.0 (por defecto es 5.1) para ejecutar en Windows 2000.

La solución habitual para este problema es crear su propia versión personalizada de CRT. Aquí hay instrucciones para esto. Solo tendrá que editar el código para ignorar EncodePointer y DecodePointer . (Ya debería haber un #define para eso).

Hay otras dos cosas menores que deberá hacer:

  • Vaya a la configuración Enlazador-> Directorios de biblioteca adicionales y establezca C:\Microsoft Visual Studio 9.0\VC\lib como la primera ruta de búsqueda. (Supongo que utilizó el directorio de instalación predeterminado, de lo contrario, cambie según corresponda).
  • Cambie la versión del subsistema, en el encabezado PE, a 5.00 (use el CFF Explorer Suite gratis si no tiene otra herramienta a mano para ello).

Eso debería permitir que su progtwig se ejecute en Windows 2000, así como en versiones posteriores.

Opción 1: cree una versión modificada del tiempo de ejecución de 2010 que redirija las llamadas problemáticas de la API a una DLL que proporcione. No sé cuán fácil o difícil sería (con la esperanza de que sea solo un pequeño cambio en la tabla de símbolos, depende del formato del archivo) y es muy probable que se tope con la cláusula de ingeniería inversa de la licencia, por supuesto. .

Opción 2: compare los símbolos exportados en dos versiones diferentes de las libs de tiempo de ejecución. Si los símbolos son los mismos, tiene buenas probabilidades de compatibilidad, aunque no hay garantías. Incluso es posible que los formatos de archivo lib sean diferentes.

Opción 3: compruebe si puede obtener acceso a fonts de tiempo de ejecución a través de MSDN o similar, específicamente para crear una versión parchada.

Opción 4: compruebe si puede usar el comstackdor de 2010, pero un enlazador anterior, quizás configurado en sus soluciones como un paso de comstackción personalizado. De nuevo, esto depende de si los archivos obj y lib tienen el mismo formato de archivo, pero es posible que pueda escribir una pequeña utilidad para parchar diferencias simples como números de versión en un encabezado. El enlazador anterior no debería tener problemas para vincularse en el tiempo de ejecución anterior, suponiendo que los objs del nuevo comstackdor sean compatibles con él.

Opción 5: comstackr archivos DLL en 2010 que no necesitan su propio tiempo de ejecución, pero que se cargan y alojan en una aplicación creada con el comstackdor anterior. Lograr el requisito “sin tiempo de ejecución” para sus archivos DLL puede significar que muchas de sus bibliotecas deben estar integradas en la aplicación de alojamiento, por supuesto, y es posible que deba proporcionar sus propias interfaces (a través de la aplicación host) a las funciones de la biblioteca que necesita para trabajar con – especialmente cosas de asignación de memoria.

Merece la pena verificar las opciones, pero estoy seguro de que ya las pensó todas, lo siento, no tengo idea de si alguna de ellas funcionará, o si funcionarán casi por completo, pero ocasionarán problemas intermitentes.

Esto sería mucho más fácil si se le permite usar una DLL. Básicamente, escriba un EXE que no requiera ninguna función de tiempo de ejecución de C, utilizando la función del enlazador / ENTRYPOINT. Una vez que haya comprobado que se cumplen sus requisitos previos básicos y haya informado de cualquier problema al usuario a través de las API provistas por Windows disponibles en todos los sistemas operativos de destino (es decir, MessageBox), llame a LoadLibrary para iniciar la DLL que contiene la mayor parte de su lógica . Esa DLL puede usar el tiempo de ejecución VS2010 como de costumbre. Incluso puede evitar implementar dos archivos separados al descomprimir la DLL de un recurso contenido en su .EXE principal al inicio. (Puede hacer esto completamente dentro de la memoria sin escribir .DLL en el disco, pero no si desea aprovechar el cargador de Windows PE para arreglar todas sus importaciones).

Cree un .LIB que implemente la funcionalidad faltante y vincule antes de KERNEL32.LIB.

Tendrá que utilizar la opción del vinculador /NODEFAULTLIB:kernel32.lib para que pueda poner su w2kcompat.lib por delante de kernel32.lib.