How toCreate your own MASM Import Libraries

by Iczelion
This short essay is about the mechanics of creating import libraries for use with MASM. I assume you already know something about import libraries, ie. you know what an import library is and so on. I will focus on the technique used to generate your own custom MASM import libraries.

MASM Import Library Format

MASM and Visual C++ can use the same import libraries which is very handy. Microsoft import libraries use a variation of COFF file format which is different from the OMF format used by TASM. That is the reason TASM cannot use MASM's import libs and vice versa. I won't go into detail about the details of Microsoft import library format. Suffice to say that every Microsoft import lib contains information about functions in some DLLs. That information includes the function names and the overall size of parameters passed to functions. If you examine kernel32.lib with a hex editor, you will find entries with this format:
_ExitProcess@4
_CreateProcessA@40
The function names are "decorated" with a leading underscore. The number following @ is the overall size of parameters of that function, in bytes. ExitProcess takes only one dword parameter, so that number is 4.
Why includes the information about the size of parameters? That information is used by MASM to check if the correct number and size of parameters are passed to a function. You get this feature when you call that function with invoke keyword. If you just push parameters on the stack and execute the function with call, you won't get this MASM check.
It's this extra boon which makes it nearly impossible to create MASM import libs directly from DLLs because DLLs don't contain explicit information about the size of parameters passed to their own functions.

Creating MASM Import Libs from DLLs

If you are willing to push parameters on the stack and execute functions with call, you can create import lib from any DLL for use with MASM like this:
      LIBRARY blah
      EXPORTS
      GetSomeLine
That's it. You'll get blah.lib which you can use with MASM so long as you don't use invoke with the functions in the import lib.

Creating MASM Import Libs for Use with invoke

I, for one, am reluctant to use the above approach. invoke is a nice function call wrapper. It's one of the reasons I prefer MASM to TASM. But as I pointed out earlier, it's next to impossible to create a 100% working MASM import lib from any DLL. You can't use the above method to create an MASM import lib which can be used with invoke. For example, you may think that if you modify the function names in .def file to include "@xx", the import lib should be ok. Trust me. It won't work.
The easy way to create an "invokable" import lib is to use MASM itself. If you have coded a DLL, you will observe that you also get an import lib for that DLL as well. And that import lib is fully invokable! Our strategy is as follow:
  1. Obtain the function names and the overall sizes of parameters
  2. Create a DLL source code that includes all those functions with the correct number and size of arguments.
  3. Create a module definition file that describes the corresponding functions in the asm source code.
  4. Assemble the asm source code as a DLL project.
That's it. You'll obtain a fully functional MASM import lib. The above steps deserve more explanation

Obtain the function names and overall sizes of parameters

This is the most difficult part of the process. If you have only the DLL, you're in for a tiresome adventure. Below are the methods I can think of, none of them works 100%.

Create a DLL asm source code which contains all those functions

After you obtain the function names and their parameter sizes, the rest is easy. You just create a DLL asm skeleton and then create functions with the same names as those in the DLL in the file. For example, if the DLL has only one function, GetSomeLine, which takes 16 bytes of parameters. In the asm file, you type the following lines:
.386
.model flat,stdcall
.code
GetSomeLine proc param1:DWORD, param2:DWORD, param3:DWORD, param4:DWORD
GetSomeline endp
end
What's this? You may ask. A procedure with no instruction inside? An import lib doesn't contain any info on what the functions are supposed to do. Its sole purpose is to provide information about the function names and their parameters. So we don't need to put any instruction into the dummy procedure. We will discard the useless DLL generated by the assembling process anyway. All we want is to put the info about the function names and the size of parameters into the asm source code so that MASM can generate the working import lib. The size of each parameter is NOT essential. For your information, currently MASM always regards each parameter as a DWORD no matter which size specifier you use. For example, we can use:
.386
.model flat,stdcall
.code
GetSomeLine proc param1:BYTE, param2:BYTE, param3:BYTE, param4:BYTE
GetSomeline endp
end
And MASM will happily create _GetSomeLine@16 entry in the import lib.

Create a matching module definition file

This is a simple process. You need this file so that MASM can generate the DLL and import lib. A module defintion file template is like this:
LIBRARY  <The name of the DLL>
EXPORTS
<The names of the functions>
You just fill the name of the DLL which will be used as the name of the import lib as well. And then put the list of the function names below the EXPORTS line, each name on its own line. Save the file and you got a working module defintion file.

Assemble the asm source code as a DLL project

The last step is the simplest one. Just use ml.exe and link.exe.
ml /c /coff /Cp blah.asm
link /DLL /NOENTRY /def:blah.def /subsystem:windows blah.obj
And you'll get an invokable import lib.

An Example

The dry explanation above may not be clear enough. I'm a firm believer in learning by doing. So I provide an example that demonstrates the above process. The example files are: Assembling the example will give you a kernel32.lib which you can use in place of the one provided by Microsoft.

More Tools

If you want to add/remove functions to/from a certain import lib, you can use two simpleminded tools I coded. For example, if you want to add undocumented functions to kernel32.lib, you'll find these tools useful.

Lib2Def

It extracts function names and the corresponding sizes of parameters from any MASM/VC++ import lib. Just run it and it will process ALL import libraries that are in the same folder. The output files have .icz extensions. The content looks like this:
_ExitProcess@4
_ExitThread@4
_ExitVDM@8
_ExpandEnvironmentStringsA@12
_ExpandEnvironmentStringsW@12   @12
If you want to add a function, you just insert a new line and put a leading underscore, followed by the function name and the combined size of its parameters. If the function is exported by ordinal, there will be another @xx following the name. The "xx" being the ordinal number. Note that this simple tool doesn't check for duplicate function names. And there can be duplicate names in some import libs.

MLib

This is the tool that accepts the output files of Lib2Def and creates import libs from them. It will process ALL files with .icz extension. For your information, it parses the lines in .icz files and creates .asm and .def from them. Then it calls ml.exe and link.exe to generate the import lib. The .obj, .asm, .exp and .dll are deleted afterwards so only .lib is left. If this tool fails to generate .lib file, please check if there are some duplicate function names in the .icz file: it's the most common cause of failure.

Download these two tools


[Iczelion's Win32 Assembly Homepage]