Dll原理和使用

转载


DLL原理。。。


    DLL 由4部分构成:代码段,数据段,输出符号表和输入符号表。


    代码段只读的,每个进程共享映射到此代码段.
    数据段在DLL 中可以定义多个,当DLL被映射到进程时,操作系统会为每个进程都创建一个对应的数据段,并把DLL中的全局数据复制到进程中。因此,如果不采取特别的措施,DLL中的数据段不能跨进程共享。但是可以将数据段的属性修改为共享的,这样该数据将被映像到所有的依附到该DLL的进程,多个进程将共享该数据段。
    在DLL 中可以调用其他的DLL 中实现的功能,因此,跟应用程序一样,DLL 中包含了一个输入符号表。该表中的每个项目记录了一个符号名、定义该符号的DLL模块名等信息。
    对DLL 而言,最重要的是它包含了一个输出符号表。对于DLL 中的输出的每个函数,变量都会在该表中添加一个项目,记录输出函数或者变量的符号名、序号以及在DLL 中的偏移。DLL 中的输出符号将被其他的DLL 或应用程序引入。

要查看DLL输出了那些符号,要指定-exports显项。例如:dumpbin .net 工具
   dumpbin exports sample14_1.dll
 结果显示sample14_1.dll输出了一个函数,其输出序号为0,其虚拟地址为0x00011389.
 ..............
 ordinal    hint     RVA        name
    1        0       00011389    DLLFunc1
               输出符号表

输出符号序号地址内容
DLLFunc1000011389hjmp DLLFunc1(00011f10h)
DLLFunc2100011393hjmp DLLFunc2(00011f50h)

查看DLL 输入了那些符号,要指定 -imports显项。例如sample14_1_1.exe,它用到了 sample14_1.dll中定义的两个函数,DLLFunc1和DLLFunc2。
..............
Section contains the following imports:
  SAMPLE14_1.dll
       42A310 Import Address Table
       42A18C Import Name Table
          0 time date stamp
          0 index of first forwarder reference
        0 DLLFunc1
        1 DLLFunc2
它表明,可执行文件中引用了在sample14_1.dll中定义的DLLFunc1 和DLLFunc2。链接器将位每个输入符号分配四个字节的表项,以保存该符号在进程空间的实际地址。"42A310"表示从SAMPLE14_1.dll中引用的第一个符号地址为0X42A310。由此可以推断,第二个从sample14_1.dll 中引入的符号地址为0x42a314。链接阶段,链接器无法确定每个输入符号在目标进程空间的实际地址,但是它知道每个输入符号相对于定义它的DLL模块的偏移。

sample14_1.dll 输出符号表中有下面的信息:
      ordinal   hint   RVA        name
         1       0     00011389   DLLFunc1
         2       1     00011393   DLLFunc2

sample14_1.exe 输入模块表(14-2):

输入模块输入符号表基地址
sample14_1.dll42A310h00000000h
kernel32.dll42A1C0h00000000h

              sample14_1.dll输入模块的输入符号表(14-3):

序号地址内容
042A310h00011389h(输出模块表地址)
142A314h00011393h

可以看出sample14_1_1.exe 的0X42A310处的值为"00011389",输入符号表中的内容是从lib文件中得到的。每个输入模块都会被分配一个输入符号表,表14-2记录了其输入符号表的起始地址。

对于DLLFunc1 和 DLLFunc2 的调用,通过一个call 指令实现:
     call         dword ptr[_imp_DLLFunc1(42A310h)]
     call         dword ptr[_imp_DLLFunc2(42A314h)]
......

假如运行时刻,地址42A310h中的内容为10000000h+00011389h=10011389h
那么:

     call dword ptr[_imp_DLLFunc1(42A310h)]

被转换为下述指令:

    10011389 jmp DllFunc1(10011F10h)...sample14_1_1.dll输出符号表实际地址=(地址0011389+偏移10000000)中存的内容(其中的地址也要相应的加偏移)

             输出符号表

输出符号序号地址内容
DLLFunc1000011389hjmp DLLFunc1(00011f10h)
DLLFunc2100011393hjmp DLLFunc2(00011f50h)

因为输入模块表仅记录了倚赖的dll的名字,所以还要确定该dll的完整路径。MFC 将按下面的路径搜索DLL:

      (1) 当前的进程的可执行模块所在的目录;
      (2) 当前的目录,也就是GetCurrentDir 返回的目录;
      (3) Windows系统目录,就是GetSystemDirectory返回的目录;
      (4) Windows 目录, 也就是GetWindowsDirectory 返回的目录;
      (5) PATH 环境变量中列出的目录。

然后MFC调用LoadLibrary 将DLL 映射到进程的地址空间。应用程序要修改它的输入模块表,记录每个DLL被映射的实际地址。如上列sample14_1.dll被映射到10000000h开始的空间,修改后的输入模块表为:

输入模块输入符号表基地址
sample14_1.dll42A310h00000000h-〉10000000h
kernel32.dll42A1C0h00000000h

输入模块输入符号表:

序号地址内容
042A310h00011389h+10000000h->10011389h
142A314h00011393h+10000000h->10011393h

jmp   DLLFunc1(00011F10h)

改为:jmp DllFunc1(10011F10h)

当DLL被映射到进程虚拟空间后,紧接着就是执行_DllMainCRTStartup,DllMainCRTStartup 会调用DLL 中定义的DLLMain函数(DLL入口函数)。系统为每个DLL都提供了一个_DllMainCRTStartup实现。而一般DLLMain由每个 DLL自己提供。

BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD ul_reason_for_call,
                      LPVOID lpReaserved
                     )
{
 }

当某线程第一次使用,最后一次使用,进程卸载DLL 系统调用次函数,传入的ul_reason_for_call分别为DLL_THREAD_ATTACH,DLL_THREAD_DETACH和DLL_PROCESS_DETACH。

 
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值