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下句柄表结构已经完全不同.

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

  1. Windows内核对象

    1. 内核对象 Windows中每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核进行访问,应用程序不能在内存中定位这些数据结构并直接更改其内容.这个内存块是一个数据结构,其成员 ...

  2. windows内核对象句柄

    内核对象用于管理进程.线程和文件等诸多种类的大量资源,每一个内核对象都只是一个句内存快,它由操作系统内核分配,并只能右操作系统内核访问.这个内存块是一个数据结构,其维护着与对象相关的信息,其中少数成员 ...

  3. windows内核对象管理学习笔记

    目前正在阅读毛老师的<windows内核情景分析>一书对象管理章节,作此笔记. Win内核中是使用对象概念来描述管理内核中使用到的数据结构.此对象(Object)均是由对象头(Object ...

  4. windows内核对象可以等待

    内核对象有两种状态 触发 与未触发. 是可以等待的.

  5. 内核对象&句柄&泄漏&检测

    今天看到这个问题如何评价王垠的 <讨厌的 C# IDisposable 接口>? - 王垠(人物),答案被歪到windows 内核对象和句柄,答案中谈的太浅显而且有误.翻出陈年老文章(此文 ...

  6. windows核心编程---第八章 使用内核对象进行线程同步

    使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...

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

    前言 若干种内核对象,包括进程,线程和作业.可以将所有这些内核对象用于同步目的.对于线程同步来说,这些内核对象中的每种对象都可以说是处于已通知或未通知的状态之中.这种状态的切换是由Microsoft为 ...

  8. Windows核心编程学习九:利用内核对象进行线程同步

    注:源码为学习<Windows核心编程>的一些尝试,非原创.若能有助于一二访客,幸甚. 1.程序框架 #include "Queue.h" #include <t ...

  9. 内核对象 windows操作系统

    问题: 什么是内核对象? 答:内核对象实际上时由内核分配的一块内存,而且只能由内核来访问.它时一个数据结构,成员包含有关于该对象的信息.一些成员对于所有对象类型都是一样的,比如对象名称.安全描述.使用 ...

随机推荐

  1. 转: linux文件链接(软链接和硬链接)

    链接:一种在共享文件和访问它的用户的若干目录项之间建立联系的一种方法. Linux中包括两种链接:硬链接(Hard Link)和软链接(Soft Link),软链接又称为符号链接(Symbolic l ...

  2. Sublime 插件安装、常用配置

    安装:sublime + 插件 安装Sublime: 官网:http://www.sublimetext.com/ 安装package control组件,之后我们会使用该组件给Sublime安装常用 ...

  3. sharepoint 2013 文档库 资源管理器打开报错 在文件资源管理器中打开此位置时遇到问题,将此网站添加到受信任站点列表,然后重试。

    我们在使用sharepoint 2013的文档库或者资源库的时候,经常会需要用到使用“资源管理器”来管理文档,但是有时候,点击“使用资源管理器打开”,会提示如下错误: 在文件资源管理器中打开此位置时遇 ...

  4. SSDP协议的Android实现以及使用

    前面一篇博客里面已经介绍过SSDP协议原理,本篇博客将实现实现Android上的SSDP协议. 关键技术分析:1.发送广播:须要发送送广播,所以须要使用MulticastSocket.SocketAd ...

  5. BootStrap 智能表单系列 三 分块表单配置的介绍

    相信广大博友肯定碰到过一个编辑页面分了很多块的情况,智能表单插件已经为您支持了这种情况, 代码如下(链接地址:https://github.com/xiexingen/Bootstrap-SmartF ...

  6. C#复习一( Twenty Days)

      今天开始将要复习最近所学的一些C#知识.下面就来总结一下今天所复习的内容,以此来巩固我对C#知识的掌握.今天主要以举几个程序为例. 首先还是要注意代码的规范: –注释//,/**/,/// –骆驼 ...

  7. npm 安装

    1.https://nodejs.org/en/  下载node.js 控制台,查看node版本 C:\WINDOWS\system32>node --version  出现版本表示安装成功 2 ...

  8. Lowest Common Ancestor of a Binary Tree, with Parent Pointer

    Given a binary tree, find the lowest common ancestor of two given nodes in tree. Each node contains ...

  9. Mysql的四种分区

    mysql一共有四大分区分别为hash range list key 四个分区. 分区的字段需要时主键才可以成功 . 第一种 hash分区 第二张list分区 第三种 key分区 第四种 range分 ...

  10. iOS现有工程 集成 Cordova/Ionic

    首先, 新建 Cordova 项目就不说了, 步骤: http://ionicframework.com/getting-started/ , cordova生成的项目用cdv_project称呼, ...