2010-02-17 7 views
5

Imagine que desea escribir un programa que pruebe funciones en un archivo C++ dll. Debe permitir al usuario seleccionar un dll (suponemos que estamos hablando de C++ dlls). Debería poder obtener una lista de todas las funciones exportadas por el dll. Luego, el usuario debería poder seleccionar un nombre de función de la lista, ingresar manualmente una lista de argumentos (los argumentos son todos básicos, como int, double, bool o char arrays (por ejemplo, cadenas tipo c)) e intentar para ejecutar la función seleccionada con los argumentos especificados. Le gustaría saber si la función se ejecuta con los argumentos especificados, o hacen que se bloquee (porque no coinciden con la firma, por ejemplo).¿Puedo deducir programáticamente la convención de llamadas utilizada por un dll de C++?

El problema principal es que C++, al ser un lenguaje fuertemente tipado, requiere conocer el número y tipo de los argumentos a favor de una llamada de función en tiempo de compilación time.And en mi caso, simplemente no sé qué estos argumentos son, hasta que el usuario los selecciona en tiempo de ejecución.

La única solución que se me ocurrió fue utilizar el ensamblado para insertar manualmente los argumentos en la pila de llamadas.

Sin embargo, he llegado a entender que si quiero meterme con el ensamblado, será mejor que me asegure de saber qué convención de llamadas son las funciones en el dll.

Así que (finalmente :) aquí está mi pregunta: ¿puedo deducir el programa de convención de llamadas matemáticamente? Dependencia Walker no me ayudará, y no tengo idea de cómo leer manualmente el formato PE.

+0

¿Por qué no hace que el usuario especifique también la convención de llamadas? Predeterminado a stdcall (que es lo que es en dlls generados por los compiladores de Microsoft en estos días), pero permite al usuario cambiarlo. –

+0

Bueno, maldición. ¡Simplemente no había pensado en eso! Tengo que verificar si puedo hacerlo, pero si lo hago, esta sería una solución válida :))) –

Respuesta

3

La respuesta es quizás.

Si los nombres de las funciones están decorados en C++, puede determinar el recuento de argumentos y los tipos de la decoración del nombre, este es el mejor de los casos y muy probablemente si se usó MSVC para escribir el código.

Si las funciones exportadas son convención de llamada convencional (el valor predeterminado para la API de Windows), puede determinar el número de bytes que se presionarán, pero no los tipos de los argumentos.

La mala noticia es que para las convenciones de llamadas C, no hay ninguna forma de saberlo mirando los nombres de los símbolos. Debería tener acceso al código fuente o a la información de depuración.

http://en.wikipedia.org/wiki/X86_calling_conventions

El nombre que una función se da como una exportación no es requerido tener alguna relación con el nombre que el enlazador ve, pero la mayoría de las veces, el nombre exportado y el nombre del símbolo que el enlazador ve son lo mismo.

+0

Bueno, deduzco que no puedo obtener ninguna información sobre los argumentos de la función. Seré solo feliz de encontrar una manera de "forzar la alimentación" au ser definido lista de argumentos para una función y ver si se bloquea. –

+0

@Emil: Debe tener en cuenta que existen diferencias entre las convenciones de llamada en cuanto a si la persona que llama o quien llama muestra los argumentos. –

2

El código compilado no solo dice 'Aquí esta función es una llamada rápida, y esta aquí es stdcall' desafortunadamente.

Ni siquiera los desarmadores modernos como IDA intentan deducir los tipos de llamadas por defecto (puede haber un complemento o una opción en algún lugar idk).

Básicamente si eres humano, puedes ver las primeras instrucciones y decirlo el 90% del tiempo. Si son pop y push, es stdcall, si pasa a través de los parámetros de los registros (especialmente ecx) entonces su cdecl. Fastcall también usa los registros, pero hace algo especial ... no lo saques de la cabeza. Pero toda esta información es inútil porque obviamente su programa no será humano.

Si está realizando pruebas, ¿al menos no tiene los archivos de encabezado? Esta es una manera muy difícil de pelar un gato ..

+1

Comparando con https://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions su heurística no parece aplicar. Tanto stdcall como cdecl pasan parámetros en la pila. – jpa

0

Si desea saber qué convención de llamada de una función C++ utiliza, su mejor esperanza es estudiar

  1. El encabezado que declara que la función, y
  2. La documentación para el compilador que compiló su DLL particular.

Pero todo esto suena un poco desordenado, sinceramente. ¿Por qué su amigo quiere poder hacer esto y por qué no puede obtener la información que necesita al analizar un encabezado que declara las funciones relevantes?

+0

Lo sé, parece más que un desastre :) Estoy haciendo esto para la empresa para la que estoy haciendo una pasantía, y es simplemente una funcionalidad que necesitan proporcionar. Lo que es embarazoso es el hecho de que he visto un programa de uno de nuestros competidores que hace exactamente lo que describí, así que sé con certeza que es factible. No estoy seguro de si mi método es el camino a seguir, pero no tengo otras ideas :( –

+0

I Hace un rato, leí un artículo sobre cómo la compañía A siempre eclipsaba a sus competidores, porque usaban un lenguaje diferente. ¿Es posible que estén haciendo algo similar? ¿Tal vez tienen una capa de scripting o alguna otra rareza? – Narfanator

+0

Además, si tiene una muestra, vaya a un método científico y trate de descubrir cómo lo están haciendo. – Narfanator

3

No especificó si está hablando de 32 bits o de 64 bits aquí, y las dificultades esbozadas por usted y por los otros carteles se aplican principalmente al código de 32 bits. En Windows de 64 bits, básicamente hay una sola convención de llamadas (también está en el artículo de wikipedia vinculado por John Knoeller), lo que significa que usted sabe conoce la convención de llamadas (por supuesto, con la excepción de cualquiera que cocine por su cuenta) .

Además, con la convención de llamadas Microsoft x64, no conocer la cantidad de parámetros de la función a llamar no le impide llamarla, proporcionando tantos parámetros como desee o desee el usuario. Esto se debe a que, como persona que llama, aparta el espacio de la pila y lo limpia después. - Por supuesto, si no proporciona los [parámetros] correctos, la función llamada puede hacer tonterías porque está proporcionando información no válida, pero esa es otra historia.

+0

Sí, lo siento, quise decir 32 bits. –

0

Esta página describe la forma en VC++ 6 codifica parámetro y la información convención de llamada en un nombre de símbolo: http://www.bottledlight.com/docs/mangle.html

Sospecho que las versiones posteriores de VC++ serán compatibles pero no lo han confirmado.

También hay algunas herramientas que automatizan este que acompañan el compilador: http://msdn.microsoft.com/en-us/library/5x49w699.aspx

El nombre mangling sólo se aplica para funciones de C++; si una función es 'extern' C '' 'entonces esto no funcionará.

Cuestiones relacionadas