本文為保護模式教程系列第二部分,深入剖析任務內控制轉移機制:無特權級轉移 (JMP/CALL/RET)、調用門跨特權調用、堆疊自動切換與參數複製、帶立即數返回指令清理參數、別名技術,並附實例四 (ASM4.ASM) 完整演示 0↔1↔3 級特權轉換。
同一記憶體區域用不同類型描述符描述,滿足不同操作需求。實例三中:
LDTable (系統段描述符, DT=0, TYPE=LDT) → LLDT 載入 LDTRToLDT (資料段描述符, DT=1, TYPE=RW) → 載入 DS/ES/FS/GS 以資料段方式存取 LDT 內容 (如讀取代碼段界限)原因:系統段描述符**不能**載入資料段寄存器。別名技術突破此限制,常用於:不同 TYPE 訪問、不同 DPL 訪問、代碼段寫入 (以資料段別名寫入)。
調用門描述符 (8 bytes, DT=0, TYPE=12/14) 包含:目標代碼段選擇子 + 32-bit 偏移 = 48-bit 完整入口指標。DCount (0-31) 指定參數複製數量 (雙字)。

**關鍵**:參數自動複製使內層程式無需感知堆疊切換,直接用 [EBP+8] 等訪問參數。
帶立即數 RET (如 RET 8) 同時清理內外層參數,**必須**用於有堆疊傳參的子程序。否則外層堆疊指標錯誤,導致崩潰。
C 調用慣例 vs STDCALL:C 調用由呼叫者清理參數 (需外層手動 ADD ESP),STDCALL 由被呼叫者清理 (RET n),後者符合 x86 硬體機制,Win32 API 採用 STDCALL。
任務結構:單任務,含 TSS、LDT、0/1/3 級堆疊、三代碼段 (演示 3 級、顯示子程序 1 級、過渡 0 級)、臨時 0 級 16-bit 代碼。
CALL 調用門 ToT32GateA (DPL=0) → 過渡代碼 T32Begin (0 級)DemoBeginRETF → **0→3 級降權**,切換到 3 級堆疊,進入 DemoBeginCALL 調用門 ToEchoGate (DPL=3) → 顯示子程序 EchoSub (1 級) → **3→1 級提權**,複製 0 參數EchoSub 從堆疊取呼叫者 CS.RPL (=3) 顯示 "CPL=3"RETF → **1→3 級降權**,返回演示代碼CALL 調用門 ToT32GateB (DPL=3) → 過渡代碼 T32End (0 級) → **3→0 級提權** (有去無回)JMP 臨時代碼 → 清理、返回實模式; T32Begin: 建立 3 級返回環境並降權
T32Begin:
mov ax, DemoStack0_Sel; mov ss, ax; mov esp, DemoStack0Len ; 建 0 級堆疊
push dword ptr DemoStack3_Sel; push DemoStack3Len ; 外層 SS:ESP
push dword ptr DemoCode_Sel; push offset DemoBegin ; 返回 CS:EIP
retf ; 0→3 級降權
; EchoSub: 顯示呼叫者 CPL (從堆疊取 CS 選擇子)
EchoSub:
push ebp; mov ebp, esp
mov ax, Echo_Sel1; mov ds, ax ; 可讀代碼段別名
mov ax, Video_Sel; mov es, ax
mov edi, 1996; mov esi, offset Message; mov ah, 4eh
; ... 顯示 "CPL=" ...
mov eax, [ebp+8] ; 堆疊上方第一雙字 = 呼叫者 CS 選擇子
and al, 3 ; 取 RPL (bit 0-1)
add al, '0'; stosw ; 顯示數字
pop ebp; retf
; DemoBegin: 3 級代碼
DemoBegin:
call32 ToEcho_Sel, 0 ; 3→1 級顯示 CPL
call32 ToT32B_Sel, 0 ; 3→0 級進入過渡 (不返回)
調用門是 x86 保護模式實現**受控提權**的核心機制:
實例四完整展示了 0↔1↔3 級雙向轉換、參數傳遞、別名技術、TSS 堆疊指標使用,是掌握 x86 保護機制的經典教材。