Windows句柄与内核对象
内核对象
基本概念
例如,访问令牌,事件对象,文件对象,文件映射对象,I/O完成端口对象,作业对象,邮件槽对象,互斥量对象,管道,进程对象,信号量对象,线程对象,可等待计时器对象,线程池工厂
这些对象是通过不同名称的函数创建的
每个内核对象都是一个内存块,成员维护着与对象相关的信息
内核对象只能由操作系统内核访问
利用Windows提供的一组函数,这组函数会以最恰当的方式来操纵这些结构
句柄
调用一个会创建内核对象的函数后,函数会返回一个句柄(handle),它标识了所创建的对象
可以把这个句柄想象成一个不透明(opaque)的值,它可由进程中的任意线程使用
在32位Windows进程中,句柄是一个32位值,在64位Windows进程中,句柄是64位值
句柄是与进程相关的,将句柄传给另一个进程中的线程,那么另一个进程用我们的进程的句柄值来发出调用时,可能会失败
使用计数
指明多少个进程正在使用同一个内核对象
内核对象的安全性?
内核对象可以用一个安全描述符(security descriptor,SD)来保护,描述了谁拥有对象
进程内核对象句柄表
一个进程在初始化时,系统将为它分配一个句柄表,这个句柄表仅供内核对象使用,不适用于用户对象或GDI对象
每个结构都包含指向一个内核对象的指针,一个访问掩码和一些标志
索引 | 指向内核对象内存块的指针 | 访问掩码(包含标志位的一个DWORD) | 标志 |
1 | 0x??? | 0x??? | 0x??? |
2 | 0x??? | 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,相当于向系统表明我们要创建一个未命名的内核对象,微软没有提供任何专门的机制来保证内核对象的名称是唯一的。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!