ObReferenceObjectByHandle() 函数简略分析

原文链接

1. 逆向出来的 ObReferenceObjectByHandle() 函数实现

这个函数的实现请参考这个文章:ObReferenceObjectByHandle() 函数,这里不再重复贴出。 这个函数的原型是:

NTSTATUS
ObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation
);

这个函数的目的是:根据提供的 Handle 值得到 Object!

2. Handle 属于 kernel Handle 时

ObReferenceObjectByHandle() 会先判断 Handle 是否属于 kernel 级别的 Handle 值:

if ((LONG)Handle < 0)
{
// 属于 Kernel Handle
}
else
{
// 非 Kernel Handle

当 Handle < 0 时(即:bit 31 为 1),是表明属于 kernel 的 Handle 值,ObReferenceObjectByHandle() 会进一步判断:

  • Handle == -1(0xFFFFFFFF)时,属于当前 process Handle
  • Handle == -2(0xFFFFFFFE)时,属于当前 thread Handle

-1 与 -2 是两个伪 Handle 值,分别代表当前 KPROCESS 和 KTHREAD 结构的 Handle 值(注意:与 EPROCESS 及 ETHREAD 的区别)

2.1 Handle 属于当前 process Handle 值时

当 Handle == -1 时,它属于 process Handle。需要从 KPROCESS 结构(由 Thread->ApcState.Process 得到)查找到相关联的 EPROCESS 结构,从而得到相关信息。 如下图所示:

这里的处理逻辑是:

  • 得到 KPROCESS 指针: Process = Thread->ApcState.Process; 这个 Process 指向 EPROCESS 结构的 Pcb 域。
  • 得到 EPROCESS 结构地址:EProcess = CONTAINING_RECORD(Process, EPROCESS, Pcb); 根据这个 Pcb 来得到 EPROCESS 结构地址
  • 所需的权限:GrantedAccess = EProcess->GrantedAccess;
2.2 Handle 属于当前 thread Handle 值时

当 Handle == -2 时,它属于 thread Handle。直接从 Thread (由 fs:[124h] 得到)指针求得 ETHREAD 结构。Thread 指向 ETHREAD 结构的 Tcb 域。 如下图所示:

这里的处理逻辑是:

  • 得到 ETHREAD 结构地址:EThread = CONTAINING_RECORD(Thread, ETHREAD, Tcb); 根据 Tcb 来得到 ETHREAD 结构地址
  • 所需权限:GrantedAccess = EThread->GrantedAccess
2.3 能访问的权限

在上面两个图中的 ETHREAD 结构或 EPROCESS 结构得到的 GrantedAccess 值决定了允许访问的权限。从 ObReferenceObjectByHandle() 函数 的实现上看。

下面的情形是失败的:

if (((~GrantedAccess & DesiredAccess) != 0) && (AccessMode != KernelMode))
{
return STATUS_ACCESS_DENIED; // 权限不足
}

换个角度来说,也就是当:

if (((~GrantedAccess & DesiredAccess) == 0) || (AccessMode == KernelMode))
{
// 允许访问
}

上面的检查中是通过的!当访问模式为 KernelMode 或者权限符合时就允许访问。

那么:GrantedAccess 值设置了允许访问的权限位,通过权限位和访问者提供的权限比较是否符号。

2.4 返回 Object 值与 HandleInformation 信息

假如传递的参数 HandleInformation 不为 NULL 时,需要返回相关的 OBJECT_HANDLE_INFORMATION 结构信息。

if (HandleInformation != NULL)
{
HandleInformation->GrantedAccess = GrantedAccess;
HandleInformation->HandleAttributes = 0;
}

返回的 Object 值为 Thread(从 fs:[124h] 里得到的 KTHREAD 结构)。

3. Handle 是非 kernel Handle 时

当属于非 kernel Handle 时,先得到 HANDLE_TABLE 结构地址:

这个 EPROCESS 结构 Object 的获得方法是与 Kernel Handle 下当 Handle 属于 process Handle 时是一样的。

//
// 当前 handle >= 0 时:得到当前 EPROCESS 结构地址和 HANDLE_TABLE 结构
//
Process = Thread->>ApcState.Process;
EProcess = CONTAINING_RECORD(Process, EPROCESS, Pcb);
HandleTable = &EProcess->ObjectTable;

从 EPROCESS 结构的 ObjectTable 域来获得 HANLDE_TABLE 结构的地址值。

TableEntry = ExMapHandleToPointerEx(HandleTable, Handle, AccessMode);

在后续的代码里将调用 ExMapHandleToPointerEx() 函数来得到 TableEntry 值。

而 ExMapHandleToPointerEx() 函数内部最终将调用 ExpLookupHandleTableEntry() 函数,在 HandleTable 里根据 Handle 值来找到 TableEntry(HANDLE_TABLE_ENTRY 结构)值。

关于 ExpLookupHandleTableEntry() 函数如何工作,请参考另一篇文章:ExpLookupHandleTableEntry() 函数分析

3.1 HANDLE_TABLE_ENTRY 结构

在得到的 TableEntry 指针找到 HANDLE_TABLE_ENTRY 结构,如下图所示:

HANDLE_TABLE_ENTRY 结构实际上只有两个域 8 个 bytes,其中 Object 值经过计算得到指向 OBJECT_HEADER 结构的指针 ObjectHeader。

如下面代码所示:

ObjectHeader = (POBJECT_HEADER )((ULONG)TableEntry->Object & 0xFFFFFFF8);

后续代码将对 OBJECT_HEADER 结构的两个重要成员进行处理:

  • 增加 Object 的引用计数,如下面代码所示:

    InterlockedIncrement(ObjectHeader->PointerCount); // 增加 object 计数

  • 最终会返回 Body 地址作为 Object 指针值,如下面代码所示:

    *Object = &ObjectHeader->Body; // ObjectHeadler 的 Body 域作为 Object 参数值返回

HANDLE_TABLE_ENTRY 结构的 GrantedAccess 域,是允许访问的权限(见前面所述)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值