2017-05-31 33 views
1

您好我正在嘗試在python腳本中創建一個導入表格構建器,就像MacT的Import Reconstructor一樣。如何解決來自PE上IAT的轉發API?

但是我很難找到從轉發的API獲取原始API信息的方法。例如,我從IAT得到了一個「ntdll!RtlDecodePointer」,但它是從「kernel32!DecodePointer」轉發的,我沒有任何想法可以找到它。

我是否需要搜索導入目錄中的每個加載模塊的ForwarderChain?

回答

0

不,ForwarderChain in Import directory與此無關。

當裝載機決心kernel32.DecodePointer一些PE進口 - 它認爲,這點有些地址IMAGE_EXPORT_DIRECTORYKERNEL32.DLL的 - 這就是所謂的轉出口。裝載機在這種情況下明白kernel32.DecodePointer點不是代碼,而是在格式字符串somedll.somefunction或形式somedll.#someordinal作爲結果裝載機是儘量負載somedll並通過名稱或搜索somefunctionsomeordinal按順序。這個搜索如何查看can(以及在向前輸出的情況下)遞歸。它停了,當我們終於得到函數地址不在裏面IMAGE_EXPORT_DIRECTORY - 這個地址,將存儲在IAT或進程失敗 - 我們沒有找到dll /或在此dll導出。

注意,這裏deliminator(DLL功能名之間 - 不!.)有趣的問題 - 什麼是如果包含.在自己的名字somedll - 說my.x64.dll。老版本的窗口不正確的進程名是這樣的(my.x64.dll.somefunc),因爲它在搜索字符串第一.通過strchr - 因此將搜索x64.dll.somefuncmy DLL和失敗。但現在這是固定的 - 裝載機使用strrchr - 他搜索字符串中的最後.

爲每年因此我們不能擴展指定全DLL名稱 -

#pragma comment(linker, "/export:fn=kernel32.dll.DecodePointer"); 
GetProcAddress((HMODULE)&__ImageBase, "fn"); 

不能說在XP。但現在 - 確切地說win10,可能是win8.1(需要檢查),這是正確的,將是工作 - xp將搜索dll.DecodePointerkernel32而win10搜索DecodePointerkernel32.dll。也從這裏指出,如果沒有.dll擴展名,現在我們不能將輸出轉發到模塊,現在 - 沒有這種限制。(加載默認追加.DLL後綴對加載庫名,如果不包含.它 - 所以,當呼叫LoadLibrary("my") - 實際上將被打開並裝載"my.DLL",但"my.""my.x64"後綴.DLL將不追加(在名稱.字符))

所以如果回到你的具體例子 - kernel32.DecodePointer指向IMAGE_EXPORT_DIRECTORYkernel32.dll。裝載機閱讀通過這個地址 - NTDLL.RtlDecodePointer - 調用strrchr(或strchr舊版本)在這個字符串找到.最後加載NTDLL - >NTDLL.DLL(後綴添加,因爲在名稱中沒有.)並搜索RtlDecodePointer - 地址找到它不在IMAGE_EXPORT_DIRECTORYntdll.dll - 所以這是代碼地址。這裏過程已停止,地址RtlDecodePointer保存在初始PEIAT

你從自己身邊需要重複裝載程序步驟。但在現代操作系統中存在一個問題 - 許多字符串以API-MS-* dll名稱開頭。這不是真正的DLL,但The API Set Schema - 無文件和可變的方式,如何加載程序解析此名稱

+0

謝謝你的解釋。我想我需要學習更多關於操作原理......:' – Vanz

0

聽起來像你想要區分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 
} 
+0

非常感謝。你的例子對我很有幫助! – Vanz