Dll的编写(上)

dll是非常实用代码复用机制,所有的方法在物理内存或者disk page中只有一份,数据可以是一份也可以定义为多份。这就为数据,方法共享和多任务操作,提供了非常大的便利。

——————>dll

dll当然是PE格式的文件,就像许多其他含有公用方法的文件一样,这些功能上都算是动态链接库。

当然了,关于PE文件,还得另行研究了。

——————>编写要点

1 dll同样可以使用资源,同样可以导入其他动态链接库的函数。

2 dll的方法被某PE使用之后,这个方法就相当于是该PE自身的,没有区别。

3 dll需要一个入口方法,也就是MSDN中的DLLMAIN

DllEntry proc _hInstance,_dwReason,_dwReserved
mov eax,TRUE
ret
DllEntry Endp

这里得到的_hInstance是dll本身的handle。也是唯一一次dll得到自己的handle 的机会

_dwReason有4种:

DLL_PROCESS_ATTACH

得到这个消息就表示,dll已经载入到线性地址中了。

这里可以做一些申请保留地址,以及初始化工作。

DLL_PROCESS_DETACH

可以做释放内存的工作,或将打开文件关闭等等工作。

DLL_THREAD_ATTACH

得到这个消息的时候,说明这个进程新建了一个线程。

MSDN上说这个时候可以去做一个TLS slot

DLL_THREAD_DETACH

这里可以把做TLS slot的memory 释放。

——————>也是,关于内存的操作一般都写在dll中的,exe都是处理逻辑上的事物,方法和模块都另外封装吧。

4文件的最后结尾是:end  入口方法名

5写完之后,我们还需要写一个def文件,这个是链接器需要的

要是详细了解还是要参看MSDN的”链接”这一个关键词

一个主要的写法就是:

EXPORTS

方法名A

方法名B

也可以定义变量。

(因为类里面有公有和私有,而EXPORTS的意思就是公有化。)

——————>link的选项

基本写法就是

/subsystem:windows /Dll  /DEF DEF文件名 obj文件 RES文件

——————>

这里面,如果需要数据段共享,那么可以加上个选项/Section .bss,S

MSDN上对这个选项的解释不太明确,还是要参考一篇文章:

http://msdn.microsoft.com/en-us/library/ms809762.aspx

——————>

编译链接之后,会生成需要的dll和lib文件

编程使用的话,需要lib来找dll

要是使用include的方式来加载lib,则需要用写一个prototype列表文件。

——————>

prototype在JavaScript里面有很广泛的应用,但是之前我在C里面是根本没有见过这个词

不过现在MASM里面却是出现了这个伪指令PROTO,其实这个词的意思就是函数声明,是编译器需要的。

感觉一部分用途是生成方法入口地址,另一部分是提供一个函数的参考模板,看看参数的数量类型(这个汇编里面没有返回值数量类型一说。。)是否匹配

prototypelist也就是模板的主要内容了。

所以,prototype就是个set default structure的意思。

——————>

回到dll的使用中

这里有2个扩展应用,一个是动态加载dll。另一个是其他语言加载汇编的dll

————————————>动态加载dll

这个比较麻烦,不过却解决了很多问题。反正大概知道有好处就是了,反正好处越大,代码就越复杂。。

就像传统的C和高级语言相比,写起来慢,但是好处是巨大的,这个不用说的。

动态加载dll涉及到3个API方法:

invoke LoadLibrary,addr szDll

参数是Dll的名字的string,如果成功,返回值是dll的handle(每个进程得到的handle是不一样的)

invoke GetProcAddress,hDllInstance,addr szIncCounter

第二个参数是存有公开的方法名的,string。返回值是方法的入口地址

invoke FreeLibrary,hDllInstance

释放这个dll。

——————>

1。操作系统会给dll上加个计数器,每加载一次+1,每free 1次就-1。当为0时,清楚掉dll在内存中的数据

2。要调用的时候,需要把dll的名称和方法都存到const里面去,这样也是麻烦不小。

3。调用过程,这个方法我们不能使用invoke。应该是编译器认为这只是个地址而不是的proc的缘故。毕竟我们之前没有函数声明。

所以我们变通的写两个数据类型的宏,即用typedef

先做个proto数据类型的宏,然后给这个宏的地址再用typedef做个宏。

_PROCVAR4 typedef proto :dword,:dword,:dword,:dword

_PROCVAR3 typedef proto :dword,:dword,:dword

_PROCVAR2 typedef proto :dword,:dword

_PROCVAR1 typedef proto :dword

_PROCVAR0 typedef proto

PROCVAR4 typedef ptr _PROCVAR4

PROCVAR3 typedef ptr _PROCVAR3

PROCVAR2  typedef ptr _PROCVAR2

PROCVAR1 typedef ptr _PROCVAR1

PROCVAR0 typedef ptr _PROCVAR0

我们就可以定义PROCVARx类型的指针数据了。

这个可以用invoke 来传参数了。

——————>

要让这个lib在C以及C++可以调用,那么,就必须写个头文件了。

要更深一步,比如在C和C++里面动态调用dll。我就不知道了。

头文件大致这样写:

#ifdef __cplusplus

extern “C” {

#endif

__stdcall _IncCounter();

__stdcall _DecCounter();

__stdcall _Mod(unsigned num1,unsigned num2);

#ifdef __cplusplus

}

#endif

在C和C++里面,汇编的返回值,那就是eax中,以unsigned表示了。

发表评论

您的电子邮箱不会被公开。 标记为 * 的区域必须填写

*


您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>