日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

PE文件和COFF文件格式分析——导出表的应用——一种插件模型

發布時間:2023/11/27 生活经验 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PE文件和COFF文件格式分析——导出表的应用——一种插件模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 可能在很多人想想中,只有DLL才有導出表,而Exe不應該有導出表。而在《PE文件和COFF文件格式分析——導出表》中,我卻避開了這個話題。我就是想在本文中討論下載Exe中存在導出表的場景。(轉載請指明出于breaksoftware的csdn博客)

? ? ? ? 首先要說的是Exe是可以有導出表的,我用我寫的PE分析工具掃描了我電腦上所有文件。發現有導出表的Exe文件還不少。比如chrome.exe。

? ? ? ? 還有OllyDBG.EXE。

? ? ? ? 我一開始還不能理解為什么要在Exe中搞導出函數。后來查了相關資料,發現這樣做是為了方便開發插件,這讓我一下煥然大悟。

? ? ? ? 現在思考一個過程,我們的Exe程序的邏輯可能需要若干Dll中函數來輔助。如下圖

? ? ? ? A.exe需要B.dll、C.dll和D.dll輔助?,F在我們要支持插件,那么我們需要提供一些接口函數供插件使用。比如我們要提供B1()、C1()和D1()供插件使用,那如何設計呢?

? ? ? ? 最簡單的辦法就是不做設計,插件要動態LoadLibrary我們的B.dll、C.dll和D.dll,然后把各個函數導出來用??此坪芊奖?#xff0c;但是如果我們工程不止是3個Dll呢?暴露的函數也不止這三個呢?我想做這個系統的插件的同學想到要Load那么多DLL就會感覺煩!而且還有一個嚴重的問題,哪天我們想給B.dll改個名字,叫E.dll,那么使用B.dll的插件都不能正常工作了??梢砸姷眠@是個非常不穩定的方案,因為它關聯的因素太多了。

? ? ? ? 那我們收斂一下方案,我們做個空殼DLL(使用《PE文件和COFF文件格式分析——導出表》介紹的類似于Kernel32.dll的AddVectoredExceptionHandler導出方法,這個方法的應用我會在之后寫篇文章介紹),該DLL就導出B.dll中B1()、C.dll中C1()和D.dll中D1()的入口地址。然后插件就加載這個DLL,調用該DLL中的方法。如下圖

? ? ? ? 這樣就很好解決了之前的不足。貌似離最佳不遠了,但是想想,是不是還可以優化呢?我們這么設計要多維護一個DLL(PluginHelper.dll),這個也就引入了一個不穩定因素。那么這個DLL可以省掉么?省掉后導出的那些函數放哪兒?

? ? ? ? 經過考慮,PluginHelper.dll的功能放在哪個DLL文件中都不合適。那只能放在A.exe中了。是的!我們讓A.exe導出函數,反正我們A.exe也是要加載B.dll、C.dll和D.dll,這樣還可以省下PluginHelper.dll加載如上DLL的過程?,F在我寫了一個工程,模擬這種插件模型。

? ? ? ? ExeMain是我們的主程序,DllOne和DllTwo是ExeMain需要加載的DLL,它們也提供了插件需要暴露給插件的函數的實現。Plugin是個插件。

? ? ? ?我們先看下DLLOne和DllTwo的導出函數

LIBRARY	"DllOne"
EXPORTSRet1
LIBRARY	"DllTwo"
EXPORTSRet2

? ? ? ? 那么在Exe中如何暴露這兩個函數呢?看Exe中的代碼

typedef int (WINAPI* RetNFunc)();extern "C" __declspec(dllexport) int MainRet1();
extern "C" __declspec(dllexport) int MainRet2();int MainRet1(){int nRet = 0;HMODULE hDllOne = LoadLibraryA("DllOne.dll");do {if ( NULL == hDllOne ) {break;}RetNFunc pFunc = (RetNFunc)GetProcAddress( hDllOne, "Ret1" );nRet = pFunc();FreeLibrary( hDllOne );hDllOne = NULL;} while (0);return nRet;
}int MainRet2(){int nRet = 0;HMODULE hDllTwo = LoadLibraryA("DllTwo.dll");do {if ( NULL == hDllTwo ) {break;}RetNFunc pFunc = (RetNFunc)GetProcAddress( hDllTwo, "Ret2" );pFunc();FreeLibrary( hDllTwo );hDllTwo = NULL;} while (0);return nRet;
}

? ? ? ? 我們看下Exe的導出函數表

? ? ? ? 至于插件的調用,我這兒不準備搞復雜的設計,我這兒將直接Load插件DLL,并調用DLL中的導出方法(該方法的調用約定是提前確定好的)。調用方法是

typedef void (WINAPI* PluginFunc)();
int _tmain(int argc, _TCHAR* argv[])
{HMODULE hPlugin = LoadLibraryA("Plugin.dll");do {if ( NULL == hPlugin ) {break;}PluginFunc pFunc = (PluginFunc)GetProcAddress( hPlugin, "PluginMain" );pFunc();FreeLibrary( hPlugin );hPlugin = NULL;} while (0);system("pause");return 0;
}

? ? ? ? 那么插件該如何寫呢?插件的邏輯代碼如下

LIBRARY	"Plugin"
EXPORTSPluginMain

?

?

typedef int (WINAPI* RetNFunc)();void PluginMain() {RetNFunc pFun1 = (RetNFunc)GetProcAddress( GetModuleHandle(NULL), "MainRet1" );if ( NULL != pFun1 ) {printf( "MainRet1: %d\n", pFun1() );}RetNFunc pFun2 = (RetNFunc)GetProcAddress( GetModuleHandle(NULL), "MainRet2" );if ( NULL != pFun2 ) {printf( "MainRet2: %d\n", pFun2());}
}

? ? ? ? 因為插件DLL已經被Exe加載,所以此處GetModuleHandle(NULL)會得到該進程Exe的模塊句柄,GetProcAddress該句柄的導出方法,就可以獲得了Exe中導出的函數入口地址了。

? ? ? ? 看!這樣的插件模型是不是非常簡單而且緊湊而且易用。

? ? ? ? 附上工程

總結

以上是生活随笔為你收集整理的PE文件和COFF文件格式分析——导出表的应用——一种插件模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。