PspCidTable 完全解读 by sysdog 2009.5.1 Whu

-------------------------------------------------------------------------------

一、句柄

句柄:HADNLE 在winnt.h 定义如下:

typedef void *HANDLE;

是一个 32 位无类型指针,充当内核对象在内核的索引.

句柄本质—内核对象(object)的索引

每个进程都有自己的进程句柄表,当操作进程对象时,会把对象指针放在自己的句柄表中,

返回一个句柄,通过句柄来索引对象指针,然后操作对象。

进程句柄表是根据 HANDLE 索引对象指针的,而pspcidtable(未导出,需要自己定位地址)

是根据 CID 索引对象指针的.

EPROCESS 和 ETHREAD 分别是进程对象和线程对象

NT 执行体处理进程线程对象,进程和线程描述表可由 EPROCESS 结构来访问,NT 内核处理进

程和线程描述表

二、句柄表

XP 下句柄表是动态分配的,是个三层表,1 级表(称为基本表)存放系统底层的。

句柄表大小为 1页即 4K,而每个表项是一个HANDLE_TABLE_ENTRY占8个字节,所以

每个表最多只能放 512个表项,又因为表项索引是以 4递增的,因此一个最终表能承受的最

大索引值也是 2048即 0x800,两个表最大为 0x1000,三个表就是 0x1800。

句柄表的格式如下:

句柄表就是 HANDLE_TABLE 结构,如下:

里面没有指针结构啊,那么句柄表到底存储在那里?

实际是保存在 TableCode 里面,但是 TableCode 并不是地址,它比地址所担任的责任多一

点:标明这个指针指向的是哪一级别的句柄,在 x86 上面Windows 总是分配内存使其沿四个

字节对齐,所以实际的句柄表地址的低两位一定是 0? 。XP 就用这两位来标示这个表是哪个

级别,00 表示 1 级表,01 表示 2 级表,02 表示 3 级表。2 级表存放的是 1 级表的指针,3 级

表存放的是 2 级表的指针。

TableCode转变一下就是HANDLE_TABLE_ENTRY了,转变也很简单,就是低两位清零,

因为底两位代表当前句柄表的级数,HANDLE_TABLE里面存放的是一些信息,

HANDLE_TABLE_ENTRY才是真正的句柄表。

HANDLE_TABLE_ENTRY结构如下:

如果是一级表 HANDLE_TABLE_ENTRY=TableCode

如果是二级表 HANDLE_TABLE_ENTRY需要根据 2级表中的指针来找 1级表的基址,然后

再根据 1级表中的偏移找到进程对象…..三级表类推

三、内核对象

作为一个 Wi n d o w s软件开发人员,经常需要创建、打开和操作各种内核对象。系统要创

建和操作若干类型的内核对象,比如存取符号对象、事件对象、文件对象、文件映射对象、

I / O完成端口对象、作业对象、信箱对象、互斥对象、管道对象、进程对象、信标对象、线

程对象和等待计时器对象等。这些对象都是通过调用函数来创建的。例如, C r e a t e F i l e M

a p p i n g函数可使系统能够创建一个文件映射对象。每个内核对象只是内核分配的一个内存

块,并且只能由该内核访问。该内存块是一种数据结构,它的成员负责维护该对象的各种信

息。有些数据成员(如安全性描述符、使用计数等)在所有对象类型中是相同的,但大多数

数据成员属于定的对象类型。例如,进程对象有一个进程 I D、一个基本优先级和一个退出

代码,而文件对象则拥有一个字节位移、一个共享模式和一个打开模式。由于内核对象的数

据结构只能被内核访问,因此应用程序无法在内存中找到这些数据结构并直接改变它们的内

容。M i c r o s o f t规定了这个限制条件,目的是为了确保内核对象结构保持状态的一致。这

个限制也使 M i c r o s o f t能够在不破坏任何应用程序的情况下在这些结构中添加、删除和修

改数据成员。如果我们不能直接改变这些数据结构,那么我们的应用程序如何才能操作这些

内核对象呢?解决办法是,Wi n d o w s提供了一组函数,以便用定义得很好的方法来对这些

结构进行操作。这些内核对象始终都可以通过这些函数进行访问。当调用一个用于创建内核

对象的函数时,该函数就返回一个用于标识该对象的句柄。该句柄可以被视为一个不透明值,

你的进程中的任何线程都可以使用这个值。将这个句柄传递给 Wi n d o w s的各个函数,这

样,系统就能知道你想操作哪个内核对象。

四、PspCidTable

对象指针:从其线形地址来看,它将常驻内存的结构体划分为两部分:一个对象头和一个对

象体。对象指针并没有指向对象自身的基地址,而是指向了对象体,由于紧接着对象头的就

是对象体,所以可以给对象指针加上一个负的偏移量来访问对象头。

PspCidTable:指向 HANDLE_TABLE的指针,未导出结构,存放所有进程及线程对象指针。

PspCidTable 是一个句柄表,其格式与普通的句柄表是完全一样的.但它与每个进程私有的句

柄表有以下不同:

1.PspCidTable中存放的对象是系统中所有的进线程对象指针,其索引就是 PID 和 CID

2.PspCidTable中存放是对象体(指向 EPROCESS 和 ETHREAD),而每个进程私有的句柄表则存放

的是对象头(OBJECT_HEADER)

3.PspCidTable是一个独立的句柄表,而每个进程私有的句柄表以一个双链连接起来

PspCidTable 在XP 下是个三层表,动态分配的

PspCidTable 是内核未导出的 HANDLE_TABLE 结构,它保存着所有进程及线程对象指针.只要

可以遍历这个表就可以遍历所有进程,包括隐藏进程(hook ZWQuerySystemInformation),

抹除 PspCidTable 除外,下面根据 KD 查看此表:

图一

通过 PspCidTable 遍历进程就是为了获取进程对象指针。PspCidTable 是根据 PID 或者 CID

索引的,所以就依据进程 CID 获取进程对象指针。

五、演示说明

1.根据 HANDLE 索引object 指针

注意红色部分。ObjectTable: e7313480指向HANDLE_TABLE 结构

TableCode: 0xe5018000最低两位为 00 表示 0 级表。于是查找句柄为 0x14 的对象指针

有(因为索引时按 4 递增的,一个HANDLE_TABLE_ENTRYA 占 8 个字节)

Ptr=HANDLE_TABLE_ENTRY+HANDLE*8/4=HANDLE_TABLE_ENTRY+HANDLE*2

看到 e1c050b9 就是 0x14 对应的 object Header,这里需要转换一下(低三位清零再加上 Object

Header 大小,因为 object header 是 8 个字节对齐,低三位做标志位)

Object=objectHeader&0xfffffff8+sizeof(Object Header)

e1c050b9 &0xfffffff8 + 0x18=e1c050d0-

跟上面的一模一样。

2.根据 CID 索引(PspCidTable句柄表)对象指针

首先是查找 pspcidtable 句柄表的地址:

然后观察 HANDLE_TABLE结构:

TableCode=e3a39001

第二位为 01表示有 2层表。

NextHandleNeedingPool: 0x1000,该字段说明了当 PID或CID达到多少以上时,需要再建

立一个新表(最终表)。我们的系统里现在已经有两个最终表了。最终表大小为 1页即 4K,

而每个表项是一个 HANDLE_TABLE_ENTRY占 8个字节,所以每个表最多只能放512个表

项,又因为表项是用 PID或者 TID来索引的,而索引是以 4递增的,因此一个最终表能承受

的最大 ID也是 2048即 0x800,两个表最大为 0x1000,以此类推…..

TableCode=e3a39001可知道:有 2个基本表

一级表中放的是基本表的指针

0级表的 HANDLE_TABLE_ENTRY= e1005000

计算公式:

PHANDLE_TABLE_ENTRY=HANDLE_TABLE_ENTRY+CID*sizeof(HANDLE_TABLE_ENTRY)/PID_INC

PHANDLE_TABLE_ENTRY =HANDLE_TABLE_ENTRY+CID*2

对 CID=0x16C<0x800

下面对这个进行验证。

由于 CID<0x800说明在 0级表中

PHANDLE_TABLE_ENTRY =e1005000+16c*2=e10052d8

得到 EPROCESS的地址为0x88cb7021&(~3)= 0x88cb7020

验证正确。

对于 CID=0x984>0x800

CID>800说明在 1级表中

PHANDLE_TABLE_ENTRY = e3a39000+984*2(e3a3a000+184*2)

得到 EPROCESS的地址为0x88cc78b1&(~3)= 0x88cc78b0,验证正确。

六、基于 PspCidTable 的进程检测及隐藏技术分析

1.基于 HOOK 的检测技术:遍历PspCidTable 所有进程对象指针

由于 PspCidTable 是未导出结构,需要自己定位

【一】PspCidTble 的定位

1.PsLookupProcessByProcessId(PsLookupThreadByThreadId或者PsLookupProcessThreadByCid)

函数中搜索

特征串(0x35ff 和 0x8e)定位 PspCidTalbe

CODE:

2.利用 KDDEBUGGER_DATA(32/64)结构得到 pspCidTable

KdEnableDebugger->KdInitSystem->KdDebuggerDataBlock->KDDEBUGGER_DATA32->PspCi

dTable

3. 利用 KPCR 中取,KRCR 地址

ffdff000处是一个叫做 KPCR的结构,PCR即 Processor Control Region,处理器控制域。这

是一个很有用的结构。系统本身就大量使用。0xffdff000是 KPCR这个结构变量的地址

那么+0x34就是KdVersionBlock成员变量在该结构中的偏移

但是在 0xffdff034指向的地方对应有个结构_DBGKD_GET_VERSION64

可惜的是这个结构只有 0x28字节大小但是....嘿嘿这个结构后面藏着 N多超级重要的内核

变量。我们的 pspcidtable这个变量其实就在这个结构起始位置的 0x80字节偏移处~

【二】进程对象的遍历

1.利用未导出的ExEnumHandleTable函数

2.直接自己获取PHANDLE_TABLE_ENTRY等,然后 PsLookupProcessByProcessId

3.自己写实现遍历(完成)

PspCidTable 完全解读相关推荐

  1. Python Re 模块超全解读!详细

    内行必看!Python Re 模块超全解读! 2019.08.08 18:59:45字数 953阅读 121 re模块下的函数 compile(pattern):创建模式对象 > import ...

  2. Bert系列(二)——源码解读之模型主体

    本篇文章主要是解读模型主体代码modeling.py.在阅读这篇文章之前希望读者们对bert的相关理论有一定的了解,尤其是transformer的结构原理,网上的资料很多,本文内容对原理部分就不做过多 ...

  3. Bert系列(三)——源码解读之Pre-train

    https://www.jianshu.com/p/22e462f01d8c pre-train是迁移学习的基础,虽然Google已经发布了各种预训练好的模型,而且因为资源消耗巨大,自己再预训练也不现 ...

  4. NLP突破性成果 BERT 模型详细解读 bert参数微调

    https://zhuanlan.zhihu.com/p/46997268 NLP突破性成果 BERT 模型详细解读 章鱼小丸子 不懂算法的产品经理不是好的程序员 ​关注她 82 人赞了该文章 Goo ...

  5. 解读模拟摇杆原理及实验

    解读模拟摇杆原理及实验 Interpreting Analog Sticks 当游戏支持控制器时,玩家可能会一直使用模拟摇杆.在整个体验过程中,钉住输入处理可能会对质量产生重大影响.让来看一些核心概念 ...

  6. 自监督学习(Self-Supervised Learning)多篇论文解读(下)

    自监督学习(Self-Supervised Learning)多篇论文解读(下) 之前的研究思路主要是设计各种各样的pretext任务,比如patch相对位置预测.旋转预测.灰度图片上色.视频帧排序等 ...

  7. 自监督学习(Self-Supervised Learning)多篇论文解读(上)

    自监督学习(Self-Supervised Learning)多篇论文解读(上) 前言 Supervised deep learning由于需要大量标注信息,同时之前大量的研究已经解决了许多问题.所以 ...

  8. 可视化反投射:坍塌尺寸的概率恢复:ICCV9论文解读

    可视化反投射:坍塌尺寸的概率恢复:ICCV9论文解读 Visual Deprojection: Probabilistic Recovery of Collapsed Dimensions 论文链接: ...

  9. 从单一图像中提取文档图像:ICCV2019论文解读

    从单一图像中提取文档图像:ICCV2019论文解读 DewarpNet: Single-Image Document Unwarping With Stacked 3D and 2D Regressi ...

最新文章

  1. templateclass T函数模板
  2. [转载] HTTP 之 IOS一谈
  3. Stanford概率图模型: 第一讲 有向图-贝叶斯网络
  4. 【最短路】【SPFA】单源最短路径 (luogu 3371)
  5. 小学计算机学情分析报告,小学信息技术_重点文字图说话教学设计学情分析教材分析课后反思...
  6. html中左侧播放器插件,简洁实用的html5音乐播放器插件
  7. Android 查看每个应用的最大可用内存
  8. QT5 QSqlQuery的SELECT INSERT UPDATE DELETE命令用法
  9. 靠谱测试人员需具备宏观把控能力
  10. 在Activiti中如何使用自定义的组织架构
  11. Java自定义数组排序
  12. 通俗易懂的Matlab线性规划求解详解
  13. Towards End-to-End Prosody Transfer for Expressive Speech Synthesis with Tacotron
  14. 什么是独立主机?独立主机的优势有些?
  15. among us私服搭建
  16. qt android刘海屏状态栏,安卓手机刘海屏算抄袭苹果iPhone X吗?真相了
  17. 项目管理工具DHTMLX Gantt灯箱元素配置教程:配置灯箱元素
  18. Scala学习小计 - 什么是模式匹配(pattern-matchin)?
  19. NHibernate Mapping Attribute实现复合主键映射
  20. 使用hexo+github免费搭建个人博客网站超详细教程

热门文章

  1. zoj4110 Strings in the Pocket(manacher)
  2. WPF 4 Ribbon 开发 之 应用程序菜单(Application Menu)
  3. 2017-2018-2 20179209《网络攻防》第六周作业
  4. Software Engineering | Factory method pattern
  5. 关于matlab中的梯度使用
  6. c++ 隐式类型转换
  7. AgileEAS.NET平台开发指南-实现插件
  8. Exchange Server 2000/2003 中设定超过2G的邮箱图解
  9. 数据库-ADONET-使用强类型DataSet
  10. 使用EHPC实现“完美并行”的高效批处理方案