KeRaiseIrql 是 Windows 核心提升 IRQL(Interrupt Request Level)的核心 API,實現執行緒同步、鎖保護、DPC 執行等關鍵功能。本文通過反組譯與 WRK 原始碼,深度剖析其底層實現。
HalpIRQLtoTPR 獲取 TPR 值,寫入 APIC_TPR;舊 IRQL 從 HalpVectorToIRQL 反查。mov cr8, rcx 單指令完成。KeRaiseIrql → KfRaiseIrql (x86) / 內聯 KfRaiseIrql (x64)。hal!KfRaiseIrql:
movzx edx, cl ; 輸入 NewIrql
movzx ecx, byte ptr hal!HalpIRQLtoTPR[edx] ; 查表得 TPR
mov eax, dword ptr ds:[FFFE0080h] ; 讀舊 APIC_TPR
mov dword ptr ds:[FFFE0080h], ecx ; 寫新 TPR
shr eax, 4
movzx eax, byte ptr hal!HalpVectorToIRQL[eax] ; 反查舊 IRQL
ret
#define APIC_TPR ((volatile ULONG *)0xFFFE0080)
extern PUCHAR HalpIRQLToTPR;
extern PUCHAR HalpVectorToIRQL;
KIRQL KfRaiseIrql(KIRQL NewIrql) {
KIRQL oldIrql = KeGetCurrentIrql();
ASSERT(NewIrql >= oldIrql);
ULONG tprValue = HalpIRQLToTPR[NewIrql];
KeMemoryBarrier();
*APIC_TPR = tprValue;
KeMemoryBarrier();
return oldIrql;
}
KIRQL KeGetCurrentIrql() {
ULONG tpr = *APIC_TPR;
return HalpVectorToIRQL[tpr / 16];
}
nt!KfRaiseIrql:
mov rax, cr8 ; 讀舊 IRQL (CR8 低 4 位)
movzx ecx, cl ; NewIrql
mov cr8, rcx ; 寫新 IRQL
ret
KeMemoryBarrier 確保記憶體存取順序,防止亂序執行破壞同步語義。| 場景 | 命令/方法 |
|---|---|
| 查看當前 IRQL (Win2003+) | !irql 或 dd nt!KiOldIrql L1 |
| Win2003 前 | 僅能反組譯 KeGetCurrentIrql 推導 |
| KeFreezeExecution 時 | 舊 IRQL 保存在 KiOldIrql 全域變數 |