D041-遍历指进程句柄权限+修改权限

2021在线班
郁金香灬老师 QQ 150330575
交流群:158280115
学习目标 
   windbg调试技巧
   逆向分析
   windbg访问断点
   dt查看结构指令

windbg使用帮助
参考 https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/commands
 
 https://www.jianshu.com/p/1dcf0b246667?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
 
 typedef struct _HANDLE_TABLE_ENTRY                  // 8 elements, 0x10 bytes (sizeof) 
{
    union                                           // 4 elements, 0x8 bytes (sizeof)  
    {
        /*0x000*/         VOID*        Object;//这里去掉最低3位指向 _object_header
        /*0x000*/         ULONG32      ObAttributes;
        /*0x000*/         PVOID* InfoTable;
        /*0x000*/         UINT64       Value;
    };
    union                                           // 3 elements, 0x8 bytes (sizeof)  
    {
        /*0x008*/         ULONG32      GrantedAccess;//权限
        struct                                      // 2 elements, 0x8 bytes (sizeof)  
        {
            /*0x008*/             UINT16       GrantedAccessIndex;
            /*0x00A*/             UINT16       CreatorBackTraceIndex;
            /*0x00C*/             UINT8        _PADDING0_[0x4];
        };
        /*0x008*/         ULONG32      NextFreeTableEntry;
    };
}HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;


 
PHANDLE_TABLE_ENTRY ExpLookupHandleTableEntry (
    IN PHANDLE_TABLE HandleTable,//参数1是句柄表的地址，即 TableCode，注意，这里 TableCode 的低位不能清零，函数里要判断句柄表结构的。
    IN EXHANDLE Handle//参数2是句柄值，PID 的值就是一个句柄值，调用 OpenProcess 打开一个进程得到的也是句柄值，前者用来索引全局句柄表，后者用来索引进程的句柄表。
    )
	
 



 typedef struct _HANDLE_TABLE                         // 15 elements, 0x68 bytes (sizeof) 
{
    /*0x000*/     UINT64       TableCode;  //关键一项
    /*0x008*/     struct _EPROCESS* QuotaProcess;
    /*0x010*/     VOID*        UniqueProcessId;
    /*0x018*/     UINT64 HandleLock;                 // 7 elements, 0x8 bytes (sizeof)   
    /*0x020*/     struct _LIST_ENTRY HandleTableList;              // 2 elements, 0x10 bytes (sizeof)  
    /*0x030*/     UINT64 HandleContentionEvent;      // 7 elements, 0x8 bytes (sizeof)   
    /*0x038*/     PVOID DebugInfo;
    /*0x040*/     LONG32       ExtraInfoPages;
    union                                            // 2 elements, 0x4 bytes (sizeof)   
    {
        /*0x044*/         ULONG32      Flags;
        /*0x044*/         UINT8        StrictFIFO : 1;                 // 0 BitPosition                    
    };
    /*0x048*/     ULONG32      FirstFreeHandle;
    /*0x04C*/     UINT8        _PADDING0_[0x4];
    /*0x050*/     struct _HANDLE_TABLE_ENTRY* LastFreeHandleEntry;
    /*0x058*/     ULONG32      HandleCount;
    /*0x05C*/     ULONG32      NextHandleNeedingPool;
    /*0x060*/     ULONG32      HandleCountHighWatermark;
    /*0x064*/     UINT8        _PADDING1_[0x4];
}HANDLE_TABLE, *PHANDLE_TABLE;

假如只有一项,TableCode指向的内容是HANDLE_TABLE_ENTRY数组,低3位表示是否是2,3级表:

 typedef struct _HANDLE_TABLE_ENTRY                  // 8 elements, 0x10 bytes (sizeof) 
{
    union                                           // 4 elements, 0x8 bytes (sizeof)  
    {
        /*0x000*/         VOID*        Object;//这里去掉最低3位指向_object_header
        /*0x000*/         ULONG32      ObAttributes;
        /*0x000*/         PVOID* InfoTable;
        /*0x000*/         UINT64       Value;
    };
    union                                           // 3 elements, 0x8 bytes (sizeof)  
    {
        /*0x008*/         ULONG32      GrantedAccess;
        struct                                      // 2 elements, 0x8 bytes (sizeof)  
        {
            /*0x008*/             UINT16       GrantedAccessIndex;
            /*0x00A*/             UINT16       CreatorBackTraceIndex;
            /*0x00C*/             UINT8        _PADDING0_[0x4];
        };
        /*0x008*/         ULONG32      NextFreeTableEntry;
    };
}HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;

一个进程的句柄值handle/4=index, handle_table[index].object=目标对象的对象头


kd> dt _handle_table fffff8a0`00004880
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0xfffff8a0`01201001  低4个bit非0说明是2-4级表
   +0x008 QuotaProcess     : (null) 
   +0x010 UniqueProcessId  : (null) 
   +0x018 HandleLock       : _EX_PUSH_LOCK
   +0x020 HandleTableList  : _LIST_ENTRY [ 0xfffff8a0`000048a0 - 0xfffff8a0`000048a0 ]
   +0x030 HandleContentionEvent : _EX_PUSH_LOCK
   +0x038 DebugInfo        : (null) 
   +0x040 ExtraInfoPages   : 0n0
   +0x044 Flags            : 1
   +0x044 StrictFIFO       : 0y1
   +0x048 FirstFreeHandle  : 0x3b0
   +0x050 LastFreeHandleEntry : 0xfffff8a0`01202e70 _HANDLE_TABLE_ENTRY
   +0x058 HandleCount      : 0x228
   +0x05c NextHandleNeedingPool : 0xc00

kd> dq 0xfffff8a0`01201000
fffff8a0`01201000  fffff8a0`00005000 fffff8a0`01202000
fffff8a0`01201010  fffff8a0`01831000 00000000`00000000
fffff8a0`01201020  00000000`00000000 00000000`00000000


kd> dt _handle_table_entry fffff8a0`00005010
nt!_HANDLE_TABLE_ENTRY
   +0x000 Object           : 0xfffffa80`18dc5741 Void system进程的eprocess
   +0x000 ObAttributes     : 0x18dc5741
   +0x000 InfoTable        : 0xfffffa80`18dc5741 _HANDLE_TABLE_ENTRY_INFO
   +0x000 Value            : 0xfffffa80`18dc5741
   +0x008 GrantedAccess    : 0
   +0x008 GrantedAccessIndex : 0
   +0x00a CreatorBackTraceIndex : 0
   +0x008 NextFreeTableEntry : 0

kd> !process 0 0 system
PROCESS fffffa8018dc5740
    SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00187000  ObjectTable: fffff8a000001780  HandleCount: 507.
    Image: System


一级表遍历方法: pid=0x110
kd> db poi(fffff8a0`00005000+0x10*(110/4))-1+0x2e0
fffffa80`1ad37e10  73 76 63 68 6f 73 74 2e-65 78 65 00 00 00 00 02  svchost.exe.....
fffffa80`1ad37e20  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fffffa80`1ad37e30  00 00 00 00 00 00 00 00-c0 9d d3 1a 80 fa ff ff  ................
fffffa80`1ad37e40  80 6f da 1a 80 fa ff ff-00 00 00 00 00 00 00 00  .o..............
fffffa80`1ad37e50  00 00 00 00 00 00 00 00-0e 00 00 00 c5 ef db f5  ................
fffffa80`1ad37e60  00 00 00 00 00 00 00 00-00 e0 fd ff ff 07 00 00  ................
fffffa80`1ad37e70  00 00 00 00 00 00 00 00-3c 08 00 00 00 00 00 00  ........<.......
fffffa80`1ad37e80  06 00 00 00 00 00 00 00-c1 2f 00 00 00 00 00 00  ........./......

二级表遍历方法:pid=0x460
kd> db poi(poi(fffff8a0`01201000+8)+0x10*((460-0x400)/4))-1+0x2e0
fffffa80`1ad48340  73 70 6f 6f 6c 73 76 2e-65 78 65 00 00 00 00 02  spoolsv.exe.....
fffffa80`1ad48350  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fffffa80`1ad48360  00 00 00 00 00 00 00 00-80 24 d4 1a 80 fa ff ff  .........$......
fffffa80`1ad48370  70 1d 15 1b 80 fa ff ff-00 00 00 00 00 00 00 00  p...............
fffffa80`1ad48380  00 00 00 00 00 00 00 00-0c 00 00 00 39 ff d0 e4  ............9...
fffffa80`1ad48390  00 00 00 00 00 00 00 00-00 40 fd ff ff 07 00 00  .........@......
fffffa80`1ad483a0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fffffa80`1ad483b0  00 00 00 00 00 00 00 00-c4 02 00 00 00 00 00 00  ................

每个表最大的句柄值为0x400,超过的为(pid-0x400)/4






PHANDLE_TABLE_ENTRY
ExpLookupHandleTableEntry (
    IN PHANDLE_TABLE HandleTable,
    IN EXHANDLE Handle
    )

/*++

Routine Description:

    This routine looks up and returns the table entry for the
    specified handle value.

Arguments:

    HandleTable - Supplies the handle table being queried

    Handle - Supplies the handle value being queried

Return Value:

    Returns a pointer to the corresponding table entry for the input
        handle.  Or NULL if the handle value is invalid (i.e., too large
        for the tables current allocation.

--*/

{
    ULONG_PTR i,j,k;
    ULONG_PTR CapturedTable;
    ULONG TableLevel;
    PHANDLE_TABLE_ENTRY Entry;

    typedef HANDLE_TABLE_ENTRY *L1P;
    typedef volatile L1P *L2P;
    typedef volatile L2P *L3P;

    L1P TableLevel1;
    L2P TableLevel2;
    L3P TableLevel3;

    ULONG_PTR RemainingIndex;
    ULONG_PTR MaxHandle;
    ULONG_PTR Index;

    PAGED_CODE();


    //
    // Extract the handle index
    //
    Handle.TagBits = 0; // 低2位清零
    Index = Handle.Index; // 取31-2位作为句柄表下标

    MaxHandle = *(volatile ULONG *) &HandleTable->NextHandleNeedingPool;

    //
    // See if this can be a valid handle given the table levels.
    //
    if (Handle.Value >= MaxHandle) {
        return NULL;        
    }

    //
    // Now fetch the table address and level bits. We must preserve the
    // ordering here.
    //
    CapturedTable = *(volatile ULONG_PTR *) &HandleTable->TableCode;

    //
    //  we need to capture the current table. This routine is lock free
    //  so another thread may change the table at HandleTable->TableCode
    //

    TableLevel = (ULONG)(CapturedTable & LEVEL_CODE_MASK); // LEVEL_CODE_MASK == 3
    CapturedTable = CapturedTable & ~LEVEL_CODE_MASK;

    //  The lookup code depends on number of levels we have

    switch (TableLevel) {
        
        case 0:
            //  We have a simple index into the array, for a single level
            //  handle table
            TableLevel1 = (L1P) CapturedTable;
            Entry = &(TableLevel1[Index]);
            break;        
        case 1:
            //
            //  we have a 2 level handle table. We need to get the upper index
            //  and lower index into the array
            //

            TableLevel2 = (L2P) CapturedTable;                
			// LOWLEVEL_COUNT == 512 //0x200 //win7 64 0x400?
            i = Index / LOWLEVEL_COUNT; // 计算属于第几张句柄表
            j = Index % LOWLEVEL_COUNT; // 计算在句柄表内的偏移
            Entry = &(TableLevel2[i][j]);

            break;
        
        case 2:
            
            //
            //  We have here a three level handle table.
            //

            TableLevel3 = (L3P) CapturedTable;

            //
            //  Calculate the 3 indexes we need
            //
                
			// MIDLEVEL_THRESHOLD == 1024 * 512 //0x80000
            i = Index / (MIDLEVEL_THRESHOLD);//0x80000
            RemainingIndex = Index - i * MIDLEVEL_THRESHOLD; // RemainingIndex=Index%0x80000
            j = RemainingIndex / LOWLEVEL_COUNT;
            k = RemainingIndex % LOWLEVEL_COUNT;
            Entry = &(TableLevel3[i][j][k]);

            break;

        default :
            _assume (0);
    }

    return Entry;
}


: kd> u ExpLookupHandleTableEntry l 20
nt!ExpLookupHandleTableEntry:
fffff800`041cef90 8b415c          mov     eax,dword ptr [rcx+5Ch]
fffff800`041cef93 4889542408      mov     qword ptr [rsp+8],rdx
fffff800`041cef98 83e2fc          and     edx,0FFFFFFFCh
fffff800`041cef9b 89542408        mov     dword ptr [rsp+8],edx
fffff800`041cef9f 4c8b4c2408      mov     r9,qword ptr [rsp+8]
fffff800`041cefa4 4c3bc8          cmp     r9,rax
fffff800`041cefa7 7339            jae     nt!ExpLookupHandleTableEntry+0x52 (fffff800`041cefe2)
fffff800`041cefa9 4c8b01          mov     r8,qword ptr [rcx]
fffff800`041cefac 418bc8          mov     ecx,r8d
fffff800`041cefaf 83e103          and     ecx,3
fffff800`041cefb2 8bc1            mov     eax,ecx
fffff800`041cefb4 4c2bc0          sub     r8,rax
fffff800`041cefb7 85c9            test    ecx,ecx 一级表
fffff800`041cefb9 7422            je      nt!ExpLookupHandleTableEntry+0x4d (fffff800`041cefdd)
fffff800`041cefbb 83f901          cmp     ecx,1 
fffff800`041cefbe 0f857c420300    jne     nt! ?? ::NNGAKEGL::`string'+0x2230 (fffff800`04203240)

fffff800`041cefc4 498bc9          mov     rcx,r9 二级表算法
fffff800`041cefc7 81e1ff030000    and     ecx,3FFh
fffff800`041cefcd 4c2bc9          sub     r9,rcx
fffff800`041cefd0 49c1e907        shr     r9,7
fffff800`041cefd4 4b8b0401        mov     rax,qword ptr [r9+r8]
fffff800`041cefd8 488d0488        lea     rax,[rax+rcx*4] _HANDLE_TABLE_ENTRY
fffff800`041cefdc c3              ret
一级表算法
fffff800`041cefdd 4b8d0488        lea     rax,[r8+r9*4] _HANDLE_TABLE_ENTRY
fffff800`041cefe1 c3              ret
fffff800`041cefe2 33c0            xor     eax,eax
fffff800`041cefe4 c3              ret
fffff800`041cefe5 90              nop
fffff800`041cefe6 90              nop
fffff800`041cefe7 90              nop
fffff800`041cefe8 90              nop
fffff800`041cefe9 90              nop
3: kd> u fffff800`04203240 
 
nt! ?? ::NNGAKEGL::`string'+0x2230:
fffff800`04203240 498bd1          mov     rdx,r9 三级表算法 
fffff800`04203243 81e2ff030000    and     edx,3FFh
fffff800`04203249 4c2bca          sub     r9,rdx
fffff800`0420324c 49c1e907        shr     r9,7
fffff800`04203250 498bc9          mov     rcx,r9
fffff800`04203253 81e1ff0f0000    and     ecx,0FFFh
fffff800`04203259 4c2bc9          sub     r9,rcx
fffff800`0420325c 49c1e909        shr     r9,9
fffff800`04203260 4b8b0401        mov     rax,qword ptr [r9+r8]
fffff800`04203264 488b0c08        mov     rcx,qword ptr [rax+rcx]
fffff800`04203268 488d0491        lea     rax,[rcx+rdx*4] _HANDLE_TABLE_ENTRY
fffff800`0420326c c3              ret
 
 
 
kd> dq handleobj
fffff880`068e07a0  00fffff8`a00415d0 00000000`00000008

rbx=fffff8a003142480 


r8 _HANDLE_TABLE->TableCode
//编号0的表走这里 第1张表
fffff800`041ba1b7 4b8d1c88        lea     rbx,[r8+r9*4] //取句柄表  r9=8140 句柄 第0张表走这里

//编号1的表走这里 第2张表
fffff800`041ba2fa 498bc9          mov     rcx,r9 句柄 0x8140
fffff800`041ba2fd 81e1ff030000    and     ecx,3FFh ecx=0140   取0x400的余数
fffff800`041ba303 4c2bc9          sub     r9,rcx  r9=0x8140-0x140=0x8000
fffff800`041ba306 49c1e907        shr     r9,7   0x8000>>7=0x100    0x8000/0x80=0x100
fffff800`041ba30a 4b8b0401        mov     rax,qword ptr [r9+r8]  [TableCode+0x100]+140*4  //  dd   poi(fffff8a001f17000+100)+140*4 //OK
fffff800`041ba30e 488d1c88        lea     rbx,[rax+rcx*4]



//编号2的表走这里 第3张表
fffff800`0411de92 498bd1          mov     rdx,r9 句柄 0x18140
fffff800`0411de95 81e2ff030000    and     edx,3FFh
fffff800`0411de9b 4c2bca          sub     r9,rdx
fffff800`0411de9e 49c1e907        shr     r9,7
fffff800`0411dea2 498bc9          mov     rcx,r9
fffff800`0411dea5 81e1ff0f0000    and     ecx,0FFFh
fffff800`0411deab 4c2bc9          sub     r9,rcx
fffff800`0411deae 49c1e909        shr     r9,9
fffff800`0411deb2 4b8b0401        mov     rax,qword ptr [r9+r8]
fffff800`0411deb6 488b0c08        mov     rcx,qword ptr [rax+rcx]
fffff800`0411deba 488d1c91        lea     rbx,[rcx+rdx*4]




0: kd> u nt!ObReferenceObjectByHandleWithTag l 100
nt!ObReferenceObjectByHandleWithTag:
fffff800`041ba0e0 44884c2420      mov     byte ptr [rsp+20h],r9b
fffff800`041ba0e5 4c89442418      mov     qword ptr [rsp+18h],r8
fffff800`041ba0ea 89542410        mov     dword ptr [rsp+10h],edx
fffff800`041ba0ee 53              push    rbx
fffff800`041ba0ef 55              push    rbp
fffff800`041ba0f0 56              push    rsi
fffff800`041ba0f1 57              push    rdi
fffff800`041ba0f2 4154            push    r12
fffff800`041ba0f4 4155            push    r13
fffff800`041ba0f6 4156            push    r14
fffff800`041ba0f8 4157            push    r15
fffff800`041ba0fa 4881ec88000000  sub     rsp,88h
fffff800`041ba101 65488b3c2588010000 mov   rdi,qword ptr gs:[188h]
fffff800`041ba10a 488b9c24f8000000 mov     rbx,qword ptr [rsp+0F8h]
fffff800`041ba112 4533e4          xor     r12d,r12d
fffff800`041ba115 4c8b7f70        mov     r15,qword ptr [rdi+70h] //进程PEP

fffff800`040d5e46 498bcf          mov     rcx,r15
fffff800`040d5e49 e82e630800      call    nt!ObReferenceProcessHandleTable (fffff800`0415c17c)  tableCode=ObReferenceProcessHandleTable(PEPROCESS)
fffff800`040d5e4e 40b501          mov     bpl,1
fffff800`040d5e51 488bf0          mov     rsi,rax
fffff800`040d5e54 4088ac24d0000000 mov     byte ptr [rsp+0D0h],bpl
fffff800`040d5e5c e9f6c20900      jmp     nt!ObReferenceObjectByHandleWithTag+0x77 (fffff800`04172157)
fffff800`040d5e61 4080fd01        cmp     bpl,1
fffff800`040d5e65 7521            jne     nt! ?? ::NNGAKEGL::`string'+0x2027e (fffff800`040d5e88)

nt!ObReferenceProcessHandleTable:
fffff800`0415c17c fff3            push    rbx
fffff800`0415c17e 4883ec20        sub     rsp,20h
fffff800`0415c182 4c8bc1          mov     r8,rcx //有一个参数
fffff800`0415c185 4881c178010000  add     rcx,178h
fffff800`0415c18c 0f0d09          prefetchw [rcx]
fffff800`0415c18f 488b01          mov     rax,qword ptr [rcx]
fffff800`0415c192 4883e0fe        and     rax,0FFFFFFFFFFFFFFFEh
fffff800`0415c196 488d5002        lea     rdx,[rax+2]
fffff800`0415c19a f0480fb111      lock cmpxchg qword ptr [rcx],rdx
fffff800`0415c19f 0f85bbf80400    jne     nt! ?? ::NNGAKEGL::`string'+0x7af0 (fffff800`041aba60)
fffff800`0415c1a5 498b9800020000  mov     rbx,qword ptr [r8+200h]
fffff800`0415c1ac 4885db          test    rbx,rbx
fffff800`0415c1af 0f84bff80400    je      nt! ?? ::NNGAKEGL::`string'+0x7b04 (fffff800`041aba74)
fffff800`0415c1b5 488bc3          mov     rax,rbx
fffff800`0415c1b8 4883c420        add     rsp,20h
fffff800`0415c1bc 5b              pop     rbx
fffff800`0415c1bd c3              ret

