先说总结:说白了提升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)