个人理解,记录一下,如有错误请轻喷。。。。
PspCidTable存放着一个结构为_HANDLE_TABLE的指针,_HANDLE_TABLE结构记录句柄表的相关信息,句柄表存放着所有进程和线程的对象,其索引就是PID和TID,在WinDbg看一下相关的结构。
我们遍历进程对象需要关注两个成员,第一个是TableCode,第二个是NextHandleNeedingPool。
TableCode:该成员记录表级和表地址,低2位记录着表的级数,掩掉低2位后为表地址,表级为0时为一级表,表地址直接指向_HANDLE_TABLE_ENTRY数组,表级为1时为二级表,表地址指向一级表数组,表级为2时为三级表,表地址指向二级表数组。
引用一位博主的图片https://blog.csdn.net/whatday/article/details/17189093
每个表的大小为1页=4K,二级表和三级表储存指针,所以分别可以储存4K/8=512个表,一级表储存_HANDLE_TABLE_ENTRY结构,在x64中该结构大小为16,所以一级表可以储存4K/16=256个表,计算PID的方式为:(三级表索引*二级表最大表数(512)*一级表最大表数(256)+二级表索引*一级表最大表数(256)+一级表索引)*4
NextHandleNeedingPool:该成员记录下一次句柄扩展时的起始值。
下面通过WinDbg来获取进程的对象,
首先访问PspCidTable获取指针地址,
通过该指针地址获取_HANDLE_TABLE相关信息,
根据TableCode低两位为0,说明是一个二级表,我们通过TableCode&(~3)得到二级表指针,
然后访问第一个一级表指针,
通过结构_HANDLE_TABLE_ENTRY访问第一项为,
由于是二级表,我们通过(二级表索引*一级表最大表数(256)+一级表索引)*