句柄表

admin 2023年12月20日09:23:42评论32 views字数 9075阅读30分15秒阅读模式

什么是句柄?

句柄是一种内核对象,当一个进程创建或者打开一个内核对象时,就会获得一个句柄,通过这个句柄就可以访问内核对象。

而句柄并不是高2G内存,他是一个索引,通过这个所以我们可以在内核轻松找到对应的内核对象结构体的地址。

而且,这里需要注意,句柄是给3环用的,而不是给内核用的。

句柄表

上面介绍了什么是句柄,那么什么是句柄表呢?句柄表其实就是一个表结构,存储了每个句柄。

那么如何寻找呢?

在_EPROCESS的0xc4的位置,有一个_HANDLE_TABLE,而这个就是存放句柄表的。


kd> dt _EPROCESS
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
kd> dt _HANDLE_TABLE
ntdll!_HANDLE_TABLE
+0x000 TableCode : Uint4B
+0x004 QuotaProcess : Ptr32 _EPROCESS
+0x008 UniqueProcessId : Ptr32 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0x02c ExtraInfoPages : Int4B
+0x030 FirstFree : Uint4B
+0x034 LastFree : Uint4B
+0x038 NextHandleNeedingPool : Uint4B
+0x03c HandleCount : Int4B
+0x040 Flags : Uint4B
+0x040 StrictFIFO : Pos 0, 1 Bit

我们这里要介绍一下TableCode

TableCode总共8个字节:

63            ①            47

               ②           31

                ③          15

              ④               0

第一部分:共计两个字节(48-63位),低字节保留(一直都是0),高位字节是给SetHandleInformation这个函数用的,例如当执行如下语句:

SetHandleInformation(Handle,HANDLE_FLAG_PROTECT_FROM_CLOSE,HANDLE_FLAG_PROTECT_FROM_CLOSE);

那么高位字节就会被写入0x02,这是因为HANDLE_FLAG_PROTECT_FROM_CLOSE宏的值为0x00000002,取了其最低字节写入第一部分的高位字节中,因此第一部分最终的值就是0x0200;

第二部分:共计2个字节(32-47),表示访问掩码,是给OpenProcess函数使用的,其存储的值就是OpenProcess函数的第一个参数对应的值;

第三部分和第四部分:共计4字节(0-31),第0位表示调用者是否允许关闭该句柄默认值为1,第1位表示该句柄是否可继承(是否可以将句柄项拷贝到其他句柄表中),第2位表示 关闭该对象时是否产生一个审计事件默认值为0,第3位到第31位存放的是该内核对象在内核中的具体地址。

而我们的句柄都是占4字节。

句柄表

计算公式

因此,计算公式:地址+(句柄/4*8)

如何查找/定位

// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>

void Test()
{

DWORD PID;
HANDLE hPro = NULL;

HWND hWnd = FindWindow(NULL,"计算器");
GetWindowThreadProcessId(hWnd,&PID);
for (int i = 0;i<100;i++)
{
hPro = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, TRUE,PID);
printf("句柄:%x n",hPro);
}
//SetHandleInformation(hPro, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
}

int main(int argc, char* argv[])
{
Test();
printf("Hello World!n");
getchar();
return 0;
}


Failed to get VadRoot
PROCESS 85ccd020 SessionId: 0 Cid: 0898 Peb: 7ffdb000 ParentCid: 02d8
DirBase: 37db7000 ObjectTable: e214d2c8 HandleCount: 122.
Image: Test.exe

Failed to get VadRoot
PROCESS 85e91618 SessionId: 0 Cid: 08b0 Peb: 7ffdc000 ParentCid: 04a8
DirBase: 3b758000 ObjectTable: e1688c08 HandleCount: 179.
Image: wuauclt.exe

kd> dt _EPROCESS 85ccd020
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER 0x01da3285`956055ee
+0x078 ExitTime : _LARGE_INTEGER 0x0
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : 0x00000898 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x85e916a0 - 0x86097bb0 ]
+0x090 QuotaUsage : [3] 0x578
+0x09c QuotaPeak : [3] 0x578
+0x0a8 CommitCharge : 0x5b
+0x0ac PeakVirtualSize : 0xdbb000
+0x0b0 VirtualSize : 0xdbb000
+0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0x85e916cc - 0x86097bdc ]
+0x0bc DebugPort : 0x860b2780 Void
+0x0c0 ExceptionPort : 0xe1324030 Void
+0x0c4 ObjectTable : 0xe214d2c8 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF

句柄表

kd> dt _HANDLE_TABLE 0xe214d2c8
ntdll!_HANDLE_TABLE
+0x000 TableCode : 0xe10cc000
+0x004 QuotaProcess : 0x85ccd020 _EPROCESS
+0x008 UniqueProcessId : 0x00000898 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY [ 0xe1688c24 - 0xe227e2ac ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : (null)
+0x02c ExtraInfoPages : 0n0
+0x030 FirstFree : 0x63c
+0x034 LastFree : 0
+0x038 NextHandleNeedingPool : 0x800
+0x03c HandleCount : 0n122
+0x040 Flags : 0
+0x040 StrictFIFO : 0y0
kd> dq 0xe10cc000
ReadVirtual: e10cc000 not properly sign extended
e10cc000 fffffffe`00000000 00000000`00000000
e10cc010 00000004`00000000 00000008`00000000
e10cc020 0000000c`00000000 00000010`00000000
e10cc030 00000014`00000000 00000018`00000000
e10cc040 0000001c`00000000 00000020`00000000
e10cc050 00000024`00000000 00000028`00000000
e10cc060 0000002c`00000000 00000030`00000000
e10cc070 00000034`00000000 00000038`00000000
kd> dq 0xe10ccd28
ReadVirtual: e10ccd28 not properly sign extended
e10ccd28 0000003a`86097b13 0000003a`86097b13
e10ccd38 0000003a`86097b13 0000003a`86097b13
e10ccd48 0000003a`86097b13 0000003a`86097b13
e10ccd58 0000003a`86097b13 0000003a`86097b13
e10ccd68 0000003a`86097b13 0000003a`86097b13
e10ccd78 0000003a`86097b13 0000003a`86097b13
e10ccd88 0000003a`86097b13 0000003a`86097b13
e10ccd98 0000003a`86097b13 0000003a`86097b13

句柄表

通过公式计算得出:0xD28

句柄表

找到这个句柄了。

使用SetHandleInformation

// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>

void Test()
{

DWORD PID;
HANDLE hPro = NULL;

HWND hWnd = FindWindow(NULL,"计算器");
GetWindowThreadProcessId(hWnd,&PID);
for (int i = 0;i<100;i++)
{
hPro = OpenProcess(PROCESS_CREATE_THREAD, TRUE,PID);
printf("句柄:%x n",hPro);
}
SetHandleInformation(hPro, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
}

int main(int argc, char* argv[])
{
Test();
printf("Hello World!n");
getchar();
return 0;
}


Failed to get VadRoot
PROCESS 85d1e748 SessionId: 0 Cid: 0b24 Peb: 7ffd8000 ParentCid: 02d8
DirBase: 3b385000 ObjectTable: e23b72c8 HandleCount: 122.
Image: Test.exe

kd> ! _EPROCESS 85d1e748
No export _EPROCESS found
kd> dt _EPROCESS 85d1e748
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER 0x01da3286`8008345e
+0x078 ExitTime : _LARGE_INTEGER 0x0
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : 0x00000b24 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x8056a658 - 0x85d1d0a8 ]
+0x090 QuotaUsage : [3] 0x578
+0x09c QuotaPeak : [3] 0x578
+0x0a8 CommitCharge : 0x5b
+0x0ac PeakVirtualSize : 0xdbb000
+0x0b0 VirtualSize : 0xdbb000
+0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0xf7d60014 - 0x85d1d0d4 ]
+0x0bc DebugPort : 0x860edfc0 Void
+0x0c0 ExceptionPort : 0xe1324030 Void
+0x0c4 ObjectTable : 0xe23b72c8 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF

句柄表

kd> dt _HANDLE_TABLE 0xe23b72c8
ntdll!_HANDLE_TABLE
+0x000 TableCode : 0xe10a5000
+0x004 QuotaProcess : 0x85d1e748 _EPROCESS
+0x008 UniqueProcessId : 0x00000b24 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY [ 0x8056b948 - 0xe21482b4 ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : (null)
+0x02c ExtraInfoPages : 0n0
+0x030 FirstFree : 0x63c
+0x034 LastFree : 0
+0x038 NextHandleNeedingPool : 0x800
+0x03c HandleCount : 0n122
+0x040 Flags : 0
+0x040 StrictFIFO : 0y0
kd> dq 0xe10a5000
ReadVirtual: e10a5000 not properly sign extended
e10a5000 fffffffe`00000000 00000000`00000000
e10a5010 00000004`00000000 00000008`00000000
e10a5020 0000000c`00000000 00000010`00000000
e10a5030 00000014`00000000 00000018`00000000
e10a5040 0000001c`00000000 00000020`00000000
e10a5050 00000024`00000000 00000028`00000000
e10a5060 0000002c`00000000 00000030`00000000
e10a5070 00000034`00000000 00000038`00000000
kd> dq 0xe10a5c80
ReadVirtual: e10a5c80 not properly sign extended
e10a5c80 02000002`86097b13 00000002`86097b13
e10a5c90 00000002`86097b13 00000002`86097b13
e10a5ca0 00000002`86097b13 00000002`86097b13
e10a5cb0 00000002`86097b13 00000002`86097b13
e10a5cc0 00000002`86097b13 00000002`86097b13
e10a5cd0 00000002`86097b13 00000002`86097b13
e10a5ce0 00000002`86097b13 00000002`86097b13
e10a5cf0 00000002`86097b13 00000002`86097b13

0x640/4*8

句柄表


全局句柄表PsdCidTable

在进程中可以创建、打开很多内核对象,这些内核对象的地址都存储在当前进程的句柄表中。我们在应用层得到的句柄实际上就是句柄表的索引。

进程的句柄表是私有的,每个进程都有一个自己的句柄表。除此之外,系统还有一个全局句柄表:PsdCidTable


  1. 所有的进程和线程无论无论是否打开,都在这个表中。

  2. 每个进程和线程都有一个唯一的编号:PID和CID    这两个值其实就是全局句柄表中的索引。

进程和线程的查询,主要是以下三个函数,按照给定的PID或CID从PspCidTable从查找相应的进线程对象:

PsLookupProcessThreadByCid()  

PsLookupProcessByProcessId()  

PsLookupThreadByThreadId()      

全局句柄表结构

句柄表

查找

  1. 现获得记事本的PID:

句柄表

  1. 计算:580/4=145 = 0x91 在第一张表中。

  2. 获得全局句柄表:

kd> dd PspCidTable
8056a760 e1002c98 00000002 00000000 00000000
8056a770 00000000 00000000 00000000 00000000
8056a780 00000000 00000000 00000000 00000000
8056a790 00000000 00000000 00000000 00000000
8056a7a0 00000000 00000000 00000000 00000000
8056a7b0 00000000 00000000 00000000 00000000
8056a7c0 00000000 00000000 00000000 00000000
8056a7d0 00000000 00000000 00000000 00000000
kd> dt _HANDLE_TABLE 0xe1002c98
ntdll!_HANDLE_TABLE
+0x000 TableCode : 0xe10bd001
+0x004 QuotaProcess : (null)
+0x008 UniqueProcessId : (null)
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY [ 0xe1002cb4 - 0xe1002cb4 ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : (null)
+0x02c ExtraInfoPages : 0n0
+0x030 FirstFree : 0xb78
+0x034 LastFree : 0xb74
+0x038 NextHandleNeedingPool : 0x1000
+0x03c HandleCount : 0n388
+0x040 Flags : 1
+0x040 StrictFIFO : 0y1
  1. 查看_EPROCESS结构体

kd> dd 0xe10bd000
ReadVirtual: e10bd000 not properly sign extended
e10bd000 e1005000 e10c3000 00000000 00000000
e10bd010 00000000 00000000 00000000 00000000
e10bd020 00000000 00000000 00000000 00000000
e10bd030 00000000 00000000 00000000 00000000
e10bd040 00000000 00000000 00000000 00000000
e10bd050 00000000 00000000 00000000 00000000
e10bd060 00000000 00000000 00000000 00000000
e10bd070 00000000 00000000 00000000 00000000
kd> dq e1005000+0x91*8
ReadVirtual: e1005488 not properly sign extended
e1005488 00000000`85ea4021 00000aec`00000000
e1005498 00000000`860b6431 00000274`00000000
e10054a8 000000d0`00000000 00000164`00000000
e10054b8 000001ac`00000000 0000027c`00000000
e10054c8 00000260`00000000 0000040c`00000000
e10054d8 00000fd0`00000000 00000f1c`00000000
e10054e8 00000238`00000000 00000000`85d418c1
e10054f8 00000270`00000000 00000000`85e91621
kd> dt _EPROCESS 85ea4020

句柄表


原文始发于微信公众号(loochSec):句柄表

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月20日09:23:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   句柄表http://cn-sec.com/archives/2318623.html

发表评论

匿名网友 填写信息