天天看點

PE檔案靜态注入

DLL注入指的是向運作中的其他程序強制插入特定的DLL檔案。

可以通過修改靜态的PE檔案,修改輸入表結構,使得程式執行時載入特定的DLL檔案。

通常可執行檔案需要使用其他DLL檔案中的代碼或資料,這些DLL檔案相關的資訊會儲存在輸入表中,是以我們通過修改PE檔案中輸入表相應的資訊,即可實作PE檔案在運作時自動載入特定的DLL檔案。

pe結構分析之手工段表建構--該實驗,明确段結構在windows PE程式中的作用,掌握段在檔案和記憶體中加載的過程。實操請複制下方連結

https://www.hetianlab.com/expc.do?ce=d5bc0c11-a182-474b-8ac1-251194174436?pk_campaign=weixin-wemedia#stu

使用PEview工具可以清晰的看到程式輸入表的資訊

PE檔案靜态注入

【——全網最全的網絡安全學習資料包分享給愛學習的你,關注我,私信回複“領取”擷取——】

1.網絡安全多個方向學習路線

2.全網最全的CTF入門學習資料

3.一線大佬實戰經驗分享筆記

4.網安大廠面試題合集

5.紅藍對抗實戰技術秘籍

6.網絡安全基礎入門、Linux、web安全、滲透測試方面視訊

輸入表

由于需要修改輸入表資訊,是以這裡簡單介紹一下輸入表的結構。

在PE檔案的可選頭中存在這資料目錄項, 裡面記載了輸出表、輸入表等關鍵資訊的偏移及大小。那麼理所當然的PE檔案在執行時也會通過資料目錄項裡的資訊去找尋輸入表。

PE檔案靜态注入

輸入表是由IMAGE_IMPORT_DESCRIPTOR結構的數組組成,簡稱IID,沒有特定的成員指出IID項數,但是會由全為0的IID結構作為結束。

上圖可以看出輸入表的起始位址為0x1B1C4,這是RVA(相對偏移位址)位址,我們需要轉化為檔案的偏移位址才能夠在檔案中找到相應的内容。工具中提供了RVA與檔案偏移位址的轉換或者自行計算。

PE檔案靜态注入

從上圖可以看出IID結構确實是由全為0的IID結構作為結束。

輸入表結構

IID結構的字段成員如下,其中OriginalFirstThunk、Name以及FirstThunk成員是我們添加DLL檔案的關鍵。

IMAGE_IMPORT_DESCRIPTOR
 union
  characteristics DWORD
  OriginalFirstThunk DWORD //指向IMAGE_THUNK_DATA結構的數組
 ends
 TimeDateStamp DWORD //時間标志
 ForwarderChain DWORD //一般為0
 Name   DWORD //指向DLL名稱的指針
 FirstThunk  DWORD//指向IMAGE_THUNK_DATA結構的數組
IMAGE_IMPORT_DESCRIPTOR
           

在PE檔案尚未執行過時,OriginalFirstThunk與FirstThunk字段指向相同的結構,差別在于OriginalFirstThunk不可以重寫,而FirstThunk可以被重寫,當PE檔案執行後FirstThunk指向的結構會用于存放輸入函數的真實位址。是以我們修改時将OriginalFirstThunk與FirstThunk字段指向同個位址即可。而Name字段存放的是指向DLL檔案名稱的指針。

OriginalFirstThunkFirstThunkName指向IMAGE_THUNK_DATA結構的數組指向IMAGE_THUNK_DATA結構的數組指向DLL名稱的指針

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA
 union u1
  ForwarderString DWORD //指向一個轉向者字元串的RVA
  Function  DWORD //被輸入的函數的記憶體位址
  Oridinal  DWORD //被輸入的API的序數值
  AddressOfData DWORD //指向IMAGE_IMPORT_BY_NAME
IMAGE_THUNK_DATA
           

IMAGE_THUNK_DATA結構在不同情況下的成員不同,但是重點關注AddresOfData字段,該字段指向IMAGE_IMPORT_BY_NAME結構,該結構記錄的輸入函數的名稱。當IMAGE_THUNK_DATA值的雙字的最高位為0時,表示函數以字元串類型的函數名方式輸入。是以構造時高兩個位元組為0,低兩個位元組為IMAGE_IMPORT_BY_NAME結構位址即可。

IMAGE_IMPORT_BY_NAME

IMAGE_IMPORT_BY_NAME STRUCT
 Hint WORD //忽略設定為0
 Name BYTE //輸入函數名稱
IMAGE_IMPORT_BY_NAME
           

IMAGE_IMPORT_BY_NAME結構的高兩位元組的值忽略,後門跟着的資料直接填入DLL檔案中輸出的函數名稱,即PE檔案運作時會使用到DLL檔案中函數的名稱。

修改PE檔案

這裡準備兩個檔案

  • 檔案一:HelloWorld.exe,該檔案僅僅是簡單在螢幕輸出HelloWorld!!!的字元
  • 檔案二:待注入的DLL檔案,show.dll,該DLL檔案的功能可以根據實際情況而定,這裡我準備的DLL檔案可以簡單的彈出一個對話框。

将HelloWorld.exe檔案拖入PEview工具中,檢視輸入表内容。可以看到并沒有載入show.dll檔案。

PE檔案靜态注入

運作HelloWorld.exe檔案

PE檔案靜态注入

開始修改HelloWorld.exe檔案的思路

  • 需要在輸入表中添加額外的IID結構,該IID成員的資訊為show.dll檔案的資訊
  • 由于需要添加IID成員,需要觀察原始輸入表是否由額外的空間可以容納新的IID結構,若沒有則可以選擇
    • 檔案中的空白區域
    • 檔案末尾添加新節區

現在觀察HelloWorld.exe檔案的輸入表,可以看見在輸入表的結尾處緊跟着的是一串資料,并且大機率不是無用的資料,若我們直接在輸入表結尾處添加新的IID結構必定會破壞原檔案的結構,導緻程式無法正常運作。

PE檔案靜态注入

是以選擇在找空白處,因為PE檔案需要對齊,是以會使用大量的空字元進行填充。空白區域可以任取,但是需要記住選取的位址因為後續需要用到。并且我們需要觀察該空白區域是否會被載入到記憶體中去。我們這裡選擇的是idata段末尾位置,是以需要去查詢idata段資訊。

PE檔案靜态注入

如下圖所示,檔案中idata段的大小比映射到記憶體中的大小更大,是以我們可以利用這段內插補點填充僞造輸入表。這裡選擇檔案偏移0x8960作為輸入表的起始位址。不能将0x8950作為其實位址,這樣KERNEL32.DLL字元串會缺失截斷符,運作時會提示找不到該DLL檔案。

PE檔案靜态注入

首先将原輸入表的資料複制下來,寫入檔案偏移0x8960處,新增一個IID結構,Name字段填入DLL檔案的名字,即show.dll,而OriginalFirstThunk與FirstThunk字段填入填入IMAGE_IMPORT_BY_NAME結構體的位址,IMAGE_IMPORT_BY_NAME的内容填入輸入函數的名稱,并且高兩個位元組需要為0。這裡所有填入的位址都為RVA位址,是以需要将檔案位址轉化為RVA位址填入。

PE檔案靜态注入

接着需要改寫idata的權限,前面說到FirstThunk在PE檔案運作後是會被改寫的,是以輸入表所在的區段需要具有寫權限。可以看到idata不具備寫權限,是以需要将寫權限加上。

PE檔案靜态注入

0x80000000為寫權限的标志位,是以将原來的資料或上0x80000000即可

PE檔案靜态注入

修改後為0xC0000000

PE檔案靜态注入

最後由于修改了輸入表結構以及所在位址并且新增了一個IID結構是以需要去資料目錄項的位置修改輸入表的位址及大小。

PE檔案靜态注入

使用PEView工具檢視修改後的檔案,能夠發現修改後的檔案使用工具依然能夠識别出來,證明沒有把檔案修壞。

PE檔案靜态注入

最後執行程式,發現show.dll檔案成功注入

PE檔案靜态注入

參考文章

  • 加密與解密
  • 逆向工程核心原理