deroko
February 3rd, 2008, 12:50
I was playing with IRQL and spotted one interesting thing. If IRQL is raised to HIGH_LEVEL, then KeGetCurrentIrql will return wrong info about IRQL:
Decode IRQL to Task Priority Register [APIC_base+0x80]
Also there is a array used to decode Task Priority Register to IRQL:
Basically if we are running at HIGH_LEVEL, KeGetCurrentIrql will always return POWER_LEVEL. Calculaion is simple here, it uses Task Priority, upper 8 bits of TPR (Task Priority Register) as index into _HalpVectorToIRQL or better name would be _HalpTPRtoIRQL for this 2nd array.
So are you sure that you are running at HIGH_IRQL? or POWER_LEVEL?
Code:
.text:800123B8 ; __fastcall KfRaiseIrql(x)
.text:800123B8 public @KfRaiseIrql@4
.text:800123B8 @KfRaiseIrql@4 proc near
.text:800123B8
.text:800123B8 movzx edx, cl
.text:800123BB movzx ecx, ds:_HalpIRQLtoTPR[edx]
.text:800123C2 mov eax, ds:0FFFE0080h
.text:800123C7 mov ds:0FFFE0080h, ecx
.text:800123CD shr eax, 4
.text:800123D0 movzx eax, ds:_HalpVectorToIRQL[eax]
.text:800123D7 retn
.text:800123D7 @KfRaiseIrql@4 endp
Decode IRQL to Task Priority Register [APIC_base+0x80]
Code:
.text:80012398 _HalpIRQLtoTPR db 0h <--- PASSIVE_LEVEL (0)
.text:80012399 db 3Dh <--- APC_LEVEL (1)
.text:8001239A db 41h <--- DISPATCH_LEVEL (2)
.text:8001239B db 41h
.text:8001239C db 51h
.text:8001239D db 61h <--- CMCI_LEVEL (5)
.text:8001239E db 71h
.text:8001239F db 81h
.text:800123A0 db 91h
.text:800123A1 db 0A1h
.text:800123A2 db 0B1h
.text:800123A3 db 0B1h
.text:800123A4 db 0B1h
.text:800123A5 db 0B1h
.text:800123A6 db 0B1h
.text:800123A7 db 0B1h
.text:800123A8 db 0B1h
.text:800123A9 db 0B1h
.text:800123AA db 0B1h
.text:800123AB db 0B1h
.text:800123AC db 0B1h
.text:800123AD db 0B1h
.text:800123AE db 0B1h
.text:800123AF db 0B1h
.text:800123B0 db 0B1h
.text:800123B1 db 0B1h
.text:800123B2 db 0B1h
.text:800123B3 db 0C1h <--- PROFILE_LEVEL (27)
.text:800123B4 db 0D1h <--- CLOCK1/2_LEVEL (28)
.text:800123B5 db 0E1h <--- IPI_LEVEL (29)
.text:800123B6 db 0EFh <--- POWER_LEVEL(30)
.text:800123B7 db 0FFh <--- HIGH_LEVEL (31)
Also there is a array used to decode Task Priority Register to IRQL:
Code:
.data:8001D218 _HalpVectorToIRQL db 0h <--- PASSIVE_IRQL
.data:8001D219 db 0FFh
.data:8001D21A db 0FFh
.data:8001D21B db 1 <--- APC_LEVEL
.data:8001D21C db 2 <--- DISPATCH_LEVEL
.data:8001D21D db 0FFh
.data:8001D21E db 0FFh
.data:8001D21F db 0FFh
.data:8001D220 db 0FFh
.data:8001D221 db 0FFh
.data:8001D222 db 0FFh
.data:8001D223 db 0FFh
.data:8001D224 db 1Bh PROFILE_LEVEL
.data:8001D225 db 1Ch CLOCK1/2_LEVEL
.data:8001D226 db 1Dh IPI_LEVEL and POWER LEVEL
are different in Task priority sub-class
(lower 8bits of Task Priority Register)
.data:8001D227 db 1Eh POWER_LEVEL
Basically if we are running at HIGH_LEVEL, KeGetCurrentIrql will always return POWER_LEVEL. Calculaion is simple here, it uses Task Priority, upper 8 bits of TPR (Task Priority Register) as index into _HalpVectorToIRQL or better name would be _HalpTPRtoIRQL for this 2nd array.
So are you sure that you are running at HIGH_IRQL? or POWER_LEVEL?



softice should drop irql (I saw code in it where it modifies TPR directly) when executing instruction(single steping), but when it gains control again, after that instruction, it has to raise IRQL, and seems that there is no way to see current IRQL in sice by looking at FFFE0080, not sure if sice directly modifies PCR at the same time, but if it doesn't then there is stored real irql