KeRaiseIrql理解,閱讀理解
先說總結:說白了提升IRQL其實就是從
hal!HalpIRQLtoTPR獲取要提升的IRQL級對應的TPR(Tast Preritory Register)值,改寫到APIC_TPR地址上去(0xFFFE0080). 然後將舊TPR值,從
byte ptr hal!HalpVectorToIRQL,獲取到舊的IRQL值。x64不一樣,
x64就CR8寄存器單獨干這個。
windgb:2003版本之前獲取當前IRQL只能從反匯編入手獲取。之後的版本可以!irql命令。KPRCB.DebuggerSavedIRQL,保存。
有一個名為 KiOldIrql 的全局變量,在 KeFreezeExecution 把 IRQL 提升到 HIGH_LEVEL 的時候會把原先的 IRQL 保存在這個變量裡。所以2003之後的版本可以直接dd nt!KiOldIrql L1 查看。之前的話。自己找吧。貌似通過調試器中斷下被調試系統來會導致IRQL切換,而如果崩潰則不會發生。
1 直接看反匯編。
2 kd> u nt!KeRaiseIrql
3 nt!KeRaiseIrql:
4 8053b888 ff25a0864d80 jmp dword ptr [nt!_imp__KeRaiseIrql (804d86a0)] **此處地址是間接地址,指向的是導入表數據的地址,別整錯了**
5
6 kd> uf Hal!KeRaiseIrql
7 hal!KeRaiseIrql:
8 806d775c 8bff mov edi,edi
9 806d775e 55 push ebp
10 806d775f 8bec mov ebp,esp
11 806d7761 8a4d08 mov cl,byte ptr [ebp+8]
12 806d7764 e80fbbffff call hal!KfRaiseIrql (806d3278)
13 806d7769 8b4d0c mov ecx,dword ptr [ebp+0Ch]
14 806d776c 8801 mov byte ptr [ecx],al
15 806d776e 5d pop ebp
16 806d776f c20800 ret 8
17
18 kd> u 806d3278
19 hal!KfRaiseIrql:
20 806d3278 0fb6d1 movzx edx,cl // 獲取要提升的IRQL級
21 806d327b 0fb68a58326d80 movzx ecx,byte ptr hal!HalpIRQLtoTPR (806d3258)[edx] // 將新傳入的irql作為索引,找到一個值 806d3282 a18000feff mov eax,dword ptr ds:[FFFE0080h] // 保存舊的。不清楚FFDFF000以上的結構
22 806d3287 890d8000feff mov dword ptr ds:[0FFFE0080h],ecx // 把新的值存到這個位置
23 806d328d c1e804 shr eax,4
24 806d3290 0fb68088e06d80 movzx eax,byte ptr hal!HalpVectorToIRQL (806de088)[eax] // 取得舊值
25 806d3297 c3 ret
26
27 kd> u KeGetCurrentIrql
28 hal!KeGetCurrentIrql:
29 806d32e8 a18000feff mov eax,dword ptr ds:[FFFE0080h]
30 806d32ed c1e804 shr eax,4
31 806d32f0 0fb68088e06d80 movzx eax,byte ptr hal!HalpVectorToIRQL (806de088)[eax]
32 806d32f7 c3 ret
33
34 x64下
35 nt!KfRaiseIrql:
36 fffff800`0451ab90 440f20c0 mov rax,cr8
37 fffff800`0451ab94 0fb6c9 movzx ecx,cl
38 fffff800`0451ab97 440f22c1 mov cr8,rcx
39 fffff800`0451ab9b c3 ret
40
41
42 摘錄WRK的源碼
43 extern PUCHAR HalpIRQLToTPR;
44 extern PUCHAR HalpVectorToIRQL;
45 #define APIC_TPR ((volatile ULONG *)0xFFFE0080)
46
47 #define KeGetCurrentIrql _KeGetCurrentIrql
48 #define KfLowerIrql _KfLowerIrql
49 #define KfRaiseIrql _KfRaiseIrql
50
51 KIRQL
52 FORCEINLINE
53 KeGetCurrentIrql (
54 VOID
55 )
56 {
57 ULONG tprValue;
58 KIRQL currentIrql;
59
60 tprValue = *APIC_TPR;
61 currentIrql = HalpVectorToIRQL[ tprValue / 16 ];
62 return currentIrql;
63 }
64
65 VOID
66 FORCEINLINE
67 KfLowerIrql (
68 __in KIRQL NewIrql
69 )
70 {
71 ULONG tprValue;
72
73 ASSERT( NewIrql <= KeGetCurrentIrql() );
74
75 tprValue = HalpIRQLToTPR[NewIrql];
76 KeMemoryBarrier();
77 *APIC_TPR = tprValue;
78 *APIC_TPR;
79 KeMemoryBarrier();
80 }
81
82 KIRQL
83 FORCEINLINE
84 KfRaiseIrql (
85 __in KIRQL NewIrql
86 )
87 {
88 KIRQL oldIrql;
89 ULONG tprValue;
90
91 oldIrql = KeGetCurrentIrql();
92
93 ASSERT( NewIrql >= oldIrql );
94
95 tprValue = HalpIRQLToTPR[NewIrql];
96 KeMemoryBarrier();
97 *APIC_TPR = tprValue;
98 KeMemoryBarrier();
99 return oldIrql;
100 }
101
102 KIRQL
103 FORCEINLINE
104 KeRaiseIrqlToDpcLevel (
105 VOID
106 )
107 {
108 return KfRaiseIrql(DISPATCH_LEVEL);
109 }
110
111 KIRQL
112 FORCEINLINE
113 KeRaiseIrqlToSynchLevel (
114 VOID
115 )
116 {
117 return KfRaiseIrql(SYNCH_LEVEL);
118 }
119
120 #define KeLowerIrql(a) KfLowerIrql(a)
121 #define KeRaiseIrql(a,b) *(b) = KfRaiseIrql(a)