2006年10月3日 星期3 天气晴 Last Modify: Feb 2, 2007
==================================================================================
遇到了一个问题,就是汇编数组的存储方式的问题。见45.asm中的section3中的注释。尚未解决此问题,明日继续研究。
另外就是为了研究45.asm中的问题有帮助,提前试验了51.asm的库测试程序。在此之前我重新编译了Irivine32.asm,获得了自己生成的Lib文件,生成的参考文献见下面的收录的英文文章。其实说白了也很简单,就是使用bin中的Lib命令把一个obj文件生成库文件Lib就行了。事实证明我的这种方法是可行的,但是SmallWin.inc还是有一堆错误……索性我把Smallwin.inc从Irvine32.inc中注释掉了,一样可以通过库的测试程序。
在库的测试程序中,出现了一个问题,就是一开始的定义颜色的时候遇到了麻烦,颜色不听使唤了……
;set text color to Black text on White background:
mov eax,black + (white * 16) ;颜色显示错乱,由于使用了二进制的颜色值,改为16进制后正常……
call SetTextColor
其中颜色常量是在Irivine32.inc中定义的,他使用的是2进制。改为16进制后正常。其中的*16指的是将该值左移4位。不知道是不是这里遇到了问题,我明天对寄存器做一个转储,看一看具体是什么原因。
How to Create 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.
以上介绍的都是lib的特点,主要是Lib名字后有压栈的参数的大小,而dll没有。
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:
use dumpbin.exe which comes with Visual C++ to dump the names of the export functions in the DLL.
Dumpbin /EXPORTS blah.dll > output.txt
After you got the list of function names, create a module definition file (.def) from them. For example, if the function contains only one function, GetSomeLine, type the following lines into a text file:
LIBRARY blah
EXPORTS
GetSomeLine
Save it as blah.def
Run lib.exe to create the import lib from the module definition file, like this:
lib /DEF:blah.def
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.
用call命令的时候要自己压栈参数,所以处理起来比较简单,用到了一个C++自带的工具dumpbin来导出dll中的函数名,添加一些内容后改为后缀为def文件,然后用lib生成相应的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:
Obtain the function names and the overall sizes of parameters
Create a DLL source code that includes all those functions with the correct number and size of arguments.
Create a module definition file that describes the corresponding functions in the asm source code.
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%.
Use Interactive Disassembler (IDA) to disassemble the DLL. With this wonderful tool, you can obtain the rough size of parameters expected by the functions. The information is not perfect, however. IDA is an awesome disassembler but sometimes, only humans can decide which is which. You will have to peruse and check the whole disassembling listing.
Observe the value of the stack pointer before and after calls to all the functions in the DLL. The method is:
Obtain the address of the functions with GetProcAddress
Call each function without passing any parameter on the stack. Note the value of esp before the call.
When the function returns, compare the value of esp after the call with the one before the call. The rationale is: with stdcall parameter passing convention, the function is the one who takes care of the stack balancing. The difference of the esp values is the size of parameters expected by that function.
Alas, this method is not bullet-proof. It can fail under these circumstances:
If the functions in the DLL use other parameter passing convention other than stdcall or pascal.
If the functions fail to clean up the stack, such as when exceptions occur.
If the functions are designed to do something dangerous such as formatting the hard disk (God forbids!)
Study the existing programs that use the DLL. You can debug/disassemble those programs to see the number and size of parameters they pass to functions in the DLL. However, if there are some functions in the DLL which are never used in any program, you're left with the above two methods.
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:
The asm source code that contains all functions in kernel32.dll (the documented ones anyway)
The matching module definition file
A batch file which you can use to build the import lib
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
-----Feb 2, 2007-------------
加入这篇文章的本意是介绍Lib的用法,现在仔细看了一下没想到是关于为了在MASM中使用Lib而把DLL转化成为Lib的一篇文章,直到现在为止我还停留用C在制作Lib文件包含并调用他,还没有生成过dll,此篇文章中的中文为此次修订时后加的.
给出此网页的地址(如果无效了就google一下),下面这个貌似是他Iczelion的官方网站的文章:
http://win32assembly.online.fr/importlib.html