linker分析2

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

(*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地址在引入节部分。

最后调到引入函数的地址去执行。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有  導航