linker分析2
(*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地址在引入節部分。
最后調到引入函數的地址去執行。
總結
- 上一篇: Lenovo ThinkPad 3999
- 下一篇: dev c++怎么调试_「正点原子NAN