首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

Windows XP 使用者模式記憶體空間探勘(三):模組載入與記憶體對映

     編輯:VC 教學

前言

承接前兩篇對 XP 使用者模式 4GB 虛擬位址空間的整體架構與堆疊分析,本文將實際動手撰寫程式,列舉目前行程載入的所有模組(EXE、DLL),並查詢它們在虛擬記憶體中的確切位置與大小,進一步驗證理論與實際的對應關係。

一、核心 API:EnumProcessModules 與 GetModuleInformation

要取得行程中所有模組的資訊,主要依賴 PSAPI(Process Status Helper)提供的兩個函數:

  • EnumProcessModules:列舉指定行程載入的所有模組控制代碼(HMODULE)。
  • GetModuleInformation:依模組控制代碼取得 MODULEINFO 結構,包含基址(lpBaseOfDll)、大小(SizeOfImage)、進入點(EntryPoint)。

二、完整程式碼範例

#include 
#include 
#include 
#include 

#pragma comment(lib, "psapi.lib")

int main() {
    HANDLE hProcess = GetCurrentProcess();
    HMODULE hMods[1024];
    DWORD cbNeeded;

    if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
        int nModCount = cbNeeded / sizeof(HMODULE);
        for (int i = 0; i < nModCount; i++) {
            TCHAR szModName[MAX_PATH];
            MODULEINFO mi = {0};

            GetModuleFileNameEx(hProcess, hMods[i], szModName, MAX_PATH);
            GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi));

            _tprintf(TEXT("%-40s  Base: 0x%08X  Size: 0x%08X  Entry: 0x%08X\n"),
                     szModName, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage, (DWORD)mi.EntryPoint);
        }
    }
    return 0;
}

三、實際執行結果分析(十六進位顯示)

執行上述程式,可獲得類似下表的輸出(節選關鍵模組):

模組名稱基址 (lpBaseOfDll)大小 (SizeOfImage)進入點 (EntryPoint)
TestApp.exe0x004000000x0000F0000x00401000
ntdll.dll0x7C9000000x000B00000x7C901000
kernel32.dll0x7C8000000x000F60000x7C801000
user32.dll0x7E4100000x000910000x7E411000
gdi32.dll0x77F100000x0004B0000x77F11000
advapi32.dll0x77DD00000x0009A0000x77DD1000
msvcrt.dll0x77C100000x000580000x77C11000
shell32.dll0x7C9C00000x0081A0000x7C9C1000
comctl32.dll (v6)0x773D00000x001050000x773D1000

四、關鍵觀察與解讀

  1. EXE 固定基址 0x00400000:除非設定 /DYNAMICBASE(ASLR),預設映像基址即為 0x00400000,這與「使用者模式分區從 0x00010000 開始」一致。
  2. 系統 DLL 集中於高位址區:ntdll、kernel32、user32 等核心 DLL 基址落在 0x77xxxxxx ~ 0x7Cxxxxxx,接近 2GB 邊界(0x7FFF0000),符合 XP 將系統 DLL 映射到共享區域以節省實體記憶體的設計。
  3. 模組大小即映像大小:SizeOfImage 反映 PE 檔案標頭中 SizeOfImage 欄位,已包含所有區段(.text、.data、.rdata 等)並對齊到區塊(通常 4KB 或 64KB)。
  4. 進入點非基址:EntryPoint = 基址 + AddressOfEntryPoint(PE Optional Header 中指定),通常指向 CRT 啟動程式碼而非 main/WinMain。
  5. ASLR 與重新定址:若啟用 ASLR(Vista 後預設開啟),基址會隨機化;XP 預設不開啟,故每次執行基址固定,利於除錯與分析。

五、進階應用:手動對應 PE 結構

拿到 lpBaseOfDll 後,即可像剖析檔案一樣解析記憶體中的 PE 結構:

PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)mi.lpBaseOfDll;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((BYTE*)pDos + pDos->e_lfanew);
// 接著可遍歷 Section Header、Import Table、Export Table、Relocation Table 等

這是逆向工程、Hook 技術、熱修補、記憶體掃描等進階技術的基礎。

六、總結

透過 EnumProcessModules + GetModuleInformation,我們能快速繪製行程的「模組地圖」,直觀驗證 XP 使用者模式記憶體佈局:EXE 佔據低址,系統 DLL 聚集高址,中間留給堆積、堆疊、動態配置區域。掌握這套查詢技巧,是深入理解 Windows 記憶體管理、進行除錯與安全分析的敲門磚。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved