ImageVerifierCode 换一换
格式:DOCX , 页数:18 ,大小:102.27KB ,
资源ID:11337315      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/11337315.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(8 动态链接库的载入分析.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

8 动态链接库的载入分析.docx

1、8 动态链接库的载入分析第八章 動態連結程式庫的載入分析 動態連結程式庫 (DLL) 一直以來都是Windows的重要基礎,Windows CE也不例外。DLL對作業系統十分重要,本節的內容主要是分析loader.c中的程式碼,它負責載入EXE和DLL。這裏要討論的是關於DLL的部分,如無特別說明,本章中所引用的程式碼,都是來自Windows CE原始程式碼樹中的CEROOTPRIVATEWINCEOSCOREOSNKKERNELloader.c。8.1 loader.c中程式碼的組織結構 loader.c主要透過以下的API函數,來完成NK核心載入EXE和DLL處理程序的工作,這是使用者程式

2、對DLL和EXE程式操作的進入點。之後再透過一系列的函數呼叫,來完成DLL和EXE的載入和卸載,以及對處理程序和執行緒的其他操作。由於我們現在要討論的是有關DLL的部分,所以只列出了部分函式。 Win32 LoadLibrary call HANDLE SC_LoadLibraryW(LPCWSTR lpszFileName) HINSTANCE SC_LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) HANDLE SC_LoadDriver(LPCWSTR lpszFileName) HANDLE SC_Lo

3、adKernelLibrary(LPCWSTR lpszFileName) HANDLE SC_LoadIntChainHandler(LPCWSTR lpszFileName, LPCWSTR lpszFunctionName, BYTE bIRQ)這幾個函數基本上都是負責DLL的載入,它們都呼叫了LoadOneLibraryW這個函數,函數的原型如下: HANDLE LoadOneLibraryW(LPCWSTR lpszFileName, DWORD fLbFlags, WORD wFlags)這個函數在載入DLL的前後,處理一些必要的細節工作。更重要的是呼叫了LoadOneLibrar

4、yPart2這個函數,載入的重要工作都在該函數的程式碼中完成,在本章的後面會詳細分析它的內容。 Win32 FreeLibrary call HANDLE SC_FreeIntChainHandler(HANDLE hLib) BOOL SC_FreeLibrary(HANDLE hInst)主要是FreeLibrary函數。這個API函數負責卸載DLL。它呼叫FreeOneLibrary這個函數,函數原型如下: BOOL FreeOneLibrary(PMODULE pMod, BOOL bCallEntry)卸載的過程主要是由FreeOneLibraryPart2負責。在後面的章節會有具體

5、的分析。 Win32 GetProcAddress call LPVOID SC_GetProcAddressA(HANDLE hInst, LPCSTR lpszProc) LPVOID SC_GetProcAddressW(HANDLE hInst, LPCSTR lpszProc)這兩個函數可以得到處理程序的位址。8.2 module structure 這是記錄DLL資訊的重要資料結構之一,每一個程式對應一個module,但一個module可以對應多個處理程序。在系統中維持一條已載入模組的串列,它是一個單向鏈結串列。第一個元素是pModList。程式碼8.1 module struct

6、uretypedef struct Module LPVOID lpSelf; PMODULE pMod; LPWSTR lpszModName; DWORD inuse; DWORD calledfunc; WORD refcntMAX_PROCESSES; LPVOID BasePtr; DWORD DbgFlags; LPDBGPARAM ZonePtr; ulong startip; openexe_t oe; e32_lite e32; o32_lite *o32_ptr; DWORD breadcrumb; DWORD dwNoNotify; WORD wFlags; BYTE b

7、TrustLevel; BYTE bPadding; PMODULE pmodResource; DWORD rwLow; DWORD rwHigh; Module;/* 用於驗證,指向自己的指標 */* 鏈結串列中的下一個模組 */* 模組名字 */* 使用狀況的位元向量 */* 被呼叫的進入點,但不退出 */* 處理程序的引用計數 */* DLL載入基址 */* 偵錯旗標 */* Debug zone 指標 */* 基於0的進入點 */* 執行檔指標 */* e32標頭 */* O32串列指標 */* 每個處理程序對應一個位元,當Notify被禁用時設為1 */* 包含資源的模組 */*

8、ROM DLL中可讀寫段的基底位址 */* ROM DLL中可讀寫段的高位位址 */ refcntMAX_PROCESSES是每個處理程序的引用計數。BasePtr是DLL載入的基底位址,這是比較需要注意的部分。oe、e32、*o32_ptr放在後面介紹。8.3 LoadOneLibraryPart2載入DLL的過程呼叫LoadOneLibraryPart2 圖8.1 LoadOneLibraryPart2的基本執行步驟 函數原型: PMODULE LoadOneLibraryPart2(LPWSTR lpszFileName, DWORD fLbFlags,WORD wFlags)參數lps

9、zFileName指向DLL名字的字串,該名字確定了模組 (module) 的檔案名稱,而與它儲存在模組庫中的名字無關。函式庫模組以LIBRARY為關鍵字,在模組定義檔 (.def) 中定義。參數hFile是保留做將來使用的,現在必須是NULL。參數wFlags指定載入模組時所要處理的工作。其值可以為0、DONT_RESOLVE_DLL_REFERENCES、LOAD_LIBRARY_AS_DATAFILE或者是LOAD_LIBRARY_IN_KERNEL。DONT_RESOLVE_DLL_REFERENCE:如果使用這個旗標,而且可執行模組本身是一個DLL,則系統並不呼叫DllMain來初始

10、化和結束處理程序和執行緒。此外,一個DLL可能會引入包含在另一個DLL中的函數,而系統映射一個DLL時也會自動載入,當這個旗標被設置之後,系統就不再自動載入額外的DLL。載入過程如圖8.1所示。 載入的過程首先設定wFlags的值,然後呼叫pMod = FindModByName(dllname),藉由查找pModList串列,來得到DLL的pMod指標。對於已經載入的module,增加其引用次數。由以下的程式碼來完成: if (!(pMod-inuse & (1procnum) pMod-inuse |= (1procnum); pMod-calledfunc &= (1procnum);

11、return pMod-refcntpCurProc-procnum+;呼叫該module的處理程序是目前的處理程序。將目前處理程序對該module的引用計數加一,傳回pMod,便完成了載入的過程。如果module之前並未載入,則需要一系列的工作:1) 為module配置記憶體2) 初始化module,呼叫InitModule3) 增加引用計數4) 將這個新的pMod插入module鏈結串列中,作為第一個元素。程式碼如下: EnterCriticalSection(&ModListcs); pMod-pMod = pModList; pModList = pMod; LeaveCritical

12、Section(&ModListcs)8.4 DLL載入過程 InitModule的執行 InitModule處理載入一個新的DLL所要做的大部分工作。函數原型如下: DWORD InitModule (PMODULE pMod, LPWSTR lpszFileName, LPWSTR lpszDllName, DWORD fLbFlags, WORD wFlags)在函數InitModule中,具體執行步驟如下:1) 初始化pMod中的欄位 (field)2) 呼叫函數OpenADll,產生執行檔指標 (openexe_t)3) 載入 module的e32 資訊,產生e32標頭資訊 (e32

13、_lite)4) 檢查bTrust level參數5) 配置記憶體給DLL,取得Module-BasePtr,即載入DLL的基底位址6) 配置記憶體給name 和O32 物件,讀取這個module的O32資訊7) 改變module的名字8) 重定位映射9) 呼叫函數FindEntryPoint ,找到EXE的起始IP (或者DLL的進入點) 整體來說,這個函數就是負責設定pMod各個欄位的初始值、取得可執行檔的指標以及EXE或DLL的進入點。在這個過程中,將各個步驟、判斷中的錯誤碼,傳回給LoadOneLibraryPart2,用來作為判斷pMod是否建立成功的資訊,以繼續以後的工作。下面,將

14、對這幾個重要步驟作詳細分析。8.4.1呼叫OpenADll,產生執行檔指標 (openexe_t) module中的oe是可執行檔的指標,每個程式對應一個module,每個module對應一個可執行檔指標。oe的型別openexe_t定義如下:程式碼8.2 openexe_t structuretypedef struct openexe_t union int hppfs; HANDLE hf; TOCentry *tocptr; ; BYTE filetype; BYTE bIsOID; WORD pagemode; DWORD offset; union Name *lpName; CE

15、OID ceOid; ; openexe_t;/ ppfs handle/ 物件儲存指標/ rom entry pointer/檔案類型/分頁模式/偏移這實際上是與檔案處理等有關的結構,描述可執行程式碼的位址、分頁模式、偏移等資訊。OpenADll呼叫OpenExe,由OpenExe呼叫SafeOpenExe,設定可執行檔指標的工作基本上都在SafeOpenExe中完成。 BOOL SafeOpenExe(LPWSTR lpszName, openexe_t *oeptr, BOOL bIsDLL, BOOL bAllowPaging, OEinfo_t *poeinfo)SafeOpenEx

16、e還執行以下的工作:1) 尋找EXE檔案所在的目錄2) 按照指定路徑尋找檔案3) 在Windows目錄中尋找檔案4) 在根目錄中尋找檔案在檔案系統中搜尋DLL檔案時,根據搜尋過程中的資訊設定其中各個欄位的值。並藉由下面的程式碼取得檔案的儲存指標:oeptr-hf=CreateFileW(LPWSTR)poeinfo-tmpname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);即透過CreateFile開啟檔案。如果在ROM中有備份,則設定oeptr-tocptr的值。傳回結果:如果找到,則傳回1,否則傳回0。8.4.2設定mo

17、dule的e32 標頭資訊 module的成員e32的型別定義如下:程式碼8.3 e32_lite structuretypedef struct e32_lite unsigned short e32_objcnt; BYTE e32_cevermajor; BYTE e32_ceverminor; unsigned long e32_stackmax; unsigned long e32_vbase; unsigned long e32_vsize; unsigned long e32_sect14rva; unsigned long e32_sect14size; structinfo

18、e32_unitLITE_EXTRA; e32_lite, *LPe32_list;/* PE 32-bit .EXE header */* 記憶體物件個數 */* 版本資訊 */* 版本資訊 */* 堆疊的最大值 */* module的虛擬記憶體基底位址 */* 整個映射的Virtual 大小 */* section 14 rva */* section 14 size */* Array of extra info units */這是與記憶體相關的一組資料,在InitModule中有一段程式碼如下: / load O32 info for the module eptr = &pMod-

19、e32; if (retval = LoadE32(&pMod-oe, eptr, &flags, &entry, (pMod-wFlags & LOAD_LIBRARY_AS_DATAFILE) ? 1 : 0, bAllowPaging, &pMod-bTrustLevel) return retval; 它藉由呼叫LoadE32函數讀取DLL檔,設定e32標頭的各部分內容,設定堆疊、虛擬記憶體基底位址、映射等正確的值,使接下來DLL的記憶體配置工作能夠順利進行。8.4.3 DLL的記憶體配置與Module-BasePtr的取得 InitModule中的這一部分程式碼的主要作用是設定pMo

20、d-BasePtr。為了方便解釋,圖8.2是簡化的流程圖。是圖8.2 DLL配置記憶體的過程 由可執行檔指標pMod-oe.filetype可得到檔案類型。DLL有兩種映射,一種是普通檔案,需要將其載入到RAM中執行。為了節省時間,還有另一種方式就是XIP (Execute in place) 方式。顧名思義,就是可以立即執行,而不用載入RAM中,所以相應pMod-BasePtr的值也有兩種不同的情況。如果不是XIP (Execute in place) DLL,則保留足夠的虛擬記憶體位址空間以容納整個映射。從已經存在的DLL的底部開始由上往下分配。 DLL載入到核心位址空間 (kernel

21、space) 或是使用者空間 (user space) 也有差別。對於載入核心位址空間的DLL,必須為其取得連續的實體頁面。因為核心空間位址和虛擬記憶體位址之間是靜態映射的,這是為了讓核心執行時,不必進行位址的轉換,藉以加快核心的執行。例如在Platform Builder 下產生的platform,啟動時載入的features等就是載入核心的DLL。 if (wFlags & LOAD_LIBRARY_IN_KERNEL) PHYSICAL_ADDRESS paRet; / Loading in the kernel address space paRet = GetContiguousPa

22、ges(DWORD) (eptr-e32_vsize + PAGE_SIZE - 1) / PAGE_SIZE, 0, 0); if (paRet = INVALID_PHYSICAL_ADDRESS | !(pMod-BasePtr = (PVOID) Phys2Virt(paRet) return ERROR_OUTOFMEMORY; 它先向系統要求連續的實體位址頁面,取得實體位址,再將其直接映射到虛擬位址空間,並把虛擬記憶體位址傳給pMod-BasePtr。有關GetContiguousPages及Phys2Virt的細節請參考其他的原始檔案。如果不是載入核心位址空間,則必須為其保留位址

23、空間,以避免其他DLL載入同樣的位址空間,而使該DLL的卸載發生問題。程式碼如下: else / try to honor the Dlls relocation base to prevent relocation if (pTOC-ulKernelFlags & KFLAG_HONOR_DLL_BASE) & (eptr-e32_vbase + eptr-e32_vsize BasePtr = VirtualAlloc (LPVOID)(ProcArray0.dwVMBase + eptr-e32_vbase), eptr-e32_vsize, MEM_RESERVE | MEM_IMAG

24、E, PAGE_NOACCESS); DEBUGMSG (pMod-BasePtr, (LLoading DLL %s at the preferred loading address %8.8lxn, lpszFileName, ZeroPtr (pMod-BasePtr); 其中,eptr-e32_vbase是module映射的虛擬記憶體基底位址,eptr-e32_vsize是module的虛擬記憶體大小。利用VirtualAlloc在目前處理程序的虛擬記憶體位址空間保留一個區域,基底位址是處理程序位址空間基底位址ProcArray0.dwVMBase + module映射的虛擬記憶體基底

25、位址。大小受模組影響。它使用參數MEM_RESERVE | MEM_IMAGE,只保留了處理程序的一部分虛擬記憶體空間,而沒有實際分配實體記憶體。而且這部分空間不能透過其他記憶體配置的操作如malloc和LocalAlloc使用,也不能被其他DLL佔用。如果配置基底位址時,發現要使用的區域已經被保留,即已經有其他DLL佔用,造成配置虛擬記憶體失敗,則由上往下配置。 / allocate top-down if we cant load it in the dlls preferred load base. if (!pMod-BasePtr & !(pMod-BasePtr = Virtual

26、Alloc (LPVOID) ProcArray0. dwVMBase,eptr-e32_vsize, MEM_RESERVE | MEM_TOP_DOWN | MEM_IMAGE, PAGE_NOACCESS) return ERROR_OUTOFMEMORY; 配置的基底位址是目前處理程序的虛擬記憶體空間基底位址,大小不變,只是由上往下配置。這樣就得到了pMod-BasePtr。下面的程式碼修改DLL的載入基址,這是個全域變數。 if (ZeroPtr(pMod-BasePtr) BasePtr);如果要載入的DLL是XIP的,即表示它是在ROM中,不需載入到處理程序位址空間,如cored

27、ll.dll就是XIP型的DLL。只需在ROM中找到要執行的DLL的基底位址,傳給pMod-BasePtr即可,如以下程式碼所示: else e32_rom *e32rp = (e32_rom *) pMod-oe.tocptr-ulE32Offset; pMod-BasePtr = (LPVOID) MapPtrProc (e32rp-e32_vbase, ProcArray); if (wFlags & LOAD_LIBRARY_IN_KERNEL) & !IsKernelVa (pMod-BasePtr) return ERROR_BAD_EXE_FORMAT; 8.4.4 name和o

28、32物件的記憶體配置 o32物件是與存取控制有關的物件。結構定義如下。 typedef struct o32_lite unsigned long o32_vsize; unsigned long o32_rva; unsigned long o32_realaddr; unsigned long o32_access; unsigned long o32_flags; unsigned long o32_psize; unsigned long o32_dataptr; o32_lite, *LPo32_lite;8.4.5 重定位映射 非XIP映射需要重新定址 (Relocate)。 if

29、 (pMod-oe.filetype != FT_ROMIMAGE) / / Non-XIP image needs to be relocated. / if (pMod-oe.pagemode = PM_NOPAGING) & !(pMod-wFlags & LOAD_LIBRARY_AS_DATAFILE) & !Relocate (eptr, pMod-o32_ptr, (ulong)pMod-BasePtr, (wFlags & LOAD_LIBRARY_IN_KERNEL) ? 0 : ProcArray0.dwVMBase) return ERROR_OUTOFMEMORY; 這

30、裏呼叫Relocate對 DLL重新定址,傳遞的參數為:可執行檔指標eptr,o32標頭資訊pMod-o32_ptr,DLL載入的基底位址pMod-BasePtr,如果DLL載入到核心,則最後一個參數為0,否則傳遞的參數是目前處理程序虛擬記憶體空間的基址。這裏還需要解釋一下重新定址 (Relocate) 的過程。重新定址的過程,是將DLL映射位址定位到目前處理程序的位址空間,即位址0x00000000-0x02000000,從0x01FFFFFF開始由上往下,最頂端是coredll.dll,然後是其他DLL。 如果是XIP映射,即DLL在ROM中。如果module被載入記憶體的Slot1 (DLL高位址區域),或者載入到核心中,則需要記錄為這個module而定址的讀寫區。程式碼如下: o32_lite *optr =

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1