您好我正在嘗試在python腳本中創建一個導入表格構建器,就像MacT的Import Reconstructor一樣。如何解決來自PE上IAT的轉發API?
但是我很難找到從轉發的API獲取原始API信息的方法。例如,我從IAT得到了一個「ntdll!RtlDecodePointer」,但它是從「kernel32!DecodePointer」轉發的,我沒有任何想法可以找到它。
我是否需要搜索導入目錄中的每個加載模塊的ForwarderChain?
您好我正在嘗試在python腳本中創建一個導入表格構建器,就像MacT的Import Reconstructor一樣。如何解決來自PE上IAT的轉發API?
但是我很難找到從轉發的API獲取原始API信息的方法。例如,我從IAT得到了一個「ntdll!RtlDecodePointer」,但它是從「kernel32!DecodePointer」轉發的,我沒有任何想法可以找到它。
我是否需要搜索導入目錄中的每個加載模塊的ForwarderChain?
不,ForwarderChain in Import directory
與此無關。
當裝載機決心kernel32.DecodePointer
一些PE進口 - 它認爲,這點有些地址內IMAGE_EXPORT_DIRECTORY
KERNEL32.DLL的 - 這就是所謂的轉出口。裝載機在這種情況下明白kernel32.DecodePointer
點不是代碼,而是在格式字符串somedll.somefunction
或形式somedll.#someordinal
作爲結果裝載機是儘量負載somedll
並通過名稱或搜索somefunction
someordinal
按順序。這個搜索如何查看can(以及在向前輸出的情況下)遞歸。它停了,當我們終於得到函數地址不在裏面IMAGE_EXPORT_DIRECTORY
- 這個地址,將存儲在IAT或進程失敗 - 我們沒有找到dll /或在此dll導出。
注意,這裏deliminator(DLL和功能名之間 - 不!
但.
)有趣的問題 - 什麼是如果包含.
在自己的名字somedll
- 說my.x64.dll
。老版本的窗口不正確的進程名是這樣的(my.x64.dll.somefunc
),因爲它在搜索字符串第一.
通過strchr
- 因此將搜索x64.dll.somefunc
在my
DLL和失敗。但現在這是固定的 - 裝載機使用strrchr
- 他搜索字符串中的最後.
。
爲每年因此我們不能擴展指定全DLL名稱 -
#pragma comment(linker, "/export:fn=kernel32.dll.DecodePointer");
GetProcAddress((HMODULE)&__ImageBase, "fn");
不能說在XP。但現在 - 確切地說win10,可能是win8.1(需要檢查),這是正確的,將是工作 - xp將搜索dll.DecodePointer
在kernel32
而win10搜索DecodePointer
在kernel32.dll
。也從這裏指出,如果沒有.dll
擴展名,現在我們不能將輸出轉發到模塊,現在 - 沒有這種限制。(加載默認追加.DLL
後綴對加載庫名,如果不包含.
它 - 所以,當呼叫LoadLibrary("my")
- 實際上將被打開並裝載"my.DLL"
,但"my."
或"my.x64"
後綴.DLL
將不追加(在名稱.
字符))
所以如果回到你的具體例子 - kernel32.DecodePointer
指向IMAGE_EXPORT_DIRECTORY
的kernel32.dll。裝載機閱讀串通過這個地址 - NTDLL.RtlDecodePointer
- 調用strrchr
(或strchr
舊版本)在這個字符串找到.
最後加載NTDLL
- >NTDLL.DLL
(後綴添加,因爲在名稱中沒有.
)並搜索RtlDecodePointer
- 地址找到它不在IMAGE_EXPORT_DIRECTORY
的ntdll.dll - 所以這是代碼地址。這裏過程已停止,地址RtlDecodePointer
保存在初始PEIAT。
你從自己身邊需要重複裝載程序步驟。但在現代操作系統中存在一個問題 - 許多字符串以API-MS-*
dll名稱開頭。這不是真正的DLL,但The API Set Schema - 無文件和可變的方式,如何加載程序解析此名稱
聽起來像你想要區分Fowarder字符串和常規函數地址,同時解析模塊的導出表的能力。
我不建議在你知道它的Forwarder字符串之前解析這個Forwarder字符串,因爲有一個更簡單的方法。訣竅是檢查導出的函數的地址是否在導出段內存範圍內。這是PE/COFF規範的「導出地址表」部分所述的官方方法。
對不起,我下面的示例代碼是在C中,而不是Python,但仍應該給你這個想法。另請注意,下面的檢查適用於PE32和PE64圖像。
當您解析導出表時,您將已經有一個指向IMAGE_DATA_DIRECTORY導出部分的指針。從那裏你可以獲得一個指向IMAGE_EXPORT_DIRECTORY的指針。例如。
IMAGE_DATA_DIRECTORY* pExportEntry = pOptHeader->DataDirectory->arDataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT;
...
//code to convert pExportEntry->VirtualAddress into file offset and store in dwExportTableFileOffset
...
IMAGE_EXPORT_DIRECTORY* pExportTable = (IMAGE_EXPORT_DIRECTORY*)(ImageFileBase + dwExportTableFileOffset);
假設你已經從pExportTable-> AddressOfFunctions檢索功能的數組指針,下面的檢查工作之下,無論該功能是否通過名稱或oridinal出口。如果函數#i的函數地址(如下面的arFuncs [i]所示)位於導出段(您已經解析)內,則該地址指向格式爲<MODULE>的Forwarder字符串。 <ExportName>,否則它是一個常規函數。
if (arFuncs[i] >= pExportEntry->VirtualAddress && arFuncs[i] < pExportEntry->VirtualAddress+pExportEntry->Size)
{
//function address is RVA to Forwarder String; e.g. NTDLL.RtlDecodePointer
}
else
{
//function address is RVA to actual code within current module
}
非常感謝。你的例子對我很有幫助! – Vanz
謝謝你的解釋。我想我需要學習更多關於操作原理......:' – Vanz