ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

(3)Windows系统总述

2020-12-03 17:00:47  阅读:254  来源: 互联网

标签:__ 总述 ULONG Windows OBJECT 系统 对象 POBJECT TYPE


一、说明

这是《Windows内核原理与实现》的第二章,主要是对一些概念进行科普,其中关于注册表和系统引导部分,我看着像在看天书,也没有写什么笔记。

这篇博客主要是记录一些我大概能看懂的,以便日后参考。其实也只是把书上的话自己总结了一下,实在没什么特别的,写博客已经是一种习惯了。

二、用户空间和内核空间

低2G是用户空间,高2G是内核空间,他们之间有一块特殊的内存。

0x7fff0000~0x7fffffff 这块特殊的64KB的地址空间,用户模式和内核模式都不能访问。

ProbeForWrite 函数用于检查用户代码是否访问了高2G内存或传递一个无效的指针,它常用于检测3环调用系统函数时的参数有效性检查。
只有当调用系统服务的是3环代码,才需要检查参数有效性,如果是另一个内核函数调用的,就无须检查。

PreviousMode = KeGetPreviousMode();
if (PreviousMode != KernelMode) {
    try {
        ProbeForWrite(InputInformation,
            InputInformationLength,
            sizeof(ULONG));
        if (ARGUMENT_PRESENT(ReturnLength)) {
        	ProbeForWriteUlong(ReturnLength);
        }
    } except(EXCEPTION_EXECUTE_HANDLER) {
    	return GetExceptionCode();
    }
}

首先检查目标内存地址是否越过了 0x7fff0000~0x7fffffff,如果是,就抛出非法访问内存异常;
然后,把目标内存的值写入到目标内存,如果不可写,就会触发异常,从而被 except 捕获。

ProbeForWrite 源码:

VOID
ProbeForWrite (
    __inout_bcount(Length) PVOID Address,
    __in SIZE_T Length,
    __in ULONG Alignment
    )

/*++

Routine Description:

    This function probes a structure for write accessibility and ensures
    correct alignment of the structure. If the structure is not accessible
    or has incorrect alignment, then an exception is raised.

Arguments:

    Address - Supplies a pointer to the structure to be probed.

    Length - Supplies the length of the structure.

    Alignment - Supplies the required alignment of the structure expressed
        as the number of bytes in the primitive datatype (e.g., 1 for char,
        2 for short, 4 for long, and 8 for quad).

Return Value:

    None.

--*/

{

    ULONG_PTR EndAddress;
    ULONG_PTR StartAddress;

#define PageSize PAGE_SIZE

    //
    // If the structure has zero length, then do not probe the structure for
    // write accessibility or alignment.
    //

    if (Length != 0) {

        //
        // If the structure is not properly aligned, then raise a data
        // misalignment exception.
        //

        ASSERT((Alignment == 1) || (Alignment == 2) ||
               (Alignment == 4) || (Alignment == 8) ||
               (Alignment == 16));

        StartAddress = (ULONG_PTR)Address;
        if ((StartAddress & (Alignment - 1)) == 0) {

            //
            // Compute the ending address of the structure and probe for
            // write accessibility.
            //

            EndAddress = StartAddress + Length - 1;

            
            //DbgPrint("Hbg: MM_USER_PROBE_ADDRESS = %x\n", MM_USER_PROBE_ADDRESS);
            // MM_USER_PROBE_ADDRESS = 7fff0000
            // 如果越过了 MM_USER_PROBE_ADDRESS ,就抛出非法访问内存异常

            if ((StartAddress <= EndAddress) &&
                (EndAddress < MM_USER_PROBE_ADDRESS)) {

                //
                // N.B. Only the contents of the buffer may be probed.
                //      Therefore the starting byte is probed for the
                //      first page, and then the first byte in the page
                //      for each succeeding page.
                //
                // If this is a Wow64 process, then the native page is 4K, which
                // could be smaller than the native page size/
                //

                EndAddress = (EndAddress & ~(PageSize - 1)) + PageSize;
                do {
                    // 目标内存的值写入到目标内存,volatile 用于关闭编译器优化,确保写入发生
                    *(volatile CHAR *)StartAddress = *(volatile CHAR *)StartAddress;
                    // 一次检查一个字节,一个字节能写入,说明整个页都能写入
                    StartAddress = (StartAddress & ~(PageSize - 1)) + PageSize;
                } while (StartAddress != EndAddress);

                return;

            } else {
                // 非法访问内存
                ExRaiseAccessViolation();
            }

        } else {
            // 内存对齐异常
            ExRaiseDatatypeMisalignment();
        }
    }

    return;
}

三、系统线程,PsCreateSystemThread

驱动程序可以调用 PsCreateSystemThread 来创建系统线程,默认属于 System 进程,也可以指定所属进程从而能访问该进程的内存。

四、中断和异常

中断和异常都会打断正常指令流,中断是CPU产生的,异常的产生则是指令执行后的结果。所以中断是异步的,异常是同步的。

五、内核对象,名称系统

对象头

windows 提供了多种类型的内核对象,设计遵循面向对象思想,每个对象都由对象头和对象体构成。

_OBJECT_HEADER 对象头的定义在 base\ntos\inc\ob.h ,存储了对象管理所需的基本信息,如引用计数,句柄计数,对象名,对象类型等。

typedef struct _OBJECT_HEADER {
    LONG_PTR PointerCount;                      // 引用计数
    union {
        LONG_PTR HandleCount;                   // 指向该对象的句柄数
        PVOID NextToFree;                       // 对象呗延迟删除时加入到一条链中
    };
    POBJECT_TYPE Type;                          // 指向对象的类型对象
    UCHAR NameInfoOffset;                       // 名称信息的内存偏移
    UCHAR HandleInfoOffset;                     // 句柄信息的内存偏移
    UCHAR QuotaInfoOffset;                      // 配额信息的内存偏移
    UCHAR Flags;

    union {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

    PSECURITY_DESCRIPTOR SecurityDescriptor;    // 安全描述符
    QUAD Body;                                  // 对象体开始
} OBJECT_HEADER, *POBJECT_HEADER;

其中,对象类型 POBJECT_TYPE Type 是一个指针,指向的类型就叫 OBJECT_TYPE ,它同样定义在 ob.h ,OBJECT_TYPE 存储了对象类型的信息,包括在全局对象类型数组中的索引,拷贝自对象头的对象名等。

对象类型

#define OBJECT_LOCK_COUNT 4

typedef struct _OBJECT_TYPE {
    ERESOURCE Mutex;
    LIST_ENTRY TypeList;
    UNICODE_STRING Name;            // Copy from object header for convenience
    PVOID DefaultObject;
    ULONG Index;                    // 此类型对象在全局数组中的索引
    ULONG TotalNumberOfObjects;
    ULONG TotalNumberOfHandles;
    ULONG HighWaterNumberOfObjects;
    ULONG HighWaterNumberOfHandles;
    OBJECT_TYPE_INITIALIZER TypeInfo;
#ifdef POOL_TAGGING
    ULONG Key;
#endif //POOL_TAGGING
    ERESOURCE ObjectLocks[ OBJECT_LOCK_COUNT ];
} OBJECT_TYPE, *POBJECT_TYPE;

在这里插入图片描述

WRK提供了31种对象类型,例如我们在中级班接触过的 PsThreadType, PsProcessType ,IoDriverObjectType 等。这些对象类型是系统初始化时调用 ObCreateObjectType 函数创建的。

ObCreateObjectType 函数原型如下:

NTSTATUS
ObCreateObjectType (
    __in PUNICODE_STRING TypeName,
    __in POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
    __in_opt PSECURITY_DESCRIPTOR SecurityDescriptor,
    __out POBJECT_TYPE *ObjectType
);

第二个参数用到了 OBJECT_TYPE_INITIALIZER 类型,它除了指定了此种类型对象的一些数据特性,还指定了该类型对象的一些基本操作方法,如 Dump, Open, Close 等。

typedef struct _OBJECT_TYPE_INITIALIZER {
    USHORT Length;
    BOOLEAN UseDefaultObject;
    BOOLEAN CaseInsensitive;
    ULONG InvalidAttributes;
    GENERIC_MAPPING GenericMapping;
    ULONG ValidAccessMask;
    BOOLEAN SecurityRequired;
    BOOLEAN MaintainHandleCount;
    BOOLEAN MaintainTypeList;
    POOL_TYPE PoolType;
    ULONG DefaultPagedPoolCharge;
    ULONG DefaultNonPagedPoolCharge;
    OB_DUMP_METHOD DumpProcedure;
    OB_OPEN_METHOD OpenProcedure;
    OB_CLOSE_METHOD CloseProcedure;
    OB_DELETE_METHOD DeleteProcedure;
    OB_PARSE_METHOD ParseProcedure;
    OB_SECURITY_METHOD SecurityProcedure;
    OB_QUERYNAME_METHOD QueryNameProcedure;
    OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure;
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

对象类型数组 ObpObjectTypes

系统使用static全局数组 ObpObjectTypes 记录所有已创建的类型,限定不超过48种对象类型,OBJECT_TYPE 中的 Index 就是对象类型在此数组中的下标。

#define OBP_MAX_DEFINED_OBJECT_TYPES 48
POBJECT_TYPE ObpObjectTypes[ OBP_MAX_DEFINED_OBJECT_TYPES ];

创建对象

类型创建后,就可以调用 ObCreateObject 函数创建对象了。

NTSTATUS
ObCreateObject (
    __in KPROCESSOR_MODE ProbeMode,
    __in POBJECT_TYPE ObjectType,
    __in POBJECT_ATTRIBUTES ObjectAttributes,
    __in KPROCESSOR_MODE OwnershipMode,
    __inout_opt PVOID ParseContext,
    __in ULONG ObjectBodySize,
    __in ULONG PagedPoolCharge,
    __in ULONG NonPagedPoolCharge,
    __out PVOID *Object
);

其中,ObjectBodySize 指定了对象体的大小,输出参数 Object 指向对象体的地址。

名称系统

windows提供了一套以名称来管理对象的机制,这对于跨模块,跨进程共享对象提供了便利。windows维护了一套全局的名称查询机制,ObpDirectoryObjectType 类型对象是实现这一机制的关键。下面来简单分析一下这套名称查询机制。

全局变量 ObpRootDirectoryObject 是根目录对象:

#define NUMBER_HASH_BUCKETS 37
#define OBJ_INVALID_SESSION_ID 0xFFFFFFFF

typedef struct _OBJECT_DIRECTORY {
    struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[ NUMBER_HASH_BUCKETS ];
    EX_PUSH_LOCK Lock;
    struct _DEVICE_MAP *DeviceMap;
    ULONG SessionId;
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;

...

POBJECT_DIRECTORY ObpRootDirectoryObject;

根目录之下,系统内置了一些子目录,通过分析 NtCreateDirectoryObject 函数被调用的情况,我们可以看到 Callback、ArcName、Device、Driver、FileSystem、KernelObjects、ObjectTypes、GLOBAL?? 和 Security
子目录的创建过程。例如,阅读 IopCreateRootDirectories 函数,发现这里创建了 Driver 子目录:

//
// Create the root directory object for the \Driver directory.
//

RtlInitUnicodeString( &nameString, L"\\Driver" );
InitializeObjectAttributes( &objectAttributes,
                           &nameString,
                           OBJ_PERMANENT|OBJ_KERNEL_HANDLE,
                           (HANDLE) NULL,
                           (PSECURITY_DESCRIPTOR) NULL );

status = NtCreateDirectoryObject( &handle,
                                 DIRECTORY_ALL_ACCESS,
                                 &objectAttributes );
if (!NT_SUCCESS( status )) {
    return FALSE;
} else {
    (VOID) ObCloseHandle( handle , KernelMode);
}

对象管理器内部有一套函数用于插入、查询和删除目录项或目录。对外提供了 ObOpenObjectByName 和ObReferenceObjectByName 函数用来根据名称打开或引用对象。这些函数我暂时不打算分析,猜测其内部应该是哈希表实现的。

对象体

分析 ObpAllocateObject 函数发现,对象体和对象头在同一块连续内存:

ObjectHeader = ExAllocatePoolWithTag( PoolType,
                                     HeaderSize + ObjectBodySize,
                                     (ObjectType == NULL ? 'TjbO' : ObjectType->Key) |
                                     PROTECTED_POOL );

通过对象头获取对象体的方法是这样的:

#define OBJECT_TO_OBJECT_HEADER( o ) \
	CONTAINING_RECORD( (o), OBJECT_HEADER, Body )

内核对象生命周期,内核计数

内核对象通过引用计数管理生命周期,当引用计数为0,对象就被销毁。引用计数来源于两方面,一个是内核的指针引用该对象,增加引用计数和减少引用计数的函数是 ObReferenceObjectByPointer
和 ObDereferenceObject;另一个是进程打开内核对象并获得一个句柄,增加减少句柄的函数是 ObpIncrementHandleCount 和ObpDecrementHandleCount 。

标签:__,总述,ULONG,Windows,OBJECT,系统,对象,POBJECT,TYPE
来源: https://blog.csdn.net/Kwansy/article/details/110546927

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有