现在的位置: 首页 > 综合 > 正文

linker分析2

2013年01月26日 ⁄ 综合 ⁄ 共 3328字 ⁄ 字号 评论关闭

(*1*):建立DLL工程。在第二步选1。即默认。
//这个dll工程只用来输出两个函数。别无他用。
添加文件dll.cpp:
文件内容如下:
#include"stdio.h"
void __declspec(dllexport) ExportOne( void )
{
 printf("I am ExportOne!/n");
}
void __declspec(dllexport) ExportTwo( void )
{
 printf("I am ExportTwo!/n");
}
编译运行产生dll.obj dll.dll.
[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]
也可这样建立:
//文件dll.cpp
#include"stdio.h"
//void __declspec(dllexport) ExportOne( void )
void ExportOne(void)
{
 printf("I am ExportOne!/n");
}
//void __declspec(dllexport) ExportTwo( void )
void ExportTwo(void)
{
 printf("I am ExportTwo!/n");
}
//文件dll.def
; dll.def : Declares the module parameters for the DLL.

LIBRARY      "dll"
DESCRIPTION  'dll Windows Dynamic Link Library'

EXPORTS
    ; Explicit exports can go here
 ExportOne @1
 ExportTwo @2
[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]

(*2*):建立LIB工程。
//这个LIB工程只用来测试引入刚才DLL输出的两个函数。
添加文件lib.cpp
文件内容如下:

#include"stdio.h"
void ExportOne(void);
void ExportTwo(void);
void main()
{
 ExportOne();
 ExportTwo();
}
编译运行产生lib.obj lib.exe.
(*3*)LIB.OBJ分析
(*4*)反编译LIB.OBJ.注意代码节的文件偏移为00000392

:00000000 55                      push ebp
   ......
:00000018 E800000000              call 0000001D  //这里就是ExportOne()调用
:0000001D E800000000              call 00000022  //这里就是ExportTwo()调用
   ......
:00000032 C3                      ret

(*5*)LIB.EXE分析:

:00401000 55                      push ebp
  ......
:00401017 AB                      stosd

* Reference To: dll.ExportOne, Ord:0001h
                                  |
:00401018 E81D000000              Call 0040103A

* Reference To: dll.ExportTwo, Ord:0002h
                                  |
:0040101D E812000000              Call 00401034
  ......
:00401032 C3                      ret

:00401033 CC                      int 03

* Referenced by a CALL at Address:
|:0040101D  
|

* Reference To: dll.ExportTwo, Ord:0002h
                                  |
:00401034 FF25C8C04000            Jmp dword ptr [0040C0C8]

* Referenced by a CALL at Address:
|:00401018  
|

* Reference To: dll.ExportOne, Ord:0001h
                                  |
:0040103A FF25C4C04000            Jmp dword ptr [0040C0C4]

(*6*)引入函数与非引入函数的区别。
从上我们可以看出,其实不管是不是引入函数,编译器产生的函数调用代码都是CALL XXXXXXXX形式的。
//from dll.lib
Archive member name at 8: /              
3E951F55 time/date Thu Apr 10 15:37:57 2003
  ...
correct header end
    7 public symbols

      1FE __IMPORT_DESCRIPTOR_dll
      4F8 __NULL_IMPORT_DESCRIPTOR
      62C dll_NULL_THUNK_DATA
      778 ?ExportOne@@YAXXZ
      778 __imp_?ExportOne@@YAXXZ
      7E2 ?ExportTwo@@YAXXZ
      7E2 __imp_?ExportTwo@@YAXXZ
我们可以看到,在LIB文件中有引入函数的信息。
函数符号比如?ExportOne@@YAXXZ能够被解析。并且LIB文件中有很多关于引入函数的信息。比如:
  Summary
          BA .debug$S
          14 .idata$2
          14 .idata$3
           4 .idata$4
           4 .idata$5
           8 .idata$6   
所有的.idata节最终会被合并到可执行文件的.IDATA节中。从而形成IAT和其他有关引入表的结构。
SECTION HEADER #2
.idata$5 name
  ...
C0300040 flags
  ...
RAW DATA #2
  00000000: 00 00 00 00  
如果函数是通过序号引入的。那么在.idata$5节的DWORD的最高位为1。低位是引入(出)序号。
否则.idata$5节的DWORD为0。
如果函数是通过名字引入的。那么在.idata$6节的第一个WORD为引入(出)序号。接下去是一个函数名字。
**通过LIB文件,函数被决议为一个JMP DWORD PTR[XXXXXXXX]形式的指令。
通常称为STUB。当然LIB文件中也有引入函数的真正地址。
010 00000000 SECT3  notype ()    External     | ?ExportOne@@YAXXZ (void __cdecl ExportOne(void))
//以下为函数ExportOne的代码。
SECTION HEADER #3
   .text name
   ...
RAW DATA #3
  00000000: 55 8B EC 83 EC 40 53 56 57 8D 7D C0 B9 10 00 00  U....@SVW.}.....
  00000010: 00 B8 CC CC CC CC F3 AB 68 00 00 00 00 E8 00 00  ........h.......
  00000020: 00 00 83 C4 04 5F 5E 5B 83 C4 40 3B EC E8 00 00  ....._^[..@;....
  00000030: 00 00 8B E5 5D C3                                ....].
综上所述,对引入函数。产生的代码大致形式如下:
         CALL XXXXXXXX
         ...
XXXXXXXX:
         JMP DWORD PTR[YYYYYYYY]
YYYYYYYY地址在引入节部分。
最后调到引入函数的地址去执行。

抱歉!评论已关闭.