Windows NT/2000 採用嚴格的核心模式 (Ring 0) 與使用者模式 (Ring 3) 分離架構,確保系統穩定性。一般應用程式若需執行特權指令 (如 I/O 埠操作、控制暫存器存取),傳統做法必須編寫核心模式驅動程式。本文揭示一種不載入驅動程式、純使用者模式程式即可實現 Ring 0 程式碼執行的進階技術——透過修改全域描述符表 (GDT) 植入呼叫閘 (Call Gate) 達成權限提升。
sgdt 指令 (非特權指令) 從 Ring 3 讀取。\Device\PhysicalMemory 區段物件,允許對實體記憶體讀寫。預設僅 SYSTEM 擁有讀寫權,Administrators 唯讀。需以 Administrator 權限執行,呼叫 GetSecurityInfo、SetEntriesInAcl、SetSecurityInfo 為目前使用者加入 SECTION_MAP_WRITE ACE。
分析 nt!MmGetPhysicalAddress 反組譯碼發現:核心空間線性位址 (0x80000000~0xA0000000) 採簡單位移對應實體位址,無需走頁表。公式:Physical = (Virtual & 0x1FFFF000)。
ZwOpenSection 開啟 \Device\PhysicalMemory (若拒絕存取則先調整 DACL)。MapViewOfFile 將 GDT 實體頁面映射至使用者空間。Selector = 0x08 (核心代碼段), DPL = 3 (允許 Ring 3 呼叫), Type = 0xC (386 Call Gate), Offset 指向使用者定義的 Ring 0 程式碼入口點。VirtualLock 鎖定使用者 Ring 0 程式碼頁面防止分頁。THREAD_PRIORITY_TIME_CRITICAL 減少被切換機率。call fword ptr [farcall] 遠端呼叫 Call Gate 進入 Ring 0。// Call Gate 描述符結構
typedef struct {
unsigned short offset_0_15;
unsigned short selector;
unsigned char param_count : 4;
unsigned char some_bits : 4;
unsigned char type : 4;
unsigned char app_system : 1;
unsigned char dpl : 2;
unsigned char present : 1;
unsigned short offset_16_31;
} CALLGATE_DESCRIPTOR;
// GDTR 結構 (sgdt 回傳)
typedef struct { short Limit; short BaseLow; short BaseHigh; } GDTR;
// 簡易虛轉實 (核心空間 0x80000000~0xA0000000)
ULONG MiniMmGetPhysicalAddress(ULONG va) {
if (va < 0x80000000 || va >= 0xA0000000) return 0;
return va & 0x1FFFF000;
}
BOOL ExecRing0Proc(ULONG EntryPoint, ULONG CodeSize) {
GDTR gdt; __asm sgdt gdt;
ULONG gdtBase = (gdt.BaseHigh << 16) | gdt.BaseLow;
ULONG physAddr = MiniMmGetPhysicalAddress(gdtBase);
if (!physAddr) return FALSE;
// 開啟 PhysicalMemory Section (含 DACL 調整邏輯)
HANDLE hSection = OpenPhysicalMemorySection();
if (!hSection) return FALSE;
// 映射 GDT 所在實體頁
PVOID pGdt = MapViewOfFile(hSection, FILE_MAP_READ|FILE_MAP_WRITE, 0, physAddr, gdt.Limit+1);
if (!pGdt) { CloseHandle(hSection); return FALSE; }
// 尋找空閒描述符並植入 Call Gate
CALLGATE_DESCRIPTOR *cg = FindAndSetupCallGate(pGdt, gdt.Limit, EntryPoint);
if (!cg) { UnmapViewOfFile(pGdt); CloseHandle(hSection); return FALSE; }
// 準備遠端呼叫指標 (Selector | 3 表示 Ring 3 呼叫)
WORD farCall[3]; farCall[2] = ((ULONG)cg - (ULONG)pGdt) | 3;
// 鎖定程式碼、執行、清理
VirtualLock((PVOID)EntryPoint, CodeSize);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
_asm call fword ptr [farCall];
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
VirtualUnlock((PVOID)EntryPoint, CodeSize);
// 清除 Call Gate
*(ULONG*)cg = 0; *((ULONG*)cg+1) = 0;
UnmapViewOfFile(pGdt); CloseHandle(hSection);
return TRUE;
}
PhysicalMemory DACL 必須具備管理員權限。\Device\PhysicalMemory、強制驅動程式簽章、PatchGuard 核心修補防護)。現代 Windows 開發需求 (硬體存取、高效能、系統監控) 應採用正規管道:
本文技術屬於「考古級」核心程式設計知識,理解其原理有助於深入掌握作業系統保護機制與安全防禦演進,但實務開發必須遵循現代安全開發規範。