PE解析器與加載器編寫指南

PE解析器與加載器編寫指南數組

  最近準備去實習,看公司要求應該開發PE相關的查殺引擎,所以再回頭複習一下PE格式,從新寫一個PE解析器和PE加載器,再此記錄下有關坑。數據結構

PE解析器部分:函數

1)如何肯定節區表spa

  正確計算方法: pSection =  pNtHeader + sizeof(IMAGE_NT_HEADER) 。
設計

  錯誤計算方法:pSection = pFile + sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADER)。
3d

  緣由:DOS_HEADER後面還留有一段數據,並不緊跟着NT_HEADER,所以你這樣計算是錯誤的!blog

    

2)RVA與FOA的轉換內存

  咱們如今是PE解析,其都基於FOA,所以咱們如今只講解RVA->FOA進行轉換,在後面的PELoader這塊,咱們再來分析FOA->RVA。開發

  其分析是基於節表的,循環遍歷節表,判斷其落在相關區間,而後在差值計算,獲得對應的FOA,以下圖:io

  

3)導入表的解析

  導入表是當DLL加載時,根據該PE文件的導入表對其進行修復操做,以後函數找到該函數就能夠找到對應的函數地址。

  如今咱們來回顧一下導入表結構,其導入表結構以下:

  

   若是咱們要獲取整張表的數據,咱們須要創建一個二維數組,對應着兩行數據,所以咱們設計了以下數據結構:

  

  如今,隨之而來的一個問題:如何肯定導入表的個數?PE文件的數據結構彷佛沒有一個數據代表其個數。

  答案是其連續0爲結束,所以咱們申請一塊中間內存進行比較便可。(這種方式在PE文件解析中常常用到)。

  下面就是初始化導入表的代碼,很好理解:

   

4)導出表的解析

  導出表主要是三張子表,函數名稱表,函數序號表,函數地址表,這三張表用一張圖就很好解決。

  

   所以咱們採用以下數據結構存儲:

  

   解析代碼:

  先遍歷函數地址表,地址和序號初始化,名字先設置爲NULL,以後咱們再遍歷名稱和序號表,根據序號將其賦值。

  

 5)重定位的解析

  重定位表構造相對簡單,其sizeOfBlock是加上塊頭部8字節的大小,計算偏移是要注意不要再加多了。

  重定位元素也很簡單,以WORD爲單位,但要注意高4位爲0x3纔有效,修復重定位表時要檢查該位是否有效。

  咱們開始是以下的數據結構:

  

   下面爲重定位表的解析,其依然採用中間變量的方法:

  

 

PE加載器

  PE加載器,就是將一個PE文件映射到本身的內存,而後啓動其main函數運行程序。

  一個PELoader的實現,須要有幾個注意點:修復IAT表;修復重定位表;將內存屬性寫爲可執行。

1)修復IAT表

  這裏有兩個函數 LoadLibrary 和 GetProcAddress,這兩個函數能幫助咱們很好的找到目標函數,其代碼以下:

  

2)修復重定位表

  

3)修改屬性並執行Main函數

  咱們開始將文件映射時,其是隻讀屬性,在修復以後若是執行Main函數會觸發0xc0000005頁權限訪問異常。

  所以咱們須要經過以下代碼將其置爲可執行屬性,固然這裏存在瑕疵,可是咱們只是寫個簡單Demo,也沒太多要求。

  

相關文章
相關標籤/搜索