0%

2015-12-18-内核对象结构简介

    内核对象包括多种进程对象、文件对象等等,应用层每次创建或打开进程、文件都会对相应的内核对象创建一个句柄(进程的pid值其实就是该进程内核对象的句柄),这个句柄其实就是一个索引值,在通过句柄操作内核对象时,由内核根据该句柄值查找句柄表,定位内核对象的位置,最终完成相应操作。

    系统所有有名的内核对象按散列表的方式保存在ObpRootDirectoryObject指针指向的对象目录表中:

    其中HashBuckets数组每个元素都指向一个_OBJECT_DIRECTORY_ENTRY结构:

    ChainLink指向下一个_OBJECT_DIRECTORY_ENTRY结构,Object表示所存放的内核对象,HashValue则是其散列值。因为对象目录本身也是一种内核对象,在Windbg中可以直接查看该对象详细信息,下图中可以看出!object可以列出对象目录信息及Hash表中不为空的表项。在编程实现遍历对象目录时需要注意递归调用遍历函数,避免遗漏,其实编程遍历对象目录的结果和WinObj查看的结果印象里是一样的。

    下面以进程对象为例介绍内核对象结构,进程的内核对象地址指的就是进程的_EPROCESS结构(文件内核对象指的是_FILE_OBJECT结构,其它对象都有相应的结构),下面先来看看explorer进程的_EPROCESS结构:

    部分结构:

    因为不同内核对象类型所对应的结构都不一样,为了方便识别内核对象类型,所有内核对象头部前0x18字节存放内核对象头信息:

    注意偏移0xC偏移处的TypeIndex成员,代表内核对象类型所在类型表中的偏移,在vista以前的系统上,_OBJECT_HEADER中是没有该成员的,而是直接存放一个_OBJECT_TYPE结构表示对象类型。所以在Win7及以上系统就需要根据索引值在全局符号变量ObTypeIndexTable中定位对象所指示的类型,可以看到_OBJECT_TYPE中Name字符串表示是进程对象:

    这和直接查看进程对象类型指针得到的地址也是一样的:

    在处理其他内核对象时也可以根据这种方式判断出所要处理的对象类型是什么,不过在编写相关程序时需要注意要根据特征搜索出ObTypeIndexTable地址,如果是调试时可以直接在Windbg中直接根据_EPROCESS结构直接查看对象类型:

    其中HandleCount和PointerCount分别表示句柄和内核对象的引用计数。

    最后需要注意下_OBJECT_TYPE类型的TypeInfo结构的其他成员:

    其中OpenProcedure等相关结构可以指定打开进程也就是OpenProcess时调用的回调函数,替换之后也可以做到很多事情,比如监控进程创建等。