第二十章 DLL高級(jí)技巧
1.概覽
?1.1動(dòng)態(tài)加載DLL文件 LoadLibraryEx
??????????????? HMODULE LoadLibraryEx(
PCTSTR pszDLLPathName,
HANDLE hFile,
DWORD dwFlags);
????????????? 返回DLL加載到進(jìn)程空間原首地址。
????????????? dwFlags 可以有以下幾個(gè)值
????????????? (1) DONT_RESOLVE_DLL_REFERENCES
?????????????????????????????
建議永遠(yuǎn)不要使有這個(gè)值,它的存在僅僅是為了向后兼容、
????????????????????????????? 更多內(nèi)容請(qǐng)?jiān)L問(wèn):http://blogs.msdn.com/oldnewthing/archive/2005/02/14/372266.aspx
????????????? (2) LOAD_LIBRARY_AS_DATAFILE
????????????????????????????? 把要加載的DLL文件以數(shù)據(jù)文件的形式加載到進(jìn)程中。
????????????????????????????? GetModuleHandle和GetProcAddress返回NULL
????????????? (3) LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
????????????????????????????? 與前者相同,不同的時(shí)獨(dú)占打開(kāi),禁止其它進(jìn)程訪問(wèn)和修改該DLL中的內(nèi)容。
????????????? (4) LOAD_LIBRARY_AS_IMAGE_RESOURCE
????????????????????????????? 不修改DLL中的RVA,以image的形式加載到進(jìn)程中。常與LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE一起使用。
????????????? (5) LOAD_WITH_ALTERED_SEARCH_PATH
????????????????????????????? 修改DLL的加載路徑
?
1.2 DLL
的加載與卸載
????????????? (1)加載
????????????????????????????? 不要在同一進(jìn)程中,同時(shí)使用LoadLIbrary和LoadLibraryEx加載同一DLL文件。
????????????????????????????? DLL的引用計(jì)數(shù)是以進(jìn)程為單位的。LoadLibrary會(huì)把DLL文件加載到內(nèi)存,然后映射到進(jìn)程空間中。
????????????????????????????? 多次加載同一DLL只會(huì)增加引用計(jì)數(shù)而不會(huì)多次映射。當(dāng)所有進(jìn)程對(duì)DLL的引用計(jì)數(shù)都為0時(shí),系統(tǒng)會(huì)在內(nèi)存中釋放該DLL。
????????????? (2)卸載
????????????????????????????? FreeLibrary,FreeLibraryAndExitThread對(duì)當(dāng)前進(jìn)程的DLL的引用計(jì)數(shù)減1
????????????? (3) GetProcAddress
????????????????????????????? 取得函數(shù)地址。它只接受ANSI字符串。
2.DLL的入口函數(shù)
??????????????? 2.1 DllMain
????????????? BOOL WINAPI DllMain(
????????????? HINSTANCE hInstDll, ""加載后在進(jìn)程中的虛擬地址
????????????? DWORD fdwReason, ""系統(tǒng)因何而調(diào)用該函數(shù)
????????????? PVOID fImpLoad ""查看是隱工還是動(dòng)態(tài)加載該DLL
?
????????????? DLLs用DllMain方法來(lái)初始化他們自已。DllMain中的代碼應(yīng)盡量簡(jiǎn)單,只做一些簡(jiǎn)單的初始化工作。
????????????? 不要在DllMain中調(diào)用LoadLibrary,FreeLibrary及Shell, ODBC, COM, RPC, 和 socket 函數(shù),從而避免不可預(yù)期的錯(cuò)誤。
?
??????????????? 2.2 fdwReason的值
????????????? ?(1)DLL_PROCESS_ATTACH
????????????? ?系統(tǒng)在為每個(gè)進(jìn)程第一次加載該DLL時(shí)會(huì),執(zhí)行DLL_PROCESS_ATTACH后面的語(yǔ)句來(lái)初始化DLL,DllMain的返回值僅由它決定。
?系統(tǒng)會(huì)忽略DLL_THREAD_ATTACH等執(zhí)行后DllMain的返回值。
????????????? ?如果DllMain返回FALSE,系統(tǒng)會(huì)自動(dòng)調(diào)用DLL_PROCESS_DETACH的代碼并解除DLL文件中進(jìn)程中的內(nèi)存映射。
????????????? ?
????????????? ?(2)DLL_PROCESS_DETACH
????????????????????????????? 如果DLL是因進(jìn)程終止而卸載其在進(jìn)程中的映射,那么負(fù)責(zé)調(diào)用ExitProcess的線程會(huì)調(diào)用DllMain中DLL_PROCESS_DETACH所對(duì)應(yīng)的代碼。
????????????????????????????? 如果DLL是因FreeLibrary或FreeLibraryAndExitThread,而卸載其在進(jìn)程中的映射,
那么FreeLibrary或FreeLibraryAndExitThread會(huì)負(fù)責(zé)調(diào)用DllMain中DLL_PROCESS_DETACH所對(duì)應(yīng)的代碼。
????????????????????????????? 如果DLL是因TerminateProcess而卸載其在進(jìn)程中的映射,系統(tǒng)不會(huì)調(diào)用DllMain中DLL_PROCESS_DETACH所對(duì)應(yīng)的代碼。
????????????? (3) DLL_THREAD_ATTACH
????????????????????????????? 若進(jìn)程是先加載的DLL,后創(chuàng)建的線程
????????????????????????????????????????????? 那么在進(jìn)程中創(chuàng)建新線程時(shí)(主線程除外),系統(tǒng)會(huì)執(zhí)行該進(jìn)程已載的所有DLL的DllMain中DLL_THREAD_ATTACH對(duì)應(yīng)的代碼。
????????????????????????????? 若進(jìn)程是先創(chuàng)建的線程,后加載的DLL
????????????????????????????????????????????? 那么系統(tǒng)不會(huì)調(diào)用DLL的DllMain中的代碼。
????????????? (4) DLL_THREAD_DETACH
????????????? ??????????????? 進(jìn)程中的線程退出時(shí),會(huì)先執(zhí)行所有已加載DLL的DllMain中DLL_THREAD_DETACH所對(duì)應(yīng)的代碼。若該代碼中有死循環(huán),線程不會(huì)退出。
?????????????
?2.3 同步化DllMain的調(diào)用
????????????? 同一時(shí)間只能有一個(gè)線程調(diào)用DllMain中的代碼,所以下面的代碼會(huì)導(dǎo)致死循環(huán)
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, PVOID fImpLoad) {
?
?? HANDLE hThread;
?? DWORD dwThreadId;
?
?? switch (fdwReason) {
?? case DLL_PROCESS_ATTACH:
????? // The DLL is being mapped into the process' address space.
?
????? // Create a thread to do some stuff.
????? hThread = CreateThread(NULL, 0, SomeFunction, NULL,
???????? 0, &dwThreadId);// CreateThread會(huì)DLL_THREAD_ATTACH中的代碼,但是由于當(dāng)前線程并未執(zhí)行完畢,
//所以DLL_THREAD_ATTACH中的代碼不會(huì)被執(zhí)行,且CreateThread永無(wú)不會(huì)返回。
?
????? // Suspend our thread until the new thread terminates.
????? WaitForSingleObject(hThread, INFINITE);
?
????? // We no longer need access to the new thread.
????? CloseHandle(hThread);
????? break;
?
?? case DLL_THREAD_ATTACH:
????? // A thread is being created.
????? break;
?
?? case DLL_THREAD_DETACH:
????? // A thread is exiting cleanly.
????? break;
?
?? case DLL_PROCESS_DETACH:
????? // The DLL is being unmapped from the process' address space.
????? break;
?? }
?? return(TRUE);
}
?
3.延時(shí)加載DLL
(1)延時(shí)加載DLL的限制
????????????? 延時(shí)加載是指當(dāng)程序在運(yùn)行時(shí)用到DLL中的函數(shù)時(shí)自動(dòng)會(huì)自動(dòng)加載DLL函數(shù),它與動(dòng)態(tài)加載不同。
????????????? http://msdn2.microsoft.com/en-us/library/yx1x886y(VS.80).aspx
?
4.已知的DLL (Known DLLs)
????????????? 位置:HKEY_LOCAL_MACHINE"SYSTEM"CurrentControlSet"Control"Session Manager"KnownDLLs
????????????? LoadLibrary在查找DLL會(huì)先去該位置查找有無(wú)相應(yīng)的鍵值與DLL要對(duì)應(yīng),若有則根據(jù)鏈值去%SystemRoot%"System32加載鍵值對(duì)應(yīng)的DLL
????????????? 若無(wú)則根據(jù)默認(rèn)規(guī)去尋找DLL
?
5.Bind and Rebase Module
????????????? 它可以程序啟動(dòng)的速度。ReBaseImage