(转)WINDOWS内核对象

WINDOWS内核对象

原文地址:http://blog.csdn.net/misterliwei/article/details/976988  支持原创

一.前言

Windows中有很多像进程对象、线程对象、文件对象等等这样的对象,我们称之为Windows内核对象。内核对象是系统地址空间中的一个内存块,由系统创建并维护。内核对象为内核所拥有,而不为进程所拥有,所以不同进程可以访问同一个内核对象。

二.内核对象结构

每个对象都有对象头和对象体组成。所有类型的对象头结构都是相同的,而结构体部分却各不相同的。下面是内核对象的结构图:

内核对象结构图

图中灰色部分是可能出现的。每个对象中是否存在这些部分主要由OBJECT_HEADER结构中的相关标志来指定。上面的5个结构的格式是固定的;而OBJECT结构体部分却是各个对象各不同的。需要注意的是:指向对象的指针POBJECT是指向对象体部分,而不是指向对象头的。所以,若需要访问OBJECT_HEADER,需要将POBJCECT减去0x18而获得。

下面是OBJECT_HEADER的结构


typedef struct _OBJECT_HEADER { DWORD PointerCount; // 指针引用的数目 DWORD HandleCount; // 打开句柄的数目 POBJECT_TYPE ObjectType;  //指向类型对象的指针 BYTE NameOffset; //对象名的偏移 BYTE HandleDBOffset; // HANDLE DB的偏移 BYTE QuotaChargesOffset; //QUOTA CHARGES的偏移 BYTE ObjectFlags; // 对象标志 union { // 对象标志中OB_FLAG_CREATE_INFO ? ObjectCreateInfo : QuotaBlock PQUOTA_BLOCK QuotaBlock; POBJECT_CREATE_INFO ObjectCreateInfo; }; PSECURITY_DESCRIPTOR SecurityDescriptor; }OBJECT_HEADER, *POBJECT_HEADER;

三.目录对象

WINDOWS中有20几类无数的内核对象,它们都独立地存在于系统地址空间中。系统利用目录对象将所有的这些对象组织起来。目录对象是一个有37个数组元素组成的哈希(HASH)树。数据结构如下:


Typedef struct _OBJECT_DIRECTORY_ENTY

{

Struct _OBJECT_DIRECTORY_ENTRY *NextEntry;

POBJECT Object

}OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY,**PPOBJECT_DIRECTORY_ENTRY;

Typedef struct _OBJECT_DIRECTORY

{

POBJECT_DIRECTORY_ENTRY HashTable[37];

POBJECT_DIRECTORY_ENTRY CurrentEntry;

BOOLEAN CurrentEntryValid;

BYTE  Reserved1;

WORD Reserved2;

DWORD Reserved3;

}OBJECT_DIRECTORY, *POBJECT_DIRECTORY;

系统将对象名称进行一定的算法得出一个HASH值,算法如下:


//根据名字计算HASH值。

hash = 0;

p = (PSHORT)wStr; //存放名称的一个WCHAR数组

while(*p)

{

Symb = (CHAR)*p;

hash = hash * 3 + (hash >> 1);

if (Symb < ‘a‘)  //<a

hash= hash  + Symb;

else if (Symb <= ‘z‘)   //即 a~z

hash = hash + Symb - 0x20;

else          // > z

hash = hash + (CHAR)RtlUpcaseUnicodeChar((WCHAR)*p);

p ++;

}

hash = hash % 37;  //最终的hash值。

系统将所有相同HASH值的对象链接到响应的数组项中,于是系统中所有元素将排列成如下的结构图:

系统根目录的对象的指针由ObpRootDirectoryObject来指定。

按理说,系统中只需要一个目录对象就够了,系统中所有的内核对象都将链接在这个目录对象上。但是不知什么原因,系统中并不是这样,系统中存在着多个目录对象,它们以根目录对象为根,组成一个“对象树”。每个目录对象中的哈希树的hash值的计算规则都是一样的。

我们可以根据系统中“对象树”的结构来遍历系统中所有的对象。

四.类型对象

内核对象中还有一种比较特殊的对象——类型对象。系统中每种类型对象只有一个类型对象,也就是说,系统中最多只有20几个类型对象。每种类型的对象都在其对象体中存在一个指向其类型对象的指针,因为一种类型对象只有一个实体,所以每种类型对象的指针都是固定的,这样我们就可以通过对象体中的类型对象指针来判断和访问对象的类型了。

各个类型对象的对象体内并没有链表结构使得它们相互链接起来。但是假如对象头部前面有OBJECT_CREATOR_INFO结构(见下表),则相同类型的对象就可以通过它的成员ObjectList相互链接起来了。但是,不幸的是:缺省情况下,只有Port和WaitPort两中类型的对象有这种结构。所以一般情况下,我们是不能通过类型对象来遍历这个系统中所有对象的。


typedef struct _OBJECT_CREATOR_INFO

{

LIST_ENTRY ObjectList; // OBJECT_CREATOR_INFO

HANDLE UniqueProcessId;

WORD Reserved1;

WORD Reserved2;

}OBJECT_CREATOR_INFO, *POBJECT_CREATOR_INFO, **PPOBJECT_CREATOR_INFO;

五.对象的遍历

上面分析过了,下面可以目录对象的遍历,来进行系统中所有对象的遍历。


//写一个递归函数。用来分析树型目录。

void AnalyseDirectory(POBJECT_DIRECTORY pDirectory, ULONG DirectoryType, int Level)

{

POBJECT_DIRECTORY_ENTRY pDirectoryEntry;

POBJECT_HEADER pObjectHeader;

POBJECT_NAME pObjectName;

PWCHAR wStr[200];

char Space[100];  //为生成空格用的。

int i, j;

for(i = 0; i < 36; i ++)  //DIR对象的对象体(BODY)是37个元素的数组。

{

pDirectoryEntry = pDirectory->HashTable[i];

while(pDirectoryEntry)

{

pObjectHeader = (POBJECT_HEADER)((ULONG)pDirectoryEntry->pObject - sizeof(OBJECT_HEADER));

//生成空格

RtlZeroMemory(Space, 100);

for(j = 0; j < 5 * Level; j ++)

Space[j] = ‘ ‘;

if (pObjectHeader->NameOffset)

{

pObjectName = (POBJECT_NAME)((ULONG)pObjectHeader  - pObjectHeader->NameOffset);

RtlZeroMemory(wStr, 200 * sizeof(WCHAR));

RtlCopyMemory(wStr, pObjectName->Name.Buffer, pObjectName->Name.Length);

DbgPrint("%s pObject: 0x%08X Name: %S", Space, pDirectoryEntry->pObject, wStr);

}

else

DbgPrint("%s pObject: 0x%08X Name: noname", Space, pDirectoryEntry->pObject);

//pObject对象是属性对象吗

if ((ULONG)pObjectHeader->pObjectType == DirectoryType)

AnalyseDirectory(pDirectoryEntry->pObject, DirectoryType, Level + 1);

pDirectoryEntry = pDirectoryEntry->NextEntry;

}

}//end of 遍历37个记录

}

六.对象的访问

内核中知道了内核对象的地址就可以直接访问这个内核对象了,但是在用户程序中却不能这样访问。Windows为内核对象的访问提供了一系列的函数。当调用一个用于创建内核对象的函数时,函数调用完便返回一个句柄值。句柄值是进程独立的,一个进程中的句柄值在另一个进程中是无效的。

句柄值是一个进程句柄表的索引。每个进程都有一个进程句柄表,而所有进程的句柄表串成一个句柄表链。这个链的头部地址保存在内核变量HandleTableListHead中。

下面具体看一下句柄表结构。系统将句柄表组织成和线性地址解析一样的结构。句柄表是个三层的表结构,而句柄值也被分成三部分,用来分别索引这三个部分。下面是句柄解析图:

七.总结

本文可以说是一个读书笔记。在参考了很多文章的基础上,然后作一些试验才完成本文的。内核对象是Windows内部的重要数据结构。通过本文可以大致了解Windows是如何组织众多的对象的。

八.参考

1.《Undocumented Windows 2000 Secrets》

2.Anathema《Inside Windows Nt Object Manager》

3.webcrazy《剖析Windows NT/2000内核对象组织》

4.《Inside Windows 2000》

5.《Windows核心编程》

注意:本节描述的句柄是再WIN2K下的句柄.WINXP下句柄表结构已经完全不同.

时间: 2024-08-29 02:43:06

(转)WINDOWS内核对象的相关文章

白话windows内核对象共享之复制对象句柄

引子:话说老王的果园大丰收,老王心花怒放,带着全家去美国阿拉斯加度假.阿拉斯加有很多东西琳琅满目,都是中国没有的,老王及家人都过了一把购物瘾.但是有一次却遇到了比较尴尬的事.怎么回事呢?原来老王第一次出国,在买地摊上的东西时讨价还价100元,但是给人家的却是100元人民币,人家自然不干撒,你100元才多少美元呀,老王只好忍痛割爱给了600元人民币. 为什么会出现这样的尴尬呢?因为两个国家的货币换算不是一样的.中国的100元和美国的100元不是等价的,如何才能等价呢?必须根据当前汇率来换算.今天要

windows内核对象管理学习笔记

目前正在阅读毛老师的<windows内核情景分析>一书对象管理章节,作此笔记. Win内核中是使用对象概念来描述管理内核中使用到的数据结构.此对象(Object)均是由对象头(Object Header)组成,实际上由于对象头概念的特殊结构,还有些可选成分.于是一个对象实际上是分为三部分. OBJECT_HEADER对象头. 数据本体(比如文件对象File Object.Event等) 附加信息(比如Object Header Name Info等) 结构如下: //摘录自 Reactos代码

Windows内核对象

1. 内核对象 Windows中每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核进行访问,应用程序不能在内存中定位这些数据结构并直接更改其内容.这个内存块是一个数据结构,其成员维护着与对象相关的信息.少数成员(安全描述符和使用计数)是所有内核对象都有的,但大多数成员都是不同类型对象特有的. 2. 内核对象的使用计数与生命期 内核对象的所有者是操作系统内核,而非进程.换言之也就是说当进程退出,内核对象不一定会销毁.操作系统内核通过内核对象的使用计数,知道当前有多少个进程正在

从hook开始聊聊那些windows内核数据结构

总览: IAT HOOK Object Hook Ssdt Hook 源码 内核知识及源码 内核知识级源码 一.IAT HOOK:因为上一篇博客对已经对IAT Hook基本流程及作用进行了介绍,希望能先学懂PE再来看IATHook.下面贴上Iathook的源码,源码中有详细的注释,还记着为什么不能结束360的进程吗?参考思路如下图(因为写代码的时候解决方案写到了源码中,不粘贴复制过来了): 以下代码是DLL注入+iathook,通过测试procexp中的kill功能并没有使用OpenProces

内核对象&amp;句柄&amp;泄漏&amp;检测

今天看到这个问题如何评价王垠的 <讨厌的 C# IDisposable 接口>? - 王垠(人物),答案被歪到windows 内核对象和句柄,答案中谈的太浅显而且有误.翻出陈年老文章(此文成于2012年,只在公司内部分享过),大部分内容来自Windows内核原理 1句柄和句柄泄露 在Windows编程过程中,很多时候我们都要和句柄打交道,比如窗体句柄,内核对象句柄,GDI句柄,Windows Multimedia库中的多种句柄等等,以及其他更多未曾使用过的句柄类型.句柄(Handle)是Win

Windows内核之内核对象

1内核对象定义: 1.1:每个内 核对象只是内核分配的一个内存块,并且只能由该内核访问. 1.2:该内存块是一种数据结构,它的成员负责维护该对象的各种信息. 有些数据成员(如安全性描述符.使用计数等)在所有对象类型中是相同的,但大多数数据成员属于特定的对象类型.例如,进程对象有一个进程ID .一个基 本优先级和一个退出代码,而文件对象则拥有一个字节位移.一个共享模式和一个打开模式. 2内核对象种类: 比如存取符号对象. 事件对象.文件对象.文件映射对象.I / O 完成端口对象.作业对象.信箱对

windows编程基础之内核对象

      学好windows编程,理解内核对象还是至关重要的(●'?'●).闲话不多说,下面先来了解一下关于内核对象的知识:       内核对象(kernel object):内核对象是用于管理进程.线程和文件等诸多种类的大量资源.       内核对象的分类:进程对象,线程对象,互斥量(mutex)对象,信号量(semaphore)对象,事件对象,作业对象,文件对象,文件映射对象,管道(pipe)对象,邮件槽(mailslot)对象,I/O完成端口对象,线程池工厂(thread pool 

读书笔记----《windows核心编程》第三章 内核对象1(句柄与安全性)

最近一直没有更新博客,因为一直在想一个问题,内核对象这一章内容很多很重要,自己没有掌握好也没有把握写好这一章,最后还是决定能写多少写多少,一面写一面学,后续学到新的再更新吧; <windows核心编程>提了几种内核对象: 访问令牌对象:与windows的安全性有关,目前不是很懂,了解后再写; 事件对象: Event对象,可跨进程同步; 由CreateEvent创建; 文件对象: File对象,比较常见; 由CreateFile创建; 文件映射对象: 通过文件映射可以方便的操作文件(如同文件数据

Windows API学习---线程与内核对象的同步

前言 若干种内核对象,包括进程,线程和作业.可以将所有这些内核对象用于同步目的.对于线程同步来说,这些内核对象中的每种对象都可以说是处于已通知或未通知的状态之中.这种状态的切换是由Microsoft为每个对象建立的一套规则来决定的.例如,进程内核对象总是在未通知状态中创建的.当进程终止运行时,操作系统自动使该进程的内核对象处于已通知状态.一旦进程内核对象得到通知,它将永远保持这种状态,它的状态永远不会改为未通知状态. 当进程正在运行的时候,进程内核对象处于未通知状态,当进程终止运行的时候,它就变