Cómo Crear tus propias bibliotecas de importación
para MASM
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í:
- usas dumpbin.exe, que viene con Visual C++, para volcar
los nombres de las funciones exportadas en la DLL.
LIBRARY blah
EXPORTS
GetSomeLine
Lo salvas como blah.def
- Corres lib.exe para crear la biblioteca de importación
a partir del archivo de definición del módulo, de esta manera:
lib /DEF:blah.def
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:
- Obtener los nombres de las funciones, y sobre todo
el tamaño de los parámetros.
-
Crear el código fuente de la DLL que incluye todas
esas funciones con el número correcto y tamaño de argumentos.
- Crear un archivo de módulo de definición
que describa las funciones correspondientes en el código fuente en
asm.
-
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:
- El código asm source que contiene todas las
funciones en kernel32.dll (las documentas de alguna manera)
- El archivo de definición de módulo matching
- Un archivo por lote [batch file] que puedes usar para
construir la lib de importación
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