现在的位置: 首页 > 综合 > 正文

Windows系统编程(一):内核对象

2018年04月04日 ⁄ 综合 ⁄ 共 2055字 ⁄ 字号 评论关闭
文章目录

作者:yurunsun@gmail.com
新浪微博@孙雨润
新浪博客
CSDN博客
日期:2012年11月3日

1. 何为内核对象

1.1 定义

内核对象是一个内存中的数据结构,只能由OS内核分配访问。访问内核对象的API会返回进程相关的Handle,无法直接跨进程共享。内核对象使用Count Reference,Life Cycle可能长于创建它的进程。

【Note】使用Sysinternals的WinObj可以查看所有内核对象类型的列表。

1.2 安全性

创建内核对象的API都有SECURITY_ATTRIBUTES做参数,如果不需要加访问限制则传NULL。如果想访问现有内核对象,需要指定即将执行的操作:

HANDLE hFileMap = OpenFileMapping(FILE_MAP_READ, FALSE, _T("TestFileMap"));

如果访问被拒绝会返回NULL。

2. 进程内核对象句柄表

进程初始化时系统为其分配一个Handle table,仅供内核对象使用而非用户对象或GDI对象。

2.1 创建

下面是一些用于常见内核对象的API:

HANDLE CreateThread(...);
HANDLE CreateFile(...);
HANDLE CreateFileMapping(...);
HANDLE CreateSemaphore(...);

【Note】CreateFile返回值与INVALID_HANDLE_VALUE比较,其余与NULL比较。

2.2关闭

CloseHandle(HANDLE hObject);

3. 跨进程边界共享内核对象

下面情况需要共享内核对象:

  • 利用FileMapping,在同一个OS上不同Process共享数据
  • 借助Mail Slot/Pipe,在网络中不同PC上运行的进程互相发送数据
  • Semaphore、Event、Mutex允许不同Process中的Thread同步执行

3.1 方法一:对象Handle继承

只有Process之间有父子关系时使用这种方式,使子进程能访问父进程的内核对象。

  • 使用上边提到的SECURITY_ATTRIBUTES:

    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    HANDLE hMutex = CreateMutex(&sa, FALSE, NULL);
    
  • 调用CreateProcess创建子进程,bInheritHandles传TRUE

  • OS遍历父进程Handle table,将Inheritable的内核对象copy到子进程的Handle table,子进程的Handle table中复制项位置与父进程中位置完全一样,保证Handle相同
  • OS递增引用计数
  • 正在运行的子进程不会继承父进程后来创建的新内核对象
  • 通常使用命令行参数、IPC、环境变量几个方法使子进程知道继承的Handles

3.2 改变Handle的Flag

父进程想控制哪些子进程能继承内核对象Handle:

BOOL SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags);

SetHandleInformation(hObj, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); // Open
SetHandleInformation(hObj, HANDLE_FLAG_INHERIT, 0); // Close    
SetHandleInformation(hObj, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);  // 禁止close句柄

3.3 方法二:为内核对象命名

许多内核对象创建时可以使用pszName命名,pszNameNULL时为匿名对象。【Note】Create*函数不知道刚刚是新建了一个内核对象,还是打开了一个现有的同名内核对象,因此最好使用Open*函数测试。

3.4 方法三:Copy对象Handle

进程S能访问一个内核对象,希望T也能访问也能访问:

HANDLE hObjInProcessS = CreateMutex(NULL, FALSE, NULL);
HANDLE hProcessT = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessIdT);
HANDLE hObjInProcessT;
DuplicateHandle(GetCurrentProcess(), hObjInProcessS, hProcessT, &hObjInProcessT, 0, FALSE, DUPLICATE_SAME_ACCESS);
CloseHandle(hProcessT);

抱歉!评论已关闭.