句柄表
当一个进程创建或者打开一个内核对象时,将获得一个句柄,通过这个句柄可以访问内核对象
- 句柄存在的目的是为了避免在应用层直接修改内核对象
- 只有进程才有句柄表,句柄表保存了进程中打开或创建的内核对象
- 关闭句柄后,会在句柄表中删除对应的项值,并将内核对象引用计数+1
- 进程关闭后,会清空句柄表,将内核对象引用计数-1
- 句柄的值都是4的整数倍,所以将句柄的值/4得到索引,再在句柄表中找对应值得到实际内核对象地址
- 因句柄表值是8字节,一个页4KB,句柄在512个以内是在一个页上,如果超过512个,句柄标会更改结构,第一级的4kb页会保存指向句柄表的地址,可以保存1024个,第二级才是真正的句柄表,值512个,共能保存1024*512个
进程中EPROCESS 0x0f4 ObjectTable _HANDLE_TABLE句柄表
nt!_HANDLE_TABLE
+0x000 TableCode 句柄表地址 句柄表中的值是8字节
+0x004 QuotaProcess
+0x008 UniqueProcessId
句柄
- 句柄表后3位是属性位,查看地址时需要清零
- 查看进程结构时因每个内核对象都有一个OBJECT_HEADER,查看内核对象结构是从0x18开始,所以需要将地址最后一个数拆分后将后3位清零再加上0x18,查看对应对象结构
全局句柄表
- windbg指令dd PsdCidTable查看全局句柄表地址,也是_HANDLE_TABLE结构体
- 只存储进程与线程
- 可以遍历全局句柄表找到进程句柄,在查看进程句柄表有没有我们的子程序,如果有可能是调试器
- 全局句柄表的值不需要加0x18,自动过滤了OBJECT_HEADER,不过也是要把最后3位属性位清零
MmGetSystemRoutineAddress()函数
- MmGetSystemRoutineAddress(“函数名”) 参数是Unicode的函数名
- 查看导出函数的地址
- 不会被IAT HOOK影响,从内核模块导出表直接找函数地址
- 函数虽然导出了,但是无法直接使用