1. ApiMapSet Hooking

    I wrote about new technique of hijacking some APIs on Windows 7 via ApiMapSet.

    small description :
    source code :
  2. ApiMapSet Explained

    I try to explain how all redirection are done in Windows 7 through dlls such as api-ms-win-core-console-l1-1-0.dll and similar
  3. tracer or Writing tracer without using Windows Debug API

    This time I decided to publish source code of an driver which I used for stealth debugging and tracing protections. I've successfully used it with many packers/protectors but most important projects which I made, and which were using this are themida and aspr 2.3 ske unpackers. Now whole code for this small tracing driver is available at :
  4. DbgView patch

    Well, there is small bug in DbgView.exe which caused serious problem to me. It happened earlier, but I was blaming my code. Recently same thing happened to me again, so I decided to investigate, and found simple bug in DbgView.exe which causes system "hang", so I made patch to fix this issue. More details can be found in readme.txt which is included with patch.
  5. VMware ring3 detection (RF handling)


    Here is one trick to detect vmware discovered by accidance

    I was writing one unpacker, and for me RF was must have to make my unpacker simpler. Unpacker worked great on live system, and then I tried it in vmware, and I got many breaks at same part of the code which should be continued with RF.

    RF from intel manual volume 3, chapter 18:

    Because the debug exception for an instruction breakpoint is generated before the
    instruction is executed, if the instruction breakpoint is not removed by the exception
    handler; the processor will detect the instruction breakpoint again when the instruction
    is restarted and generate another debug exception. To prevent looping on an
    instruction breakpoint, the Intel 64 and IA-32 architectures provide the RF flag
    (resume flag) in the EFLAGS register (see Section 2.3, “System Flags and Fields in
    the EFLAGS Register,” in the Intel® 64 and IA-32 Architectures Software Developer’s
    Manual, Volume 3A). When the RF flag is set, the processor ignores instruction
    Basically waht debugger would do with break point is:
    - breakpoint reached -> clear breakpoint
    - single step that instruction
    - set breakpoint after singlestep
    - continue execution
    - too much not needed work...

    For DebugRegister breaks on execution, you can simplfy this by setting RF in Eflags, and you don't have to remove your breakpoint on execution.

    So here is how to detect VMWare presence using debug registers due to wrong RF handling:

    Code allocates memory and stores there 0xC3, after that program generates exception to set debug registers. In exception handler code checks if exception occured 1st time (1st debug break) and sets RF (eg. continue execution), after that if exception occurs 2nd time, means that RF wasn't handled and that we have vmware (didn't try with other virtual machines).

    #include        "defs.h"
    PVOID   buffer;
    DWORD   dwExceptionCount;
    ULONG   filter(PEXCEPTION_INFO pei){
            PCONTEXT pctx;
            pctx = pei->pContext;
            if (dwExceptionCount == 0){
                    pctx->Dr7 = BPM_LOCAL_EXACT | BPM0_LOCAL_ENABLED;
                    pctx->Dr0 = (DWORD)buffer;
                    pctx->Eip += 2;
                    NtContinue(pctx, FALSE);
            }else if (dwExceptionCount == 1){
                    pctx->EFlags |= 0x10000;
                    NtContinue(pctx, FALSE);
            }else if (dwExceptionCount == 2){
                    printf("[X] vmware detected\n");
            return EXCEPTION_EXECUTE_HANDLER;        
    void __declspec(naked) hook_filter(void){
            __asm push      esp
            __asm call      filter
    int __cdecl wmain(int argc, wchar_t **argv){
            VOID    (*func)();
            DWORD   dwOldProt;
            PUCHAR  kiuser;
            printf("[*] ring3 VMWARE detection - (c) 2009 deroko of ARTeam\n");
            kiuser = (PUCHAR)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "KiUserExceptionDispatcher");
            VirtualProtect(kiuser, 7, PAGE_EXECUTE_READWRITE, &dwOldProt);
            kiuser[0] = 0x68;
            *(DWORD *)&kiuser[1] = (DWORD)hook_filter;
            kiuser[5] = 0xc3;
            buffer = func = VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
            *(DWORD *)func = 0xC3909090;
            __asm xor eax, eax
            __asm mov eax, [eax]
            printf("[*] vmware not detected\n");

    #include        <windows.h>
    #include        <stdio.h>
    // Dr6
    #define BPM0_DETECTED                    0x00000001
    #define BPM1_DETECTED                    0x00000002
    #define BPM2_DETECTED                    0x00000004
    #define BPM3_DETECTED                    0x00000008
    // Dr7
    #define BPM0_LOCAL_ENABLED               0x00000001
    #define BPM0_W                           0x00010000
    #define BPM0_RW                          0x00030000
    #define BPM1_LOCAL_ENABLED               0x00000004
    #define BPM1_W                           0x00100000
    #define BPM1_RW                          0x00300000
    #define BPM2_LOCAL_ENABLED               0x00000010
    #define BPM2_W                           0x01000000
    #define BPM2_RW                          0x03000000
    #define BPM3_LOCAL_ENABLED               0x00000040
    #define BPM3_W                           0x10000000
    #define BPM3_RW                          0x30000000
    #define BPM_LOCAL_EXACT                  0x00000100
    typedef LONG NTSTATUS;
    NtContinue(__in PCONTEXT ctx, BOOL Alertalbe);
    typedef struct{
    	PULONG ExceptionCodeAddress;
    	PCONTEXT   pContext;
    	ULONG  ExceptionCode;
    	ULONG  ExceptionFlags;
    	PULONG ExceptionRecord;
    	ULONG  ExceptionAddress;
    	ULONG  NumberOfParameters;

    output of the program running in vmware:
    [*] ring3 VMWARE detection - (c) 2009 deroko of ARTeam
    [X] vmware detected
    output of the program running on live system:

    [*] ring3 VMWARE detection - (c) 2009 deroko of ARTeam
    [*] vmware not detected

    Hope you find it usefull
  6. custom gpa spy

    read above topic to know how this idea was born well actually this idea was in my mind for almost a two years, but never found it useful to fully develop working code, but after reading this topic, and comments at posted link, I've decided to give it a go status.

    In short : at above link, you will find link to the other site which has statistic of used functions in common files. On other hand, many are missed due to GetProcAddress, and not to mention many being missed due to custom GetProcAddress. So how to spy custom GetProcAddress!?!? well read the code and you will see.

    This could be useful for protection profiling, and there are some other ways which I would use to deal with this, but for now, it seems ok, just so you get the basic idea. code is really messy, as I hate writing ring3 debuggers...

    full code and sample binary:
  7. SoftICE and KDExtensions

    Well I was writing one extension for softice, and I faced one serious problem which in turn might not be that big problem if softice authors decided to write softice code properly at some points. SoftICE manual doesn't provide us with concept how to write KDExtensions, but in turn it gives us tools which we might use to convert existing windbg extensions into softice extension. One of rules is that we may not use Exception Handling in KDExtension (taken from SoftICE manual), and silently it refuses usage of many exports from ntoskrnl.exe...

    KD2SYS.exe works simply by adding extra code to your dll, and changing it's entrypoint to code which looks like this:

    .1000147F: B800000000                     mov         eax,0
    .10001484: C20800                         retn        8
    .10001487: 0010                           add         [eax],dl
    .10001489: 0000                           add         [eax],al
    when extension is loaded, it MUST have Debug symbols so softice will know that it should check EntryPoint for mov eax, 0/retn 8 using INT 2D (during driver loading ntoskrnl.exe will call -> DbgLoadImageSymbols which in turns will call int 2D, hooked by SoftICE which will examine entrypoint of driver and substitute mov eax, 0 with jmp __softice_code which will in turn call DllEntryPoint.

    PAGE:004D7D27                 push    dword ptr [edi] ; ImageBase
    PAGE:004D7D29                 call    _CacheImageSymbols@4 ; CacheImageSymbols(x)   
    PAGE:004D7D2E                 test    eax, eax
    PAGE:004D7D30                 jz      __no_debug_symbols
    Upper code shows part of ntos which checks if Debug directory is used, and after that it will call DbgLoadImageSymbols.

    If you take a look at upper Disassm code, you may see that right after retn 08 is stored : 1000h which is RVA of DllEntryPoint... You may examine a little bit hook of int2D and you will see how loading of KD takes place in SoftICE, not a nuclear physics as you may trace Int2D hook in SoftICE without a problem, as it will be running at PASSIVE_LEVEL (level at which drivers are being loaded).

    Next step is to create such driver that will have similar if not the same code which will be handld by SoftICE. My walkaround was to define DriverEntry in asm code like this:

    extern                  DllEntryPoint@12:dword 
    public  C               DriverEntry@8
    DriverEntry@8:          mov     eax, 0
                            ret     8
                            dd      0FFFFFFFFh
                            dd      offset DllEntryPoint@12
    Also make sure that TARGETTYPE=MINIPORT to link directly with DriverEntry@8 as your entrypoint, as DRIVER type will link using GsDriverEntry:

    INIT:00011185                 public GsDriverEntry
    INIT:00011185 GsDriverEntry   proc near
    INIT:00011185                 mov     edi, edi
    INIT:00011187                 push    ebp
    INIT:00011188                 mov     ebp, esp
    INIT:0001118A                 mov     eax, __security_cookie
    INIT:0001118F                 test    eax, eax
    INIT:000111B8                 mov     __security_cookie_complement, eax
    INIT:000111BD                 pop     ebp
    INIT:000111BE                 jmp     DriverEntry
    Which is not what I want...

    Next step is to write convert.c/asm code which will:

    1. open your file
    2. locate entry point
    3. calculate relative offset of DllEntryPoint
    4. store it in placess of 0FFFFFFFF
    5. update checksum
    6. save changes

    Now you may have neet extension (at least that's how I write them). Kayaker probably has better solution

    Now comes funn part which I figgured after making dump of whole memory in VMWare, as minidump wasn't enough for me.

    I tried to call some procedures which require dropping of IRQL like ExAllocatePool, which will eventually endup in ExAcquireQueuedSpinLock, which will drop IRQL to DISPATCH_LEVEL. I've started receiving numerous BSODs, and I tought that IRQL was an issue... and those BSODs occured only, and only when I was breaking in softice from ring3 applications, so I figured something had to be wrong, but in my wildest dreams I wouldn't suspect that solution was that stupid...

    Let's have a look at code responsible for calling KDExtension in softice:

    .text:A7AB9D3A si_callExtension proc near             
    .text:A7AB9D3A ExtensionApi    = dword ptr  8
    .text:A7AB9D3A hCurrentProcess = dword ptr  0Ch
    .text:A7AB9D3A hCurrentThread  = dword ptr  10h
    .text:A7AB9D3A dwCurrentPc     = dword ptr  14h
    .text:A7AB9D3A dwProcessor     = dword ptr  18h
    .text:A7AB9D3A args            = dword ptr  1Ch
    .text:A7AB9D3A                 push    ebp
    .text:A7AB9D3B                 mov     ebp, esp
    .text:A7AB9D3D                 push    ds
    .text:A7AB9D3E                 push    es
    .text:A7AB9D3F                 push    fs
    .text:A7AB9D41                 push    gs
    .text:A7AB9D43                 pusha
    .text:A7AB9D44                 pushf
    .text:A7AB9D45                 mov     edi, kd_extension_esp_start
    .text:A7AB9D4B                 mov     ecx, kd_extension_stack_size
    .text:A7AB9D51                 shr     ecx, 2
    .text:A7AB9D54                 xor     eax, eax
    .text:A7AB9D56                 cld
    .text:A7AB9D57                 rep stosd
    .text:A7AB9D59                 cli
    .text:A7AB9D5A                 mov     save_sice_esp, esp
    .text:A7AB9D60                 mov     save_sice_ebp, ebp
    .text:A7AB9D66                 mov     ErrorString_to_display, 0
    .text:A7AB9D70                 mov     si_extension_aborted_pagefault, 0
    .text:A7AB9D77                 mov     b_extension_executing, 1
    .text:A7AB9D7E                 mov     dl, 1
    .text:A7AB9D80                 call    Install_Reinsall_DivideOverflowHandler
    .text:A7AB9D85                 mov     esp, kd_extension_esp
    .text:A7AB9D8B                 sti
    .text:A7AB9D8C                 mov     fs, word ptr kd_extension_fs 
    .text:A7AB9D92                 call    sub_A7AB9C86    
    .text:A7AB9D97                 push    [ebp+args]
    .text:A7AB9D9A                 push    [ebp+dwProcessor]
    .text:A7AB9D9D                 push    [ebp+dwCurrentPc]
    .text:A7AB9DA0                 push    [ebp+hCurrentThread]
    .text:A7AB9DA3                 push    [ebp+hCurrentProcess]
    .text:A7AB9DA6                 call    [ebp+ExtensionApi]
    .text:A7AB9DA9 loc_A7AB9DA9:                           
    .text:A7AB9DA9                 cli
    .text:A7AB9DAA                 mov     esp, save_sice_esp
    .text:A7AB9DB0                 mov     ebp, save_sice_ebp
    .text:A7AB9DB6                 mov     b_extension_executing, 0
    .text:A7AB9DBD                 call    restore_SEH
    .text:A7AB9DC2                 xor     dl, dl
    .text:A7AB9DC4                 call    Install_Reinsall_DivideOverflowHandler
    .text:A7AB9DC9                 sti
    .text:A7AB9DCA                 mov     edi, kd_extension_esp_start
    .text:A7AB9DD0                 mov     ecx, kd_extension_stack_size
    .text:A7AB9DD6                 shr     ecx, 2
    .text:A7AB9DD9                 xor     eax, eax
    .text:A7AB9DDB                 cld
    .text:A7AB9DDC                 repe scasd
    .text:A7AB9DDE                 mov     eax, ecx
    .text:A7AB9DE0                 inc     eax
    .text:A7AB9DE1                 shl     eax, 2
    .text:A7AB9DE4                 popf
    .text:A7AB9DE5                 popa
    .text:A7AB9DE6                 pop     gs
    .text:A7AB9DE8                 pop     fs
    .text:A7AB9DEA                 pop     es
    .text:A7AB9DEB                 pop     ds
    .text:A7AB9DEC                 pop     ebp
    .text:A7AB9DED                 retn    18h
    .text:A7AB9DED si_callExtension endp
    Now comes funny part, really funny part!!!!

    .text:A7AB9D8C                 mov     fs, word ptr kd_extension_fs
    This is not kd_extension_fs, this is FS of interupted TASK!!!!!!!!!! So if you are debugging ring3 code, KDExtension will be called with FS = 0x3B which points to TEB instead of KPCR, what most exports from ntoskrnl.exe will expect it to be!!! Of course, this is not the problem when you interupt TASK which is running in ring0, but I want my extension to work the same way no matter if interupted task is in ring0 or ring3.

    That's the reason why KeSetEvent, ExAllocatePool, KeInsertQueueDpc and many, many others will fail, as those at some point expect FS to point to KPCR instead of TEB!

    My solution was to create 2 functions, and call them, one at the beginning of exported function, and one at the end:

    ULONG   old_fs;
    void    set_fs()
                    xor     eax, eax
                    mov     ax, fs
                    mov     old_fs, eax
                    mov     eax, 30h
                    mov     fs, ax
    void    restore_fs()
                    mov     eax, old_fs
                    mov     fs, ax
    Although those seem like not safe functions, remember that softice ...
  8. SymbolFinder

    Dunno if this is just me or this is for real, but if someone tries to google for some kind of example of symbol lister it will endup in dead-end (maybe I should work on my google skils ), anyway, I spent last 2 days playing and figuring these symbols (great MS simply points in MSDN to PDB documentation... where is that thing!??!!?), to write this enum, struct, symbol lister and decided to share my source so there can be at least one refference on how to list and parse symbols...

    Hope someone will find it usefull
  9. pde/pte softice plugin

    Today I needed to verify some bits in PDE/PTE from SoftICE (well while I'm debugging) so I wrote one plugin for softice which will give me all needed information about pde/pte for a given address. Note that this is for PAE systems as I'm using PAE mainly... maybe I'll update it for non pae systems someday. Anyway, source is included
  10. build rule for x64 asm

    I've made build rule for x64 asm files compiled from msvc2008. I had to use asm x64 in my C code. Hope it will be usefull
    <?xml version="1.0" encoding="utf-8"?>
    			CommandLine="ml64.exe /c /nologo $(InputName).asm"
    			ExecutionDescription="Assembling x64..."

    Updated June 22nd, 2008 at 19:33 by deroko

  11. nonintrusive tracer on x64

    Well time has come to dig a little bit into x64 systems, and to move our lovely tools and ideas to that system.

    Lets have a look at KiUserExceptionDispatcher from ntdll.dll:

    .text:0000000077EF31B0                 public KiUserExceptionDispatcher
    .text:0000000077EF31B0 KiUserExceptionDispatcher:              
    .text:0000000077EF31B0                 mov     rax, cs:Wow64PrepareForException
    .text:0000000077EF31B7                 test    rax, rax
    .text:0000000077EF31BA                 jz      short loc_77EF31CB
    .text:0000000077EF31BC                 mov     rcx, rsp
    .text:0000000077EF31BF                 add     rcx, 4D0h
    .text:0000000077EF31C6                 mov     rdx, rsp
    .text:0000000077EF31C9                 call    rax ; Wow64PrepareForException
    .text:0000000077EF31CB loc_77EF31CB:                         
    .text:0000000077EF31CB                 mov     rcx, rsp
    .text:0000000077EF31CE                 add     rcx, 4D0h
    .text:0000000077EF31D5                 mov     rdx, rsp
    .text:0000000077EF31D8                 call    RtlDispatchException
    .text:0000000077EF31DD                 test    al, al
    .text:0000000077EF31DF                 jz      short loc_77EF31ED
    .text:0000000077EF31E1                 mov     rcx, rsp
    .text:0000000077EF31E4                 xor     edx, edx
    .text:0000000077EF31E6                 call    RtlRestoreContext

    Wow64PrepareForException is used only when loading wow64 process, so in "native x64" environment this variable is set to 0, and we can use that variable to write our own SEH handler in asm or nonintrusive tracer. Well let's cut to the point and see some real code:

                            mov     rax, KiUserExceptionDispatcher
                            xor     rbx, rbx
                            mov     ebx, dword ptr[rax+3]
                            add     rbx, rax
                            add     rbx, 7
                            mov     rax, offset __mykiuser
                            mov     [rbx], rax
                            xor     rax, rax
                            mov     [rax], rax
                            xor     r9, r9
                            mov     r8, offset szntdll
                            mov     rdx, offset szkiuser
                            mov     rcx, 0
                            callW   MessageBoxA
                            xor     rcx, rcx
                            callW   ExitProcess
    __mykiuser:             add     qword ptr[rdx+0F8h], 3
                            mov     rcx, rdx
                            xor     rdx, rdx
                            callW   RtlRestoreContext
    If everything worked as planned, MessageBoxA will be shown... simple isn't it
  12. IDA and vmread/vmwrite x64

    These 2 instructions are defined as:

    VMREAD  Ed/q, Gd/q
    VMWRITE Gd/q, Ed/q
    where d is for 32 bit environment, and q for 64 bit environment, which means that in 32 bit environment operands are always 32bit, and in 64bit environment those are 64bit, and operand size prefix can't affect size.

    But IDA displays wrong info:

    .text:0000000000011010                 mov     [rsp+arg_8], rdx
    .text:0000000000011015                 mov     [rsp+arg_0], rcx
    .text:000000000001101A                 sub     rsp, 38h
    .text:000000000001101E                 mov     edx, 1
    .text:0000000000011023                 mov     rcx, 1234567812345678h
    .text:000000000001102D                 call    VmWrite_proc
    .text:0000000000011032                 mov     rcx, 1234567812345678h
    .text:000000000001103C                 call    VmRead_proc
    .text:0000000000011041                 mov     [rsp+38h+var_18], rax
    .text:0000000000011046                 xor     eax, eax
    .text:0000000000011048                 add     rsp, 38h
    .text:000000000001104C                 retn
    .text:000000000001104C DriverEntry     endp
    .text:0000000000011060 VmWrite_proc    proc near               
    .text:0000000000011060                 vmwrite ecx, edx    <----- 32bit operands, which is not possible
    .text:0000000000011063                 retn
    .text:0000000000011063 VmWrite_proc    endp
    .text:0000000000011064 VmRead_proc     proc near              
    .text:0000000000011064                 vmread  eax, ecx    <----- again 32 bit operands
    .text:0000000000011067                 retn
    .text:0000000000011067 VmRead_proc     endp

    Instead this should be displayed as vmwrite rcx, rdx and vmread rax, rcx. This is also verified by looking at intel documentation (CHAPTER 5 VMX INSTRUCTION REFERENCE - Volume 2B):

    VMREAD—Read Field from Virtual-Machine Control Structure
    Opcode Instruction Description
    0F 78 VMREAD r/m64, r64 Reads a specified VMCS field (in 64-bit mode).
    0F 78 VMREAD r/m32, r32 Reads a specified VMCS field (outside 64-bit mode).

    VMWRITE—Write Field to Virtual-Machine Control Structure
    Opcode Instruction Description
    0F 79 VMWRITE r64, r/m64 Writes a specified VMCS field (in 64-bit mode)
    0F 79 VMWRITE r32, r/m32 Writes a specified VMCS field (outside 64-bit mode)
    Nothing spectacular, but still, wrong disassembly

    Updated May 20th, 2008 at 18:49 by deroko

  13. Intel VT and cpuid break

    Do you want to use cpuid as int 3 or any other event? Well Intel VT allows us that, as cpuid always generates VM-Exit. In this case what we do is:

    1. Read Guest Cr3 to check correct process
    2. inject int 3 event into Guest
    3. SoftICE will popup if i3here on is set
    4. Enjoy

    bin/src ->
  14. on mp systems running sice

    SoftICE uses drX to perform step over. One interesting question is how does it do that on MP system? It could happen that thread is running at one CPU, but code which is executed in certain procedure could switch to different CPU, and still SoftICE manages to stepover correctly. How is that possible? Using IPI, of course.

    The best example is this code if steped over in SoftICE:

            KeSetAffinityThread(cur_thread, 1<<0);
            KeSetAffinityThread(cur_thread, 1<<1);
    both calls will be steped over correctly, and that's because SoftICE sends IPI with Shorthand = All excluding self set in ICR to set drXes on both CPUs.

    I also wrote earlier that softice changes NMI handler from TaskGate to IdtGate on single cpu machine, but when I viewed IDT on MP system from SoftICE, it used TaskGate to hook NMI. So there are certain rules which have to be followed when drX access occurs from NMI and TaskGate.

    Handler must NOT iret if access to drX occurs from NMI, because iret will unblock NMI. Handler also must not use DbgPrint, or anything else that can trigger iret when executing from NMI...

    Also if we are in NMI, SoftIce won't clear NT flag in eflags, so any iret will lead to previous task. We can avoid this problem by clearing NT flag, but again, we unblock NMI using iret, so this is sidenote, not a real problem.

    This problem with iret is solved easily, by changing the way we return from int1 when it's caused from NMI:

    __s0:           str     ax              ;get task register
                    cmp     ax, 58h         ;check if it is NMI
                    je      __nmi
                    pop     es              ;not NMI so exit normally
                    pop     ds
                    pop     fs
    __nmi:          mov     eax, [esp.regEflags]            
                    push    eax             ;NMI!! - restore eflags                
                    pop     es              ;r0 epilog
                    pop     ds
                    pop     fs
                    retn    8               ;ret to interupted code and
                                            ;clear cs/eflags stored on 
    Bingo... dr7.GD is now working in mp system running sice
  15. KeGetCurrentIrql can't return HIGH_LEVEL

    I was playing with IRQL and spotted one interesting thing. If IRQL is raised to HIGH_LEVEL, then KeGetCurrentIrql will return wrong ifno about IRQL:

    .text:800123B8 ; __fastcall KfRaiseIrql(x)
    .text:800123B8                 public @KfRaiseIrql@4
    .text:800123B8 @KfRaiseIrql@4  proc near     
    .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]

    .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:

    .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?
Page 1 of 2 12 LastLast