分析未文檔化的 API 與資料結構是逆向工程的核心技能。本文以 RtlInitializeGenericTable 為例,示範如何在 OllyDbg 中配合符號表,從反組譯碼推導出完整的 C 語言結構定義與初始化邏輯。
NTDLL.DLL函數 prologue:
MOV EDI, EDI
PUSH EBP
MOV EBP, ESP
參數存取(以 EBP 為基址):
MOV EAX, DWORD PTR SS:[EBP+8] ; 參數 1 -> 結構指標
XOR EDX, EDX ; EDX = 0
LEA ECX, DWORD PTR DS:[EAX+4] ; ECX = &結構->member2
MOV DWORD PTR DS:[EAX], EDX ; member1 = 0
MOV DWORD PTR DS:[ECX+4], ECX ; member3 = &member2
MOV DWORD PTR DS:[ECX], ECX ; member2 = &member2 (自我指向)
MOV DWORD PTR DS:[EAX+0C], ECX ; member4 = &member2
後續參數 2~5 依序寫入 member7~member10:
MOV ECX, DWORD PTR SS:[EBP+0C] ; 參數2
MOV DWORD PTR DS:[EAX+18], ECX ; member7 = 參數2
MOV ECX, DWORD PTR SS:[EBP+10] ; 參數3
MOV DWORD PTR DS:[EAX+1C], ECX ; member8 = 參數3
MOV ECX, DWORD PTR SS:[EBP+14] ; 參數4
MOV DWORD PTR DS:[EAX+20], ECX ; member9 = 參數4
MOV ECX, DWORD PTR SS:[EBP+18] ; 參數5
MOV DWORD PTR DS:[EAX+14], EDX ; member6 = 0
MOV DWORD PTR DS:[EAX+10], EDX ; member5 = 0
MOV DWORD PTR DS:[EAX+24], ECX ; member10 = 參數5
struct UnknownStruct {
UNKNOWN Member1; // +0
UNKNOWN_PTR Member2; // +4
UNKNOWN_PTR Member3; // +8
UNKNOWN_PTR Member4; // +C
UNKNOWN Member5; // +10
UNKNOWN Member6; // +14
UNKNOWN Member7; // +18
UNKNOWN Member8; // +1C
UNKNOWN Member9; // +20
UNKNOWN Member10; // +24
};
void RtlInitializeGenericTable(
struct UnknownStruct *pStruct, // Param1
UNKNOWN Param2, // Param2
UNKNOWN Param3, // Param3
UNKNOWN Param4, // Param4
UNKNOWN Param5 // Param5
) {
pStruct->Member1 = 0;
pStruct->Member3 = &pStruct->Member2;
pStruct->Member2 = &pStruct->Member2; // 自我指向,可能為鏈表頭初始化
pStruct->Member4 = &pStruct->Member2;
pStruct->Member7 = Param2;
pStruct->Member8 = Param3;
pStruct->Member9 = Param4;
pStruct->Member6 = 0;
pStruct->Member5 = 0;
pStruct->Member10 = Param5;
}


流程圖清晰展示了:
[EAX+offset] 形式的存取,offset 即成員偏移LEA ECX, [EAX+4] 明確表示取成員地址Member2 = &Member2 是鏈表頭節點初始化的經典特徵受限篇幅,未深入分析成員具體資料類型(如區分指標/整數/標誌位)。後續可結合動態調試觀察實際寫入值、交叉參考其他使用該結構的函數、參考 Windows 內核研究文獻(如 Windows Internals)進一步確認。方法死、思維活,靈活運用才是關鍵。