Windows句柄与内核对象

2023-12-14 17:42:01

内核对象

基本概念

例如,访问令牌,事件对象,文件对象,文件映射对象,I/O完成端口对象,作业对象,邮件槽对象,互斥量对象,管道,进程对象,信号量对象,线程对象,可等待计时器对象,线程池工厂

这些对象是通过不同名称的函数创建的

每个内核对象都是一个内存块,成员维护着与对象相关的信息

内核对象只能由操作系统内核访问

利用Windows提供的一组函数,这组函数会以最恰当的方式来操纵这些结构

句柄

调用一个会创建内核对象的函数后,函数会返回一个句柄(handle),它标识了所创建的对象

可以把这个句柄想象成一个不透明(opaque)的值,它可由进程中的任意线程使用

在32位Windows进程中,句柄是一个32位值,在64位Windows进程中,句柄是64位值

句柄是与进程相关的,将句柄传给另一个进程中的线程,那么另一个进程用我们的进程的句柄值来发出调用时,可能会失败

使用计数

指明多少个进程正在使用同一个内核对象

内核对象的安全性?

内核对象可以用一个安全描述符(security descriptor,SD)来保护,描述了谁拥有对象

进程内核对象句柄表

一个进程在初始化时,系统将为它分配一个句柄表,这个句柄表仅供内核对象使用,不适用于用户对象或GDI对象

每个结构都包含指向一个内核对象的指针,一个访问掩码和一些标志

索引指向内核对象内存块的指针访问掩码(包含标志位的一个DWORD)标志
10x???0x???0x???
20x???0x???0x???
............

创建一个内核对象

一个进程在初始化的时候,其句柄表为空。当进程内的一个线程调用一个会创建内核对象的函数时,内核将为这个对象分配并初始化一个内存块。然后,内核扫描进程的句柄表,查找一个空白的记录项,对其进行初始化。

用于创建内核对象的任何函数都会返回一个与进程相关的句柄,这个句柄可由同一个进程中运行的所有线程使用。创建内核对象的函数有CreateThread,CreateFile,CreateFileMapping,CreateSemaphore

调用一个函数时,如果它接受一个内核对象句柄作为参数,就必须把Create*函数的返回值传给它,该函数会查找该进程的句柄表,获得目标内核对象的地址,然后以一种恰当的方式来操纵对象的数据结构。

关闭内核对象

无论以什么方式创建内核对象,关闭内核对象的API为

BOOL CloseHandle(HANDLE hobject);

函数会验证传给函数的句柄值标识是进程有权访问的一个对象,如果句柄有效,系统就会获得内核对象的数据结构地址,并将结合中的“使用记数”减一

跨进程边界共享内核对象

使用对象句柄继承

只有在进程之间有一个父—子关系的时候,才可以使用对象句柄继承

父进程决定生成一个子进程,并允许子进程访问父进程的内核对象。

执行步骤:

1.父进程创建一个内核对象时,父进程必须向系统指出他希望这个对象句柄是可以继承的(父进程必须分配并初始化一个SECURITY_ATTRIBUTES,并将这个结构的地址传给具体的Create函数)

SECURITY_ATTRIBUTES sa;
sa.nLength=sizeof(sa);
sa.lpSecurityDescriptor=NULL;
sa.bInheritHandle=TRUE;

HANDLE hMutex=CreateMutex(&sa,FALSE,NULL);

创建了一个SECURITY_ATTRIBUTES结构,表明对象要用默认安全性来创建,而且返回的句柄是可以继承的

此时句柄表中的是否可以继承的标志位被设置为1

2.创建子进程

使用CreateProcess函数来完成

将参数bInheritHandle设置为TRUE,就会继承父进程中可继承的句柄

改变句柄的标志

父进程创建了一个内核对象,得到了一个可继承的句柄,然后生成了两个子进程。但是,父进程只希望其中一个子进程继承内核对象的句柄。

使用SetHandleInformation函数来改变内核对象的继承标志。

BOOL SetHandleInformation(

????????HANDLE hObject,

? ? ? ? DWORD dwMask,

? ? ? ? DWORD dwFlags);

dwMask告诉函数我们要更改哪个或者哪些标志

如果想把每个对象的标志一次性更改完毕,可以对这两个标志执行一次按位或运算。

我么可以用GetHandleInformation来检查一下一个句柄是否可以被继承

DWORD dwFlags;
GetHandleInformation(hObj,&dwFlags);
BOOL fHandleIsInheritable=(0!=(dwflags&HANDLE_FLAG_INHERIT);

为对象命名

许多内核对象都可以进行命名

HANDLE CreateMutex(
    PSECURITY_ATTRIBUTES psa,
    BOOL bInitialOwner,
    PCTSTR pszName);

很多函数最后一个参数都是pszName,向此参数传入NULL,相当于向系统表明我们要创建一个未命名的内核对象,微软没有提供任何专门的机制来保证内核对象的名称是唯一的。

文章来源:https://blog.csdn.net/m0_73644864/article/details/134995413
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。