DLL 導入段 import section

1.爲什麼需要導入段?

要回答這個問題... 我們得了解可執行文件執行的過程..

啓動一個可執行模塊的時候(通常是EXE文件..).操作系統的加載程序(以後簡稱加載程序)會先創建一個進程,然後通
過內存映射文件.把整個exe文件映射到這個進程空間的地址空間中(通常是4GB).初始位置可能是0x40000000..
(0x40000000前面的虛擬內存幹什麼用呢..這個加載程序可能會把dll加載到這一部分..也可能閒着不用..如果你需要
使用,就自己用吧..)0x80000000後面通常是操作系統的範圍了..就是一些系統dll和內核代碼了...
②.之後,加載程序會檢查exe文件的導入段...(因爲導入段中包含有dll的相關信息..比如dll名稱..要調用該dll的函
數名稱..等還有時間戳等...)把每個dll都加載到這個進程的地址空間..
③.對於②這個過程可能會是循環的..比如某個dll中又調用的其它的dll中的函數..同樣.這個其它dll中的導入段也
會包含相關dll的一些信息..加載程序同樣也要把其加載進來...例如.a.dll .調用了b.dll 中的add函數..加載程序
在加載a.dll的時候.也會加載b.dll... ..(DLL.和exe文件格式是完全一樣 ...),你不用擔心,,這個過程不會導致死
循環..加載程序會記載每個加載過的dll的....如果已經加載了..是不會再加載的..

④.當加載程序把所有的模塊都加載完畢後..就開始修復對導入符號的引用了..(爲什麼要修復..先把這個過程弄完,
再說...)對導入段中列出的每個符號(即函數)..加載程序會檢查對應dll中的導出表...看該函數是否存在..如果存在
,那麼加載程序會取得該函數的RVA(相對虛擬地址..(DLL.中函數的地址是相對的..通常是相對於0X10000000這個地址
的..另外DLL.中保存的也是相對的虛擬地址..))取得地址後..加載程序通過計算(把rva.加上該DLL被加載的基址)就
得到了該函數在進程空間裏邊的絕對的虛擬地址...這裏..如果DLL重定位了(就是沒有被載入默認的基址.這個位置已
經被佔用了)...還要通過更復雜的算法了...(算法是這樣的..).它會把當前映射的基址減默認的基址 再加上當前加
符號的地址...
接着.加載程序就把這個地址保存在了導入段中了(可能會同時修改代碼中所有對該符號引用的地址.這一點我不清
楚...沒有辦法證明..因爲我看到的彙編代碼都是修復好的...(就是顯示是的絕對的虛擬地址))..好像是什麼
firstThunk吧...剛開始的時候用的是orignalthunk//
吧..我對PE文件格式不是很熟悉...

⑤.之後呢..加載程序就完成了使命了...我們代碼中如果調用了..某個函數..的時候..導入段中已經有了這個函數的
地址了...就能正確的被訪問了...
最後一個問題.就是爲什麼要修復呢...當然不修復也行...能找到符號的地址就不用導入段了...比方說函數的正確地
址硬編碼到指令中..這個是不可能的...比方說系統DLL.但是,每次..系統啓動的時候.映射的位置就不同的...聽說這
是VISTA.的一個特性.ASLR (地址空間佈局隨機化..)...那xp呢..可能沒有問題(同一個XP版本 比如同是SP3).如果
XPSP2..這個地址一般不會相同的.....程序肯定不能運行 ...所以硬編碼肯定不行(程序的移植性更打折扣)..那通常
我們寫程序的時候...都是調用那個符號,其實編譯器是把符號的地址寫進去了.....編譯器需要根據lib文件..(lib文
件中有dll中的函數的相對地址)....中的函數地址址,把我們的符號給替換掉....
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章