Site hosted by Angelfire.com: Build your free website today!

Cómo Crear tus propias bibliotecas de importación para MASM

por Iczelion
Este corto ensayo trata sobre los mecanismos para crear bibliotecas de importación para ser usadas con MASM. Asumo que ya conoces algo sobre las librerías de importación, es decir, que sabes qué son. Me concentraré en la técnica que puedes usar para generar tus propias bibliotecas de importación para MASM.

Formato de la biblioteca de Importación MASM

MASM y Visual C++ pueden usar las mismas bibliotecas de importación, lo que resulta muy manejable. Las bibliotecas de importación de Microsoft usan una variación del formato del archivo COFF que es diferente del formato OMF usado por TASM. Esa es la razón de que TASM no pueda usar las bibliotecas de importación de MASM y vice versa. No voy a entrar en detalles sobre el formato de las bibliotecas de importación de Microsoft. Es suficiente decir que todas las lib de importación de Microsoft contienen información sobre las funciones contenidas en algunas DLLs. Esa información incluye los nombres de las funciones y, sobre todo, el tamaño de los parámetros pasados a las funciones. Si examinas kernel32.lib con un editor hexadecimal, encontrarás entradas con este formato:
_ExitProcess@4
_CreateProcessA@40

Los nombres de las funciones son "decorados" con una línea de subrayado al comienzo. El número que sigue a @ es el total de la suma de los tamaños de los parámetros de esa función, en bytes. ExitProcess toma sólo un parámetro dword, así que el número es 4.

¿Por qué incluye la información sobre el tamaño de los parámetros? Esa información es usada por MASM para chequear si el número correcto y el tamaño de los parámetros es pasado a la función. Obtienes este funcionalidad cuando llamas a la función con la palabra clave invoke. Si pones parámetros en la pila y ejecutas la función con call, no obtendrás este chequeo por parte de MASM.

Es este dichoso aporte lo que hace casi imposible crear directamente bibliotecas de importación para MASM a partir de DLLs porque éstas no contienen información sobre el tamaño de los parámetros pasados a sus propias funciones.

Creando bibliotecas de Importación para MASM a partir de DLLs

Si quieres meter parámetros en la pila y ejecutar las funciones con call, puedes crear bibliotecas de importación para usar con MASM desde cualquier DLL así:
      LIBRARY blah
      EXPORTS
      GetSomeLine
Eso es todo. Obtendrás blah.lib que podrás usar con MASM siempre que no uses invoke con las funciones en la biblioteca de importación.

Creando bibliotecas de Importación para MASM para usar con invoke

Particularmente, soy reacio al uso del método anterior. invoke es una linda envoltura para llamar a funciones. Es una de las razones por las que prefiero MASM en vez de TASM. Pero como dije antes, es casi imposible crear una lib de importación que trabaje al 100% con MASM a partir de una DLL. No puedes usar el método de arriba para crear una lib de importación MASM que pueda ser usada con invoke. Por ejemplo, puedes pensar que si modificas los nombres de las funciones en el archivo .def para incluir "@xx", la lib de importación debería estar bien. Confía en mí. No trabajará.

La manera más fácil de crear una biblioteca de importación con funciones "invokables" es usar el mismo MASM. Si quieres escribir una DLL, observarás que también obtendrás una biblioteca de importación para esa DLL. ¡Y esa biblioteca de importación es completamente invokable! Nuestra estrategia es la siguiente:

  1. Obtener los nombres de las funciones, y sobre todo el tamaño de los parámetros.
  2. Crear el código fuente de la DLL que incluye todas esas funciones con el número correcto y tamaño de argumentos.
  3. Crear un archivo de módulo de definición que describa las funciones correspondientes en el código fuente en asm.
  4. Ensamblar el el código fuente en asm como un proyecto de DLL.
Eso es todo. Obtendrás el código fuente en asm de una lib de importación para MASM completamente funcional. Los pasos anteriores requieren mayor explicación

Obtener los nombres de las funciones y especialmente el tamaño de los parámetros asm

Esta es la parte más difícil del proceso. Si sólo puede tener la DLL, será para tí una aventura tediosa. Abajo están los métodos en los que pienso, ninguno de ellos trabaja al 100%.

 

Estudiar los programas existentes que usan la DLL. Puedes depurar/desensamblar esos programas para ver el número y tamaño de los parámetros que pasan a las funciones en la DLL. Sin embargo, si hay algunas funciones en la DLL que nunca son usadas en el programa, quedarás abandonado a los dos métodos anteriores.

Crear un código fuente asm de DLL que contenga todas las funciones

Después de obtener el nombre de las funciones y el tamaño de sus parámetros, el resto es fácil. Sólo tienes que crear un esqueleto en asm de DLL y luego creas las funciones con los mismos nombres que los de la DLL en el archivo. Por ejemplo, si la DLL tiene sólo una función, GetSomeLine, la cual tiene 16 bytes de parámetros. En el archivo asm, escribes las siguientes líneas:
.386
.model flat,stdcall
.code
GetSomeLine proc param1:DWORD, param2:DWORD, param3:DWORD, param4:DWORD
GetSomeline endp
end
¿Qué es esto? podrías preguntar. ¿Un procedimiento sin ninguna instrucción? Una lib de importacuión no contiene sobre qué funciones are supposed to do. Su único propósito es porveer información sonbre los nombres de las funciones y sus parámetros. Así que no necesitamos poner ninguna instrucción dentro del procedimiento ficticio. Descartaremos la DLL inútil generada por el proceso de ensamblado anyway. Todo lo que queremos es poner la info sobre los nombres de función y el tamaño de parámetros dentro del código fuente en asm de manera que MASM pùeda generar la lib de importación funcional. El tamaño de cada parámetro NO es esencial. Para tu información, generalmente MASM siempre considera cada parámetro como una DWORD no importa cuál especificador de tamaño uses. Por ejemplo, podemos usar:
.386
.model flat,stdcall
.code
GetSomeLine proc param1:BYTE, param2:BYTE, param3:BYTE, param4:BYTE
GetSomeline endp
end
Y MASM felizmente creará la entrada _GetSomeLine@16 en la biblioteca de importación.

Create a matching module definition file

Es un proceso simple. Necesitas este archivo de manera que MASM pueda generar la DLL y la lib de importación. Una plantilla de un archivo de definición de módulo sería algo como esto:
LIBRARY  <The name of the DLL>
EXPORTS
<The names of the functions>
Sólo llenas el miembro del nombre de la DLL que será usada también como el nombre de la lib de importación.Y luego pones la lista de los nombres de la función debajo de la línea EXPORTS, cada nombre en su propia línea. Salvas el archivo y obtendrás un archivo de definición de módulo completamente funcional.

Ensamblar el código fuente asm como un proyecto DLL

El último paso es más simple. Sólo usa ml.exe y link.exe.
ml /c /coff /Cp blah.asm
link /DLL /NOENTRY /def:blah.def /subsystem:windows blah.obj
Y obtendrás una lib de importación invokable.

Un Ejemplo

La seca explicación de arriba no puede ser lo suficientemente clara. Soy un firme creyente en el aprendizaje a través de la práctica. Así que suministro un ejemplo que demuestra el procedimiento anterior. Los archivos ejemplos son: Al ensamblar el ejemplo obtendrás una kernel32.lib que puedes usar en lugar de la suministrada por Microsoft.

Más Herramientas

Si quieres agregar/remover funciones a/desde una cierta lib de importación, puedes usar dos herramientas que codifiqué. Por ejemplo, si quieres agregar funciones no documentadas a kernel32.lib, encontrarás que esas herramientas son muy útiles.

Lib2Def

Extrae los nombres de las funciones y los tamaños correspondientes de los parámetros de cualquier biblioteca . LIB de importación MASM/VC++. Sólo córrela y procesará todas las bibliotecas de importación que están en el mismo directorio. Los archivos de salida tienen extensiones .icz. El contenido tiene un aspecto como el siguiente:
_ExitProcess@4
_ExitThread@4
_ExitVDM@8
_ExpandEnvironmentStringsA@12
_ExpandEnvironmentStringsW@12   @12
Si quieres agregar una función, sólo inserta una línea nueva y pones una línea de subrrayado, seguida por el nombre de la función y el tamaño combinado de sus parámetros. Si la función es exportada por ordinal, habrá otro @xx después del nombre. Siendo las "xx" el número del ordinal. Nota que esta simple herramienta no chequea en busca de nombres de funciones duplicados. Y puede haber algunos nombres duplicados en algunas bibliotecas de importación.

MLib

Esta es la herramienta que acepta salida de Lib2Def y crea archivos de definición a partir de ella. Procesará todos los archivos con extensión .icz. Para tu información, analiza las líneas en los ficheros .icz y crea ficheros .asm y .def a partir de ellas. Luego llama a ml.exe y a link.exe para generar una biblioteca de importación. Los archivos .obj, .asm, .exp y .dll son luego borrados y sólo se conservará el archivo .lib. Si esta herramienta falla al generará el archivo .lib, por favor chequea si hay algunos nombres de funciones duplicados en el archivo.icz: es la causa más común de la falla.

Baja estas dos herramientas


[Iczelion's Win32 Assembly Homepage]

n u M I T_o r's   Programming Page

Este tutorial, original de Iczelion, ha sido traducido por:   n u M I T_o r