自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

網(wǎng)絡(luò)安全編程:DLL編程

安全
本文通過(guò)一個(gè)簡(jiǎn)單的DLL程序來(lái)初步了解DLL程序的編寫(xiě)。一起來(lái)看看吧。

 [[384908]]

DLL(Dynamic Link Library,動(dòng)態(tài)連接庫(kù))是一個(gè)可以被其他應(yīng)用程序調(diào)用的程序模塊,其中封裝了可以被調(diào)用的資源或函數(shù)。動(dòng)態(tài)連接庫(kù)的擴(kuò)展名一般是DLL,不過(guò)有時(shí)也可能是其他的擴(kuò)展名。DLL文件屬于可執(zhí)行文件,它符合Windows系統(tǒng)的PE文件格式,不過(guò)它是依附于EXE文件創(chuàng)建的進(jìn)程來(lái)執(zhí)行的,不能單獨(dú)運(yùn)行。一個(gè)DLL文件可以被多個(gè)進(jìn)程所裝載調(diào)用。

Windows操作系統(tǒng)下有非常多的DLL文件,有的是操作系統(tǒng)的DLL文件,有的是應(yīng)用程序的DLL文件。使用DLL文件有什么好處呢?DLL是動(dòng)態(tài)連接庫(kù),相對(duì)應(yīng)地,有靜態(tài)連接庫(kù)。動(dòng)態(tài)連接庫(kù)是在EXE文件運(yùn)行時(shí)被加載執(zhí)行的,而靜態(tài)連接庫(kù)是OBJ文件進(jìn)行連接時(shí)同時(shí)被保存到程序中的。動(dòng)態(tài)連接庫(kù)可以減少可執(zhí)行文件的體積,在需要的時(shí)候進(jìn)入內(nèi)存;將軟件劃分為多個(gè)模塊,可以按照模塊進(jìn)行開(kāi)發(fā),對(duì)于發(fā)布與升級(jí)也非常方便。在某些情況下,必須使用DLL才能完成一些工作內(nèi)容。

本文通過(guò)一個(gè)簡(jiǎn)單的DLL程序來(lái)初步了解DLL程序的編寫(xiě)。

1. 編寫(xiě)簡(jiǎn)單的DLL程序

首先從一個(gè)簡(jiǎn)單的DLL程序開(kāi)始,并在DLL程序中添加一個(gè)導(dǎo)出函數(shù)。所謂導(dǎo)出函數(shù),就是DLL提供給外部EXE或其他類型的可執(zhí)行文件調(diào)用的函數(shù)。當(dāng)然,DLL本身也可以自身進(jìn)行調(diào)用。

DLL程序的入口函數(shù)不是main()函數(shù),也不是WinMain()函數(shù),而是DllMain()函數(shù),該函數(shù)的定義如下: 

  1. BOOL WINAPI DllMain(  
  2.  HINSTANCE hinstDLL, // handle to the DLL module  
  3.  DWORD fdwReason, // reason for calling function  
  4.  LPVOID lpvReserved // reserved  
  5. ); 

參數(shù)說(shuō)明如下。

hinstDLL:該參數(shù)是當(dāng)前 DLL 模塊的句柄,即本動(dòng)態(tài)連接庫(kù)模塊的實(shí)例句柄。

fdwReason:該參數(shù)表示 DllMain()函數(shù)被調(diào)用的原因。

該參數(shù)的取值有4種,也就是說(shuō)存在4種調(diào)用DllMain()函數(shù)的情況,這4個(gè)值分別是DLL_PROCESS_ATTACH(當(dāng)DLL被某進(jìn)程加載時(shí),DllMain()函數(shù)被調(diào)用)、DLL_PRO CESS_DETACH(當(dāng)DLL被某進(jìn)程卸載時(shí),DllMain()函數(shù)被調(diào)用)、DLL_THREAD_ATTACH(當(dāng)進(jìn)程中有線程被創(chuàng)建時(shí),DllMain()函數(shù)被調(diào)用)和DLL_THREAD_DETACH(當(dāng)進(jìn)程中有線程結(jié)束時(shí),DllMain()函數(shù)被調(diào)用)。

lpvReserved:保留參數(shù),即不被程序員使用的參數(shù)。

啟動(dòng)VC6集成開(kāi)發(fā)環(huán)境,創(chuàng)建一個(gè)DLL工程。創(chuàng)建一個(gè)“A simple DLL Project”類型的工程,VC生成代碼如下: 

  1. BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)  
  2.  
  3.   return TRUE;  

在生成的代碼中,函數(shù)定義處有一個(gè)APIENTRY的函數(shù)修飾符。該修飾符為一個(gè)宏,其定義如下:

  1. #define APIENTRY WINAPI 

由于DllMain()函數(shù)不止一次地被調(diào)用,根據(jù)調(diào)用的情況不同,需要執(zhí)行不同的代碼,比如當(dāng)進(jìn)程加載該DLL文件時(shí),可能在DLL中要申請(qǐng)一些資源;而在卸載該DLL時(shí),則需要將先前自身所申請(qǐng)的資源進(jìn)行釋放。出于種種原因,在編寫(xiě)DLL程序時(shí),需要把DllMain()函數(shù)的結(jié)構(gòu)寫(xiě)成如下形式: 

  1. BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)  
  2.  
  3.   switch ( ul_reason_for_call )  
  4.   {  
  5.   case DLL_PROCESS_ATTACH:  
  6.     {  
  7.       break;  
  8.     }  
  9.   case DLL_PROCESS_DETACH:  
  10.     {  
  11.       break;  
  12.     }  
  13.   case DLL_THREAD_ATTACH:  
  14.     {  
  15.       break;  
  16.     }  
  17.   case DLL_THREAD_DETACH:  
  18.     {  
  19.       break; 
  20.     }  
  21.   }  
  22.   return TRUE;  

這是一個(gè)switch/case結(jié)構(gòu),這樣寫(xiě)可以達(dá)到根據(jù)不同的調(diào)用原因執(zhí)行不同的代碼。

2. 給DLL添加一個(gè)簡(jiǎn)單的導(dǎo)出函數(shù)

上面的代碼只是一個(gè)簡(jiǎn)單的DLL程序的開(kāi)始,并沒(méi)有實(shí)際的意義。對(duì)于DLL文件來(lái)說(shuō),DllMain()并不是必需的。按照DLL文件的本質(zhì)作用是為其他的可執(zhí)行文件提供使用,那么DLL程序中需要編寫(xiě)能夠提供其他程序使用的函數(shù),這些公開(kāi)提供給其他程序使用的函數(shù)被稱為導(dǎo)出函數(shù)。在上面代碼的基礎(chǔ)上添加一個(gè)導(dǎo)出函數(shù),定義如下: 

  1. extern "C" __declspec(dllexport) VOID MsgBox(char *szMsg); 

extern "C"表示該函數(shù)以 C 方式導(dǎo)出。由于源代碼是.CPP 文件,因此,如果按照 C++的方式導(dǎo)出的話,那么在編譯后函數(shù)名會(huì)被名字粉碎,導(dǎo)致在動(dòng)態(tài)調(diào)用該函數(shù)時(shí)就會(huì)極為不方便。__declspec(dllexport)的作用是聲明一個(gè)導(dǎo)出函數(shù),將該函數(shù)從本 DLL 中開(kāi)放提供給其他模塊使用。

MsgBox()函數(shù)的實(shí)現(xiàn)如下: 

  1. VOID MsgBox(char *szMsg)  
  2.  
  3.   char szModuleName[MAX_PATH] = { 0 };  
  4.   GetModuleFileName(NULL, szModuleName, MAX_PATH);  
  5.   MessageBox(NULL, szMsg, szModuleName, MB_OK);  

該函數(shù)在被調(diào)用時(shí)會(huì)在MessageBox窗口的標(biāo)題欄處顯示其所在進(jìn)程的進(jìn)程名。

這樣,第一個(gè)DLL文件的編寫(xiě)就完成了。編譯連接該代碼,查看編譯和連接的輸出情況會(huì)發(fā)現(xiàn)VC共生成了2個(gè)文件,分別是“FirstDll.dll”和“FirstDll.lib”,前者是供其他可執(zhí)行程序使用的DLL文件,其中包含了程序員編寫(xiě)的代碼、導(dǎo)出函數(shù),而后者是一個(gè)庫(kù)文件,其中包含一些導(dǎo)出函數(shù)的相關(guān)信息,供調(diào)用DLL文件中導(dǎo)出函數(shù)函數(shù)的程序員編譯時(shí)使用。

導(dǎo)出DLL中的函數(shù)有兩種方法,這是其中的一種。另外一種方式是建立一個(gè).DEF的文件來(lái)定義導(dǎo)出哪些函數(shù)。函數(shù)除了可以通過(guò)函數(shù)名導(dǎo)出外,還可以通過(guò)序號(hào)進(jìn)行導(dǎo)出。建立.DEF文件可以較為方便地管理DLL項(xiàng)目中的導(dǎo)出函數(shù)(總比在代碼中逐個(gè)找__declspec(dllexport)要方便很多)。由于這里的代碼比較短小,因此使用了__declspec(dllexport)這種定義方法。

3. 對(duì)DLL程序的調(diào)用方法一

DLL程序是無(wú)法單獨(dú)運(yùn)行的,它需要通過(guò)編寫(xiě)一個(gè)EXE程序(當(dāng)然也可以在另外的DLL程序中調(diào)用)來(lái)調(diào)用這個(gè)DLL文件中的導(dǎo)出函數(shù)。在VC集成開(kāi)發(fā)環(huán)境中添加一個(gè)測(cè)試項(xiàng)目,在工作區(qū)的“Workspace ‘FirstDll’:1 project(s)”上單擊右鍵,在彈出的菜單中選擇“Add New Project to Workspace”,如圖1所示。

圖1  添加對(duì)DLL進(jìn)行測(cè)試的項(xiàng)目

添加一個(gè)控制臺(tái)的項(xiàng)目,然后編寫(xiě)對(duì)DLL進(jìn)行調(diào)用的測(cè)試代碼,具體如下: 

  1. #include <windows.h>  
  2. #pragma comment (lib, "FirstDll")  
  3. extern "C" VOID MsgBox(char *szMsg);  
  4. int main(int argc, char* argv[])  
  5.  
  6.   MsgBox("Hello First Dll !");  
  7.   return 0; 

#pragma comment (lib, "FirstDll")告訴連接器需要在FirstDll.lib文件中找到DLL中導(dǎo)出函數(shù)的信息。

對(duì)以上代碼進(jìn)行編譯連接,VC會(huì)產(chǎn)生一個(gè)連接錯(cuò)誤,如圖2所示。

圖2  連接出錯(cuò)信息

這個(gè)錯(cuò)誤是因?yàn)檫B接器找不到“FirstDll.lib”文件。將“FirstDll.lib”復(fù)制到測(cè)試項(xiàng)目的目錄下,然后添加到測(cè)試工程中,再次進(jìn)行編譯連接就成功了。運(yùn)行編寫(xiě)好的測(cè)試程序,會(huì)彈出一個(gè)錯(cuò)誤對(duì)話框,如圖3所示。

圖3  運(yùn)行測(cè)試程序時(shí)的錯(cuò)誤信息

根據(jù)錯(cuò)誤提示可以看出是缺少要測(cè)試的DLL文件,也就是“FirstDll.dll”文件。將其復(fù)制到與可執(zhí)行文件相同的目錄下,然后再次運(yùn)行,程序可以順利地被執(zhí)行。

一般在發(fā)布DLL文件時(shí),需要將DLL文件、Lib文件和.h文件同時(shí)發(fā)布,當(dāng)然有一個(gè)說(shuō)明文檔或手冊(cè)會(huì)顯得更加專業(yè)。

4. 對(duì)DLL程序的調(diào)用方法二

前一種方法屬于靜態(tài)調(diào)用,其方式是通過(guò)連接器將DLL函數(shù)的導(dǎo)出函數(shù)寫(xiě)進(jìn)可執(zhí)行文件?,F(xiàn)在使用第二種方法來(lái)調(diào)用DLL中的函數(shù),這種方法相對(duì)于前一種方法是動(dòng)態(tài)調(diào)用。動(dòng)態(tài)調(diào)用不是在連接時(shí)完成的,而是在運(yùn)行時(shí)完成的。動(dòng)態(tài)調(diào)用不會(huì)在可執(zhí)行文件中寫(xiě)入DLL的相關(guān)信息?,F(xiàn)在來(lái)寫(xiě)一個(gè)關(guān)于動(dòng)態(tài)調(diào)用的測(cè)試程序,該程序的創(chuàng)建方法與靜態(tài)調(diào)用的方法相同,這里不再?gòu)?fù)述。

動(dòng)態(tài)調(diào)用DLL函數(shù)的代碼如下: 

  1. #include <windows.h>  
  2. typedef VOID (*PFUNMSG)(char *);  
  3. int main(int argc, char* argv[])  
  4.  
  5.   HMODULE hModule = LoadLibrary("FirstDll.dll");  
  6.   if ( hModule == NULL )  
  7.   {  
  8.     MessageBox(NULL, "FirstDll.dll 文件不存在","DLL 文件加載失敗", MB_OK);  
  9.     return -1;  
  10.   }  
  11.   PFUNMSG pFunMsg = (PFUNMSG)GetProcAddress(hModule, "MsgBox");  
  12.   pFunMsg("Hello First Dll !");  
  13.   return 0;  

對(duì)代碼進(jìn)行編譯連接都正常通過(guò)。但是請(qǐng)注意,這個(gè)程序中并沒(méi)有用到#pragma comment()指令,也沒(méi)有通過(guò)lib在程序中留下相關(guān)的導(dǎo)入信息。運(yùn)行編譯連接好的程序,程序會(huì)給出提示“FirstDll.dll文件不存在”。按照前面的方法,將FirstDll.dll文件復(fù)制到與測(cè)試程序相同的目錄下,運(yùn)行測(cè)試程序,程序執(zhí)行成功。

DLL的動(dòng)態(tài)加載調(diào)用是非常有用的。在第一個(gè)測(cè)試程序中,如果測(cè)試系統(tǒng)的裝載器無(wú)法找到DLL文件,那么系統(tǒng)會(huì)直接報(bào)錯(cuò)而退出。而在第二個(gè)測(cè)試程序中,如果測(cè)試程序無(wú)法找到DLL文件,則由程序給出一個(gè)錯(cuò)誤的提示,同時(shí)程序其實(shí)可以繼續(xù)往下執(zhí)行,而不會(huì)影響其他代碼的運(yùn)行(當(dāng)然,由于DLL無(wú)法加載可能會(huì)損失部分的功能)。明白了動(dòng)態(tài)加載調(diào)用和靜態(tài)加載調(diào)用的區(qū)別,那么它們的優(yōu)缺點(diǎn)就很清楚了。靜態(tài)加載調(diào)用使用方便,而動(dòng)態(tài)加載調(diào)用靈活性較好。

在有些情況下,必須使用動(dòng)態(tài)加載調(diào)用的方法來(lái)使用DLL中的導(dǎo)出函數(shù)。比如函數(shù)OpenThread(),該函數(shù)在VC6自帶的PSDK中沒(méi)有提供LIB文件和函數(shù)原型定義,沒(méi)有LIB文件就無(wú)法連接成功(在新版的PSDK中有該函數(shù)對(duì)應(yīng)的LIB文件)。在這種情況下,只能使用LoadLibrary()和GetProcAddress()這兩個(gè)函數(shù)來(lái)動(dòng)態(tài)加載調(diào)用OpenThread()函數(shù)(其實(shí)有很多情況下,在使用DLL文件中的導(dǎo)出函數(shù)時(shí)是找不到對(duì)應(yīng)的LIB文件的,比如ntdll.dll中的很多函數(shù)雖然有導(dǎo)出,但是系統(tǒng)沒(méi)有提供與其對(duì)應(yīng)的LIB文件)。

現(xiàn)在了解一下LoadLibrary()函數(shù)和GetProcAddress()函數(shù)的定義。LoadLibrary()函數(shù)的定義如下: 

  1. HMODULE LoadLibrary( LPCTSTR lpFileName);  

該函數(shù)只有一個(gè)參數(shù),即要加載的DLL文件的文件名。該函數(shù)調(diào)用成功,則返回一個(gè)模塊句柄。

GetProcAddress()函數(shù)的定義如下: 

  1. FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName);  

該函數(shù)有兩個(gè)參數(shù),分別如下。

hModule:該參數(shù)是模塊句柄,通常通過(guò) LoadLibrary()函數(shù)或 GetModuleHandle()函數(shù)獲得;

lpProcName:該參數(shù)指定要獲得函數(shù)地址的函數(shù)名稱。

該函數(shù)調(diào)用成功,則返回lpProcName指向的函數(shù)名的函數(shù)地址。

5. 查看DLL程序?qū)С龊瘮?shù)的工具介紹

前面介紹DLL編程時(shí)提到了導(dǎo)出函數(shù),這里介紹兩款查看DLL程序的導(dǎo)出函數(shù)的工具。其中一款是VC自帶的工具“Depends”,另一款工具是一個(gè)功能更加強(qiáng)大的可以用來(lái)查看PE結(jié)構(gòu)和識(shí)別加殼信息的工具“PEID”。

首先用“Depends”來(lái)查看DLL的導(dǎo)出函數(shù),該工具可以在VC6的安裝菜單下找到,具體位置為“開(kāi)始”→“程序”→“Microsoft Visual Studio 6.0”→“Microsoft Visual Studio 6.0 Tools”→“Depends”。打開(kāi)該程序,依次單擊菜單項(xiàng)“File”→“Open”,在“打開(kāi)”對(duì)話框中找到所寫(xiě)的FirstDll.dll文件,選中并打開(kāi)(也可以直接進(jìn)行拖曳),其工作窗口中顯示了FirstDll.dll的信息,如圖4所示。

圖4  Depends顯示界面

在圖4的右下角區(qū)域范圍顯示的是該DLL文件導(dǎo)出的函數(shù)。從圖4中可以看出,F(xiàn)irstDll.dll文件只導(dǎo)出一個(gè)MsgBox函數(shù)。

對(duì)于Depends的介紹就這么多,現(xiàn)在來(lái)看另外一個(gè)工具“PEID”。該工具是用來(lái)識(shí)別軟件“指紋”信息(開(kāi)發(fā)環(huán)境、版本、加殼信息等)的。將FirstDll.dll文件拖曳到PEID界面上,PEID會(huì)自動(dòng)解析出該DLL文件的PE結(jié)構(gòu)信息,界面如圖5所示。

圖5  PEID顯示界面

從圖5可以看出,PEID最下方的只讀編輯框中顯示了FirstDll.dll文件是由VC6開(kāi)發(fā)的,并且版本是Debug版本。單擊“子系統(tǒng)”右邊的“大于號(hào)”按鈕,會(huì)顯示PE結(jié)構(gòu)的詳細(xì)信息,如圖6所示。

圖6  PE結(jié)構(gòu)詳情

在圖6中的PE結(jié)構(gòu)詳細(xì)信息的下半部分有個(gè)“目錄信息”,其中的第一個(gè)目錄信息就是導(dǎo)出表信息,單擊“導(dǎo)出表”最右側(cè)的“大于號(hào)”按鈕,出現(xiàn)“導(dǎo)出查看器”界面,如圖7所示。

圖7  導(dǎo)出查看器

從圖7中可以看出,F(xiàn)irstDll.dll文件只有一個(gè)導(dǎo)出函數(shù)MsgBox(),只存在一個(gè)導(dǎo)出項(xiàng)。導(dǎo)出函數(shù)的信息與Depends相同。 

 

責(zé)任編輯:龐桂玉 來(lái)源: 計(jì)算機(jī)與網(wǎng)絡(luò)安全
相關(guān)推薦

2021-01-26 13:45:03

網(wǎng)絡(luò)安全Winsock編程

2021-03-05 13:46:56

網(wǎng)絡(luò)安全遠(yuǎn)程線程

2021-02-23 10:20:07

網(wǎng)絡(luò)安全進(jìn)程代碼

2021-02-21 18:19:43

網(wǎng)絡(luò)安全網(wǎng)絡(luò)安全編程創(chuàng)建進(jìn)程

2016-10-10 00:18:27

2021-03-01 11:20:13

網(wǎng)絡(luò)安全多線程代碼

2021-06-18 09:55:09

網(wǎng)絡(luò)安全目錄監(jiān)控

2021-04-26 10:32:38

網(wǎng)絡(luò)安全PE編程工具

2021-06-15 11:16:24

網(wǎng)絡(luò)安全U盤(pán)軟件

2021-04-19 10:26:41

網(wǎng)絡(luò)安全PE文件

2021-02-04 10:50:11

網(wǎng)絡(luò)安全非阻塞模Winsock編程

2021-06-24 08:37:34

網(wǎng)絡(luò)安全內(nèi)核代碼

2021-05-12 14:57:13

網(wǎng)絡(luò)安全密碼代碼

2021-05-24 11:55:55

網(wǎng)絡(luò)安全Windows鉤子函數(shù)

2021-04-30 18:50:44

網(wǎng)絡(luò)安全PE編程添加節(jié)區(qū)

2021-04-28 14:35:48

網(wǎng)絡(luò)安全PE編程代碼

2021-04-25 21:25:09

網(wǎng)絡(luò)安全網(wǎng)絡(luò)安全編程PE編程

2021-01-18 10:35:18

網(wǎng)絡(luò)安全Windows代碼

2021-02-07 10:55:01

網(wǎng)絡(luò)安全文件API

2022-10-08 07:30:17

網(wǎng)絡(luò)安全編程語(yǔ)言C++
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)