PE (Portable Executable) 結構包含:MS-DOS Header、NT Headers (PE 簽章、COFF Header、Optional Header)、Section Headers、Section Images。導入表位於 Optional Header 的 Data Directory 索引 1 (IMAGE_DIRECTORY_ENTRY_IMPORT):
DWORD it_voffset = pNTHeaders->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
每個被導入的 DLL 對應一個 IMAGE_IMPORT_DESCRIPTOR:
OriginalFirstThunk:指向 IMAGE_THUNK_DATA 陣列 (INT),含 Hint/Name RVAFirstThunk:指向 IAT (導入位址表),載入器將填入實際函數位址Name:DLL 名稱字串 RVAtypedef struct _IMAGE_IMPORT_DESCRIPTOR {
DWORD OriginalFirstThunk;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_THUNK_DATA {
union {
PDWORD Function; // IAT: 載入後填入函數位址
PIMAGE_IMPORT_BY_NAME AddressOfData; // INT: 指向 Hint/Name 結構
} u1;
} IMAGE_THUNK_DATA;
IMAGE_IMPORT_BY_NAME 包含 WORD Hint + BYTE Name[1] (函數名稱字串)。
工具輔助:Dependency Walker (官方)、自製 Import Table Viewer (圖形化介面)。
核心演算法 (_it_fixup_1 組語例程):
VirtualAlloc 分配獨立可執行記憶體區 (0x1D000 位元組)LoadLibrary + GetProcAddress 取得目標函數位址0xE9 + 相對位移),寫入獨立區// JMP 生成邏輯
mov byte ptr [edi], 0E9h ; JMP opcode
mov eax, [TargetAddr]
sub eax, edi
sub eax, 5 ; 相對位移 = 目標 - (當前+5)
mov [edi+1], eax ; 填入位移
mov word ptr [edi+5], 0C08Bh ; MOV EAX,EAX (NOP 滑板)
mov [Thunk], edi ; 重寫 IAT
對 CALC.EXE 套用後,OllyDbg 顯示 IAT 區域變為一連串 JMP 樁代碼:
008E0000 E9 E6F8177C JMP SHELL32.ShellAboutW
008E0005 8BC0 MOV EAX,EAX
008E0007 E9 0F764F77 JMP ADVAPI32.RegOpenKeyExA
...
限制:部分 DLL (如 MSVCRT) 的 Thunk 會被內部代碼區直接呼叫 (非經 IAT),重導向失效。專業 Protector 採用 x86 指令生成器 + 變體引擎 產生極度混淆的重導向邏輯。
嘗試修改 PE Maker 使用絕對 JMP (MOV EAX, Addr / JMP EAX) 實現重導向。完整原始碼包含 itview.zip、pemaker6.zip、pemaker7.zip、zimport.zip。