在上一篇文章《驱动开发:内核枚举DpcTimer定时器》中我们通过枚举特征码的方式找到了DPC定时器基址并输出了内核中存在的定时器列表,本章将学习如何通过特征码定位的方式寻找Windows 10系统下面的PspCidTable内核句柄表地址。
首先引入一段基础概念;
windows下所有的资源都是用对象的方式进行管理的(文件、进程、设备等都是对象),当要访问一个对象时,如打开一个文件,系统就会创建一个对象句柄,通过这个句柄可以对这个文件进行各种操作。PspCidTable 就是这样的一种表(内核句柄表),表的内部存放的是进程EPROCESS和线程ETHREAD的内核对象,并通过进程PID和线程TID进行索引,ID号以4递增,内核句柄表不属于任何进程,也不连接在系统的句柄表上,通过它可以返回系统的任何对象。
内核句柄表与普通句柄表完全一样,但它与每个进程私有的句柄表有以下不同;
PID和TID。EPROCESS和ETHREAD,而每个进程私有的句柄表则存放的是对象头OBJECT_HEADER。那么在Windows10系统中该如何枚举句柄表;
PsLookupProcessByProcessId函数地址,该函数是被导出的可以动态拿到。PsLookupProcessByProcessId地址中搜索PspReferenceCidTableEntry函数。PspReferenceCidTableEntry地址中找到PspCidTable函数。首先第一步先要得到PspCidTable函数内存地址,输入dp PspCidTable即可得到,如果在程序中则是调用MmGetSystemRoutineAddress取到。
 
PspCidTable是一个HANDLE_TALBE结构,当新建一个进程时,对应的会在PspCidTable存在一个该进程和线程对应的HANDLE_TABLE_ENTRY项。在windows10中依然采用动态扩展的方法,当句柄数少的时候就采用下层表,多的时候才启用中层表或上层表。
接着我们解析ffffdc88-79605dc0这个内存地址,执行dt _HANDLE_TABLE 0xffffdc8879605dc0得到规范化结构体。
 
内核句柄表分为三层如下;
HANDLE_TABLE_ENTRY项的索引,整个表共有256个元素,每个元素是一个8个字节长的HANDLE_TABLE_ENTRY项及索引,HANDLE_TABLE_ENTRY项中保存着指向对象的指针,下层表可以看成是进程和线程的稠密索引。256个元素,每个元素是4个字节长的指向下层表的入口指针及索引,中层表可以看成是进程和线程的稀疏索引。256个元素,每个元素是4个字节长的指向中层表的入口指针及索引,上层表可以看成是中层表的稀疏索引。总结起来一个句柄表有一个上层表,一个上层表最多可以有256个中层表的入口指针,每个中层表最多可以有256个下层表的入口指针,每个下层表最多可以有256个进程和线程对象的指针。PspCidTable表可以看成是HANDLE_TBALE_ENTRY项的多级索引。
如上图所示TableCode是指向句柄表的指针,低二位(二进制)记录句柄表的等级:0(00)表示一级表,1(01)表示二级表,2(10)表示三级表。这里的 0xffffdc88-7d09b001 就说名它是一个二级表。
 
一级表里存放的就是进程和线程对象(加密过的,需要一些计算来解密),二级表里存放的是指向某个一级表的指针,同理三级表存放的是指向二级表的指针。
x64 系统中,每张表的大小是 0x1000(4096),一级表中存放的是 _handle_table_entry 结构(大小 = 16),二级表和三级表存放的是指针(大小 = 8)。
我们对 0xffffdc88-7d09b001 抹去低二位,输入dp 0xffffdc887d09b000 输出的结果就是一张二级表,里面存储的就是一级表指针。
 
继续查看第一张一级表,输入dp 0xffffdc887962a000命令,我们知道一级句柄表是根据进程或线程ID来索引的,且以4累加,所以第一行对应id = 0,第二行对应id = 4。根据尝试,PID = 4的进程是System。
 
所以此处的第二行0xb281de28-3300ffa7就是加密后的System进程的EPROCESS结构,对于Win10系统来说解密算法(value >> 0x10) & 0xfffffffffffffff0是这样的,我们通过代码计算出来。
| 
      
      1
      
     
      2
      
     
      3
      
     
      4
      
     
      5
      
     
      6
      
     
      7
      
     
      8
      
     
      9
      
     
      10
      
     
      11
      
     
      12
      
     
      13
      
     
      14
      
     
      15
      
     
      16
      
     
      17
       | 
    
     #include <Windows.h>
      #include <iostream>
      int 
       _tmain(
       int 
       argc, _TCHAR
       * 
       argv[])
      {
          
       std::cout << 
       "hello lyshark.com" 
       << std::endl;
          
       ULONG64 ul_recode 
       = 
       0xb281de283300ffa7
       ;
          
       ULONG64 ul_decode 
       = 
       (LONG64)ul_recode >> 
       0x10
       ;
          
       ul_decode &
       = 
       0xfffffffffffffff0
       ;
          
       std::cout << 
       "解密后地址: " 
       << std::
       hex 
       << ul_decode << std::endl;
          
       getchar();
          
       return 
       0
       ;
      }
       | 
   
运行程序得到如下输出,即可知道System系统进程解密后的EPROCESS结构地址是0xffffb281de283300
 
回到WinDBG调试器,输入命令dt _EPROCESS 0xffffb281de283300解析以下这个结构,输出结果是System进程。
 
理论知识总结已经结束了,接下来就是如何实现枚举进程线程了,枚举流程如下:
PspCidTable的地址。HANDLE_TBALE的地址。TableCode来判断层次结构。这里先来实现获取PspCidTable函数的动态地址,代码如下。
| 
      
      1
      
     
      2
      
     
      3
      
     
      4
      
     
      5
      
     
      6
      
     
      7
      
     
      8
      
     
      9
      
     
      10
      
     
      11
      
     
      12
      
     
      13
      
     
      14
      
     
      15
      
     
      16
      
     
      17
      
     
      18
      
     
      19
      
     
      20
      
     
      21
      
     
      22
      
     
      23
      
     
      24
      
     
      25
      
     
      26
      
     
      27
      
     
      28
      
     
      29
      
     
      30
      
     
      31
      
     
      32
      
     
      33
      
     
      34
      
     
      35
      
     
      36
      
     
      37
      
     
      38
      
     
      39
      
     
      40
      
     
      41
      
     
      42
      
     
      43
      
     
      44
      
     
      45
      
     
      46
      
     
      47
      
     
      48
      
     
      49
      
     
      50
      
     
      51
      
     
      52
      
     
      53
      
     
      54
      
     
      55
      
     
      56
      
     
      57
      
     
      58
      
     
      59
      
     
      60
      
     
      61
      
     
      62
      
     
      63
      
     
      64
      
     
      65
      
     
      66
      
     
      67
      
     
      68
      
     
      69
      
     
      70
      
     
      71
      
     
      72
      
     
      73
      
     
      74
      
     
      75
      
     
      76
      
     
      77
      
     
      78
      
     
      79
      
     
      80
      
     
      81
      
     
      82
      
     
      83
      
     
      84
      
     
      85
      
     
      86
      
     
      87
      
     
      88
      
     
      89
      
     
      90
      
     
      91
      
     
      92
      
     
      93
      
     
      94
      
     
      95
      
     
      96
      
     
      97
      
     
      98
      
     
      99
      
     
      100
      
     
      101
      
     
      102
      
     
      103
       | 
    
     #include <ntifs.h>
      #include <windef.h>
      /
       / 
       获取 PspCidTable
      /
       / 
       By: LyShark.com
      BOOLEAN get_PspCidTable(ULONG64
       * 
       tableAddr)
      {
          
       /
       / 
       获取 PsLookupProcessByProcessId 地址
          
       UNICODE_STRING uc_funcName;
          
       RtlInitUnicodeString(&uc_funcName, L
       "PsLookupProcessByProcessId"
       );
          
       ULONG64 ul_funcAddr 
       = 
       MmGetSystemRoutineAddress(&uc_funcName);
          
       if 
       (ul_funcAddr 
       =
       = 
       NULL)
          
       {
              
       return 
       FALSE;
          
       }
          
       DbgPrint(
       "PsLookupProcessByProcessId addr = %p \n"
       , ul_funcAddr);
          
       /
       / 
       前 
       40 
       字节有 call(PspReferenceCidTableEntry)
          
       /
       *
          
       0
       : kd> uf PsLookupProcessByProcessId
              
       nt!PsLookupProcessByProcessId:
              
       fffff802`
       0841cfe0 
       48895c2418      
       mov     qword ptr [rsp
       +
       18h
       ],rbx
              
       fffff802`
       0841cfe5 
       56              
       push    rsi
              
       fffff802`
       0841cfe6 
       4883ec20        
       sub     rsp,
       20h
              
       fffff802`
       0841cfea 
       48897c2438      
       mov     qword ptr [rsp
       +
       38h
       ],rdi
              
       fffff802`
       0841cfef 
       488bf2          
       mov     rsi,rdx
              
       fffff802`
       0841cff2 
       65488b3c2588010000 
       mov   rdi,qword ptr gs:[
       188h
       ]
              
       fffff802`
       0841cffb 
       66ff8fe6010000  
       dec     word ptr [rdi
       +
       1E6h
       ]
              
       fffff802`
       0841d002 
       b203            mov     dl,
       3
              
       fffff802`
       0841d004 
       e887000000      call    nt!PspReferenceCidTableEntry (fffff802`
       0841d090
       )
              
       fffff802`
       0841d009 
       488bd8          
       mov     rbx,rax
              
       fffff802`
       0841d00c 
       4885c0          
       test    rax,rax
              
       fffff802`
       0841d00f 
       7435            
       je      nt!PsLookupProcessByProcessId
       +
       0x66 
       (fffff802`
       0841d046
       )  Branch
          
       *
       /
          
       ULONG64 ul_entry 
       = 
       0
       ;
          
       for 
       (
       INT 
       i 
       = 
       0
       ; i < 
       100
       ; i
       +
       +
       )
          
       {
              
       /
       / 
       fffff802`
       0841d004 
       e8 
       87 
       00 
       00 
       00      
       call    nt!PspReferenceCidTableEntry (fffff802`
       0841d090
       )
              
       if 
       (
       *
       (PUCHAR)(ul_funcAddr 
       + 
       i) 
       =
       = 
       0xe8
       )
              
       {
                  
       ul_entry 
       = 
       ul_funcAddr 
       + 
       i;
                  
       break
       ;
              
       }
          
       }
          
       if 
       (ul_entry !
       = 
       0
       )
          
       {
              
       /
       / 
       解析 call 地址
              
       INT 
       i_callCode 
       = 
       *
       (
       INT
       *
       )(ul_entry 
       + 
       1
       );
              
       DbgPrint(
       "i_callCode = %p \n"
       , i_callCode);
              
       ULONG64 ul_callJmp 
       = 
       ul_entry 
       + 
       i_callCode 
       + 
       5
       ;
              
       DbgPrint(
       "ul_callJmp = %p \n"
       , ul_callJmp);
              
       /
       / 
       来到 call(PspReferenceCidTableEntry) 内找 PspCidTable
              
       /
       *
              
       0
       : kd> uf PspReferenceCidTableEntry
                  
       nt!PspReferenceCidTableEntry
       +
       0x115
       :
                  
       fffff802`
       0841d1a5 
       488b0d8473f5ff  
       mov     rcx,qword ptr [nt!PspCidTable (fffff802`
       08374530
       )]
                  
       fffff802`
       0841d1ac 
       b801000000      mov     eax,
       1
                  
       fffff802`
       0841d1b1 
       f0480fc107      lock xadd qword ptr [rdi],rax
                  
       fffff802`
       0841d1b6 
       4883c130        
       add     rcx,
       30h
                  
       fffff802`
       0841d1ba 
       f0830c2400      lock 
       or 
       dword ptr [rsp],
       0
                  
       fffff802`
       0841d1bf 
       48833900        
       cmp     
       qword ptr [rcx],
       0
                  
       fffff802`
       0841d1c3 
       0f843fffffff    
       je      nt!PspReferenceCidTableEntry
       +
       0x78 
       (fffff802`
       0841d108
       )  Branch
              
       *
       /
              
       for 
       (
       INT 
       i 
       = 
       0
       ; i < 
       0x120
       ; i
       +
       +
       )
              
       {
                  
       /
       / 
       fffff802`
       0841d1a5 
       48 
       8b 
       0d 
       84 
       73 
       f5 ff  mov     rcx,qword ptr [nt!PspCidTable (fffff802`
       08374530
       )]
                  
       if 
       (
       *
       (PUCHAR)(ul_callJmp 
       + 
       i) 
       =
       = 
       0x48 
       && 
       *
       (PUCHAR)(ul_callJmp 
       + 
       i 
       + 
       1
       ) 
       =
       = 
       0x8b 
       && 
       *
       (PUCHAR)(ul_callJmp 
       + 
       i 
       + 
       2
       ) 
       =
       = 
       0x0d
       )
                  
       {
                      
       /
       / 
       解析 mov 地址
                      
       INT 
       i_movCode 
       = 
       *
       (
       INT
       *
       )(ul_callJmp 
       + 
       i 
       + 
       3
       );
                      
       DbgPrint(
       "i_movCode = %p \n"
       , i_movCode);
                      
       ULONG64 ul_movJmp 
       = 
       ul_callJmp 
       + 
       i 
       + 
       i_movCode 
       + 
       7
       ;
                      
       DbgPrint(
       "ul_movJmp = %p \n"
       , ul_movJmp);
                      
       /
       / 
       得到 PspCidTable
                      
       *
       tableAddr 
       = 
       ul_movJmp;
                      
       return 
       TRUE;
                  
       }
              
       }
          
       }
          
       return 
       FALSE;
      }
      VOID UnDriver(PDRIVER_OBJECT driver)
      {
          
       DbgPrint((
       "Uninstall Driver Is OK \n"
       ));
      }
      NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
      {
          
       DbgPrint((
       "hello lyshark \n"
       ));
          
       ULONG64 tableAddr 
       = 
       0
       ;
          
       get_PspCidTable(&tableAddr);
          
       DbgPrint(
       "PspCidTable Address = %p \n"
       , tableAddr);
          
       Driver
       -
       >DriverUnload 
       = 
       UnDriver;
          
       return 
       STATUS_SUCCESS;
      }
       | 
   
运行后即可得到动态地址,我们可以验证一下是否一致:
 
继续增加对与三级表的动态解析代码,最终代码如下所示:
| 
      
      1
      
     
      2
      
     
      3
      
     
      4
      
     
      5
      
     
      6
      
     
      7
      
     
      8
      
     
      9
      
     
      10
      
     
      11
      
     
      12
      
     
      13
      
     
      14
      
     
      15
      
     
      16
      
     
      17
      
     
      18
      
     
      19
      
     
      20
      
     
      21
      
     
      22
      
     
      23
      
     
      24
      
     
      25
      
     
      26
      
     
      27
      
     
      28
      
     
      29
      
     
      30
      
     
      31
      
     
      32
      
     
      33
      
     
      34
      
     
      35
      
     
      36
      
     
      37
      
     
      38
      
     
      39
      
     
      40
      
     
      41
      
     
      42
      
     
      43
      
     
      44
      
     
      45
      
     
      46
      
     
      47
      
     
      48
      
     
      49
      
     
      50
      
     
      51
      
     
      52
      
     
      53
      
     
      54
      
     
      55
      
     
      56
      
     
      57
      
     
      58
      
     
      59
      
     
      60
      
     
      61
      
     
      62
      
     
      63
      
     
      64
      
     
      65
      
     
      66
      
     
      67
      
     
      68
      
     
      69
      
     
      70
      
     
      71
      
     
      72
      
     
      73
      
     
      74
      
     
      75
      
     
      76
      
     
      77
      
     
      78
      
     
      79
      
     
      80
      
     
      81
      
     
      82
      
     
      83
      
     
      84
      
     
      85
      
     
      86
      
     
      87
      
     
      88
      
     
      89
      
     
      90
      
     
      91
      
     
      92
      
     
      93
      
     
      94
      
     
      95
      
     
      96
      
     
      97
      
     
      98
      
     
      99
      
     
      100
      
     
      101
      
     
      102
      
     
      103
      
     
      104
      
     
      105
      
     
      106
      
     
      107
      
     
      108
      
     
      109
      
     
      110
      
     
      111
      
     
      112
      
     
      113
      
     
      114
      
     
      115
      
     
      116
      
     
      117
      
     
      118
      
     
      119
      
     
      120
      
     
      121
      
     
      122
      
     
      123
      
     
      124
      
     
      125
      
     
      126
      
     
      127
      
     
      128
      
     
      129
      
     
      130
      
     
      131
      
     
      132
      
     
      133
      
     
      134
      
     
      135
      
     
      136
      
     
      137
      
     
      138
      
     
      139
      
     
      140
      
     
      141
      
     
      142
      
     
      143
      
     
      144
      
     
      145
      
     
      146
      
     
      147
      
     
      148
      
     
      149
      
     
      150
      
     
      151
      
     
      152
      
     
      153
      
     
      154
      
     
      155
      
     
      156
      
     
      157
      
     
      158
      
     
      159
      
     
      160
      
     
      161
      
     
      162
      
     
      163
      
     
      164
      
     
      165
      
     
      166
      
     
      167
      
     
      168
      
     
      169
      
     
      170
      
     
      171
      
     
      172
      
     
      173
      
     
      174
      
     
      175
      
     
      176
      
     
      177
      
     
      178
      
     
      179
      
     
      180
      
     
      181
      
     
      182
      
     
      183
      
     
      184
      
     
      185
      
     
      186
      
     
      187
      
     
      188
      
     
      189
      
     
      190
      
     
      191
      
     
      192
      
     
      193
      
     
      194
      
     
      195
      
     
      196
      
     
      197
      
     
      198
      
     
      199
      
     
      200
      
     
      201
      
     
      202
      
     
      203
      
     
      204
      
     
      205
      
     
      206
      
     
      207
      
     
      208
      
     
      209
      
     
      210
      
     
      211
      
     
      212
      
     
      213
      
     
      214
      
     
      215
      
     
      216
      
     
      217
      
     
      218
      
     
      219
      
     
      220
      
     
      221
      
     
      222
      
     
      223
       | 
    
     #include <ntifs.h>
      #include <windef.h>
      /
       / 
       获取 PspCidTable
      /
       / 
       By: LyShark.com
      BOOLEAN get_PspCidTable(ULONG64
       * 
       tableAddr)
      {
          
       /
       / 
       获取 PsLookupProcessByProcessId 地址
          
       UNICODE_STRING uc_funcName;
          
       RtlInitUnicodeString(&uc_funcName, L
       "PsLookupProcessByProcessId"
       );
          
       ULONG64 ul_funcAddr 
       = 
       MmGetSystemRoutineAddress(&uc_funcName);
          
       if 
       (ul_funcAddr 
       =
       = 
       NULL)
          
       {
              
       return 
       FALSE;
          
       }
          
       DbgPrint(
       "PsLookupProcessByProcessId addr = %p \n"
       , ul_funcAddr);
          
       /
       / 
       前 
       40 
       字节有 call(PspReferenceCidTableEntry)
          
       /
       *
          
       0
       : kd> uf PsLookupProcessByProcessId
              
       nt!PsLookupProcessByProcessId:
              
       fffff802`
       0841cfe0 
       48895c2418      
       mov     qword ptr [rsp
       +
       18h
       ],rbx
              
       fffff802`
       0841cfe5 
       56              
       push    rsi
              
       fffff802`
       0841cfe6 
       4883ec20        
       sub     rsp,
       20h
              
       fffff802`
       0841cfea 
       48897c2438      
       mov     qword ptr [rsp
       +
       38h
       ],rdi
              
       fffff802`
       0841cfef 
       488bf2          
       mov     rsi,rdx
              
       fffff802`
       0841cff2 
       65488b3c2588010000 
       mov   rdi,qword ptr gs:[
       188h
       ]
              
       fffff802`
       0841cffb 
       66ff8fe6010000  
       dec     word ptr [rdi
       +
       1E6h
       ]
              
       fffff802`
       0841d002 
       b203            mov     dl,
       3
              
       fffff802`
       0841d004 
       e887000000      call    nt!PspReferenceCidTableEntry (fffff802`
       0841d090
       )
              
       fffff802`
       0841d009 
       488bd8          
       mov     rbx,rax
              
       fffff802`
       0841d00c 
       4885c0          
       test    rax,rax
              
       fffff802`
       0841d00f 
       7435            
       je      nt!PsLookupProcessByProcessId
       +
       0x66 
       (fffff802`
       0841d046
       )  Branch
          
       *
       /
          
       ULONG64 ul_entry 
       = 
       0
       ;
          
       for 
       (
       INT 
       i 
       = 
       0
       ; i < 
       100
       ; i
       +
       +
       )
          
       {
              
       /
       / 
       fffff802`
       0841d004 
       e8 
       87 
       00 
       00 
       00      
       call    nt!PspReferenceCidTableEntry (fffff802`
       0841d090
       )
              
       if 
       (
       *
       (PUCHAR)(ul_funcAddr 
       + 
       i) 
       =
       = 
       0xe8
       )
              
       {
                  
       ul_entry 
       = 
       ul_funcAddr 
       + 
       i;
                  
       break
       ;
              
       }
          
       }
          
       if 
       (ul_entry !
       = 
       0
       )
          
       {
              
       /
       / 
       解析 call 地址
              
       INT 
       i_callCode 
       = 
       *
       (
       INT
       *
       )(ul_entry 
       + 
       1
       );
              
       DbgPrint(
       "i_callCode = %p \n"
       , i_callCode);
              
       ULONG64 ul_callJmp 
       = 
       ul_entry 
       + 
       i_callCode 
       + 
       5
       ;
              
       DbgPrint(
       "ul_callJmp = %p \n"
       , ul_callJmp);
              
       /
       / 
       来到 call(PspReferenceCidTableEntry) 内找 PspCidTable
              
       /
       *
              
       0
       : kd> uf PspReferenceCidTableEntry
                  
       nt!PspReferenceCidTableEntry
       +
       0x115
       :
                  
       fffff802`
       0841d1a5 
       488b0d8473f5ff  
       mov     rcx,qword ptr [nt!PspCidTable (fffff802`
       08374530
       )]
                  
       fffff802`
       0841d1ac 
       b801000000      mov     eax,
       1
                  
       fffff802`
       0841d1b1 
       f0480fc107      lock xadd qword ptr [rdi],rax
                  
       fffff802`
       0841d1b6 
       4883c130        
       add     rcx,
       30h
                  
       fffff802`
       0841d1ba 
       f0830c2400      lock 
       or 
       dword ptr [rsp],
       0
                  
       fffff802`
       0841d1bf 
       48833900        
       cmp     
       qword ptr [rcx],
       0
                  
       fffff802`
       0841d1c3 
       0f843fffffff    
       je      nt!PspReferenceCidTableEntry
       +
       0x78 
       (fffff802`
       0841d108
       )  Branch
              
       *
       /
              
       for 
       (
       INT 
       i 
       = 
       0
       ; i < 
       0x120
       ; i
       +
       +
       )
              
       {
                  
       /
       / 
       fffff802`
       0841d1a5 
       48 
       8b 
       0d 
       84 
       73 
       f5 ff  mov     rcx,qword ptr [nt!PspCidTable (fffff802`
       08374530
       )]
                  
       if 
       (
       *
       (PUCHAR)(ul_callJmp 
       + 
       i) 
       =
       = 
       0x48 
       && 
       *
       (PUCHAR)(ul_callJmp 
       + 
       i 
       + 
       1
       ) 
       =
       = 
       0x8b 
       && 
       *
       (PUCHAR)(ul_callJmp 
       + 
       i 
       + 
       2
       ) 
       =
       = 
       0x0d
       )
                  
       {
                      
       /
       / 
       解析 mov 地址
                      
       INT 
       i_movCode 
       = 
       *
       (
       INT
       *
       )(ul_callJmp 
       + 
       i 
       + 
       3
       );
                      
       DbgPrint(
       "i_movCode = %p \n"
       , i_movCode);
                      
       ULONG64 ul_movJmp 
       = 
       ul_callJmp 
       + 
       i 
       + 
       i_movCode 
       + 
       7
       ;
                      
       DbgPrint(
       "ul_movJmp = %p \n"
       , ul_movJmp);
                      
       /
       / 
       得到 PspCidTable
                      
       *
       tableAddr 
       = 
       ul_movJmp;
                      
       return 
       TRUE;
                  
       }
              
       }
          
       }
          
       return 
       FALSE;
      }
      /
       * 
       解析一级表
      /
       / 
       By: LyShark.com
      BaseAddr:一级表的基地址
      index1:第几个一级表
      index2:第几个二级表
      *
       /
      VOID parse_table_1(ULONG64 BaseAddr, 
       INT 
       index1, 
       INT 
       index2)
      {
          
       /
       / 
       遍历一级表(每个表项大小 
       16 
       ),表大小 
       4k
       ,所以遍历 
       4096
       /
       16 
       = 
       526 
       次
          
       PEPROCESS p_eprocess 
       = 
       NULL;
          
       PETHREAD p_ethread 
       = 
       NULL;
          
       INT 
       i_id 
       = 
       0
       ;
          
       for 
       (
       INT 
       i 
       = 
       0
       ; i < 
       256
       ; i
       +
       +
       )
          
       {
              
       if 
       (!MmIsAddressValid((PVOID64)(BaseAddr 
       + 
       i 
       * 
       16
       )))
              
       {
                  
       DbgPrint(
       "非法地址= %p \n"
       , BaseAddr 
       + 
       i 
       * 
       16
       );
                  
       continue
       ;
              
       }
              
       ULONG64 ul_recode 
       = 
       *
       (PULONG64)(BaseAddr 
       + 
       i 
       * 
       16
       );
              
       /
       / 
       解密
              
       ULONG64 ul_decode 
       = 
       (LONG64)ul_recode >> 
       0x10
       ;
              
       ul_decode &
       = 
       0xfffffffffffffff0
       ;
              
       /
       / 
       判断是进程还是线程
              
       i_id 
       = 
       i 
       * 
       4 
       + 
       1024 
       * 
       index1 
       + 
       512 
       * 
       index2 
       * 
       1024
       ;
              
       if 
       (PsLookupProcessByProcessId(i_id, &p_eprocess) 
       =
       = 
       STATUS_SUCCESS)
              
       {
                  
       DbgPrint(
       "进程PID: %d | ID: %d | 内存地址: %p | 对象: %p \n"
       , i_id, i, BaseAddr 
       + 
       i 
       * 
       0x10
       , ul_decode);
              
       }
              
       else 
       if 
       (PsLookupThreadByThreadId(i_id, &p_ethread) 
       =
       = 
       STATUS_SUCCESS)
              
       {
                  
       DbgPrint(
       "线程TID: %d | ID: %d | 内存地址: %p | 对象: %p \n"
       , i_id, i, BaseAddr 
       + 
       i 
       * 
       0x10
       , ul_decode);
              
       }
          
       }
      }
      /
       * 
       解析二级表
      /
       / 
       By: LyShark.com
      BaseAddr:二级表基地址
      index2:第几个二级表
      *
       /
      VOID parse_table_2(ULONG64 BaseAddr, 
       INT 
       index2)
      {
          
       /
       / 
       遍历二级表(每个表项大小 
       8
       ),表大小 
       4k
       ,所以遍历 
       4096
       /
       8 
       = 
       512 
       次
          
       ULONG64 ul_baseAddr_1 
       = 
       0
       ;
          
       for 
       (
       INT 
       i 
       = 
       0
       ; i < 
       512
       ; i
       +
       +
       )
          
       {
              
       if 
       (!MmIsAddressValid((PVOID64)(BaseAddr 
       + 
       i 
       * 
       8
       )))
              
       {
                  
       DbgPrint(
       "非法二级表指针(1):%p \n"
       , BaseAddr 
       + 
       i 
       * 
       8
       );
                  
       continue
       ;
              
       }
              
       if 
       (!MmIsAddressValid((PVOID64)
       *
       (PULONG64)(BaseAddr 
       + 
       i 
       * 
       8
       )))
              
       {
                  
       DbgPrint(
       "非法二级表指针(2):%p \n"
       , BaseAddr 
       + 
       i 
       * 
       8
       );
                  
       continue
       ;
              
       }
              
       ul_baseAddr_1 
       = 
       *
       (PULONG64)(BaseAddr 
       + 
       i 
       * 
       8
       );
              
       parse_table_1(ul_baseAddr_1, i, index2);
          
       }
      }
      /
       * 
       解析三级表
      /
       / 
       By: LyShark.com
      BaseAddr:三级表基地址
      *
       /
      VOID parse_table_3(ULONG64 BaseAddr)
      {
          
       /
       / 
       遍历三级表(每个表项大小 
       8
       ),表大小 
       4k
       ,所以遍历 
       4096
       /
       8 
       = 
       512 
       次
          
       ULONG64 ul_baseAddr_2 
       = 
       0
       ;
          
       for 
       (
       INT 
       i 
       = 
       0
       ; i < 
       512
       ; i
       +
       +
       )
          
       {
              
       if 
       (!MmIsAddressValid((PVOID64)(BaseAddr 
       + 
       i 
       * 
       8
       )))
              
       {
                  
       continue
       ;
              
       }
              
       if 
       (!MmIsAddressValid((PVOID64)
       * 
       (PULONG64)(BaseAddr 
       + 
       i 
       * 
       8
       )))
              
       {
                  
       continue
       ;
              
       }
              
       ul_baseAddr_2 
       = 
       *
       (PULONG64)(BaseAddr 
       + 
       i 
       * 
       8
       );
              
       parse_table_2(ul_baseAddr_2, i);
          
       }
      }
      VOID UnDriver(PDRIVER_OBJECT driver)
      {
          
       DbgPrint((
       "Uninstall Driver Is OK \n"
       ));
      }
      NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
      {
          
       DbgPrint((
       "hello lyshark.com \n"
       ));
          
       ULONG64 tableAddr 
       = 
       0
       ;
          
       get_PspCidTable(&tableAddr);
          
       DbgPrint(
       "PspCidTable Address = %p \n"
       , tableAddr);
          
       /
       / 
       获取 _HANDLE_TABLE 的 TableCode
          
       ULONG64 ul_tableCode 
       = 
       *
       (PULONG64)(((ULONG64)
       *
       (PULONG64)tableAddr) 
       + 
       8
       );
          
       DbgPrint(
       "ul_tableCode = %p \n"
       , ul_tableCode);
          
       /
       / 
       取低 
       2
       位(二级制
       11 
       = 
       3
       )
          
       INT 
       i_low2 
       = 
       ul_tableCode & 
       3
       ;
          
       DbgPrint(
       "i_low2 = %X \n"
       , i_low2);
          
       /
       / 
       一级表
          
       if 
       (i_low2 
       =
       = 
       0
       )
          
       {
              
       /
       / 
       TableCode 低 
       2
       位抹零(二级制
       11 
       = 
       3
       )
              
       parse_table_1(ul_tableCode & (~
       3
       ), 
       0
       , 
       0
       );
          
       }
          
       /
       / 
       二级表
          
       else 
       if 
       (i_low2 
       =
       = 
       1
       )
          
       {
              
       /
       / 
       TableCode 低 
       2
       位抹零(二级制
       11 
       = 
       3
       )
              
       parse_table_2(ul_tableCode & (~
       3
       ), 
       0
       );
          
       }
          
       /
       / 
       三级表
          
       else 
       if 
       (i_low2 
       =
       = 
       2
       )
          
       {
              
       /
       / 
       TableCode 低 
       2
       位抹零(二级制
       11 
       = 
       3
       )
              
       parse_table_3(ul_tableCode & (~
       3
       ));
          
       }
          
       else
          
       {
              
       DbgPrint(
       "LyShark提示: 错误,非法! "
       );
              
       return 
       FALSE;
          
       }
          
       Driver
       -
       >DriverUnload 
       = 
       UnDriver;
          
       return 
       STATUS_SUCCESS;
      }
       | 
   
运行如上完整代码,我们可以在WinDBG中捕捉到枚举到的进程信息:
 
线程信息在进程信息的下面,枚举效果如下:
 
至此文章就结束了,这里多说一句,实际上ZwQuerySystemInformation枚举系统句柄时就是走的这条双链,枚举系统进程如果使用的是这个API函数,那么不出意外它也是在这些内核表中做的解析。
http://www.blogfshare.com/details-in-pspcidtbale.html
https://blog.csdn.net/whatday/article/details/17189093
https://www.cnblogs.com/kuangke/p/5761615.html
https://www.cnblogs.com/LyShark/p/16796158.html
更多【 驱动开发:内核枚举PspCidTable句柄表】相关视频教程:www.yxfzedu.com