终端服务命名空间
- 在正在允许终端服务的计算机中,有多个用于内核对象的命名空间。
- 其中一个是全局命名空间,所有客户端都能访问到的内核对象要放在这个命名空间里面。这个命名空间主要由服务使用。
- 此外,每个客户端会话都有一个自己的命名空间。
- 可以通过ProcessIdToSessionId知道我们的进程在哪个终端服务中运行。
1 2 3 4 5 6 7 8 9 10 |
DWORD processID = GetCurrentProcessId(); DWORD sessionID; if (ProcessIdToSessionId(processID, sessionID)) { tprintf(TEXT("process '%u' runs in terminal services session '%u'"), processID, sessionID); } else { tprintf(TEXT("unable to get terminal services session id for process '%u'"), processID); } |
- 一个服务的命名内核对象始终是位于全局命名空间内的。默认情况下,在终端服务中,应用程序自己的命名内核对象在会话的命名空间内。
但是可以强制把一个命名对象放入全局命名空间中,如下:
1 |
HADNLE handle = CreateEvent(NULL, FALSE, FALSE, TEXT("Global\\MyName")); |
- 也可以显示指出希望把一个内核对象放在当前会话的命名空间内,如下:
1 |
HANDLE handle = CreateEvent(NULL, FALSE, FALSE, TEXT("Local\\MyName")); |
专有命名空间
- 如果要确保我们自己创建的内核对象名称永远不会和其他应用程序的名称冲突,或者要确保它们免遭劫持,可以自定义前缀。并把这个前缀作为自己专有的命名空间使用。
1 2 3 4 5 6 7 8 9 |
// 第一步 // 创建边界描述符 // pszName // 用来命名一个范围的字符串标识符 // 返回值是一个指针,并非是句柄,关闭需要调用DeleteBoundaryDescriptor // 该指针指向一个用户模式的结构,结构中包含了边界的定义 HANDLE CreateBoundaryDescriptor( PCTSTR pszName, DWORD dwFlags); |
1 2 3 4 5 6 |
// 第二步 // 将一个特权用户组的SID与边界描述符关联起来 // 为边界描述符添加的SID决定了谁能进入边界并创建命名空间 BOOL AddSIDToBoundaryDescriptor( HANDLE* phBoundaryDescriptor, PSID pRequiredSid); |
1 2 3 4 5 6 7 |
// 第三步 // 第一个参数是给Windows用的,用于允许/禁止应用程序通过调用OpenPrivateNamespace来访问 // 命名空间并在其中打开/创建对象。 HANDLE CreatePrivateNamespace( PSECURITY_ATTRIBUTES psa, PVOID pvBoundaryDescriptor, PSTSTR pszAliasPrefix); |
1 2 3 4 5 6 7 8 |
// 如果用上面的函数试图创建一个已经存在的命名空间,这个函数将返回NULL // GetLastError将返回ERROR_ALREADY_EXISTS // 这时应该使用OpenPrivateNamespace // 需要注意的是,CreatePrivateNamespace和OpenPrivateNamespace返回的HANDLE并不是内核对象的句柄 // 对于这种伪句柄,需要使用对应的ClosePrivateNamespace来关闭 HANDLE OpenPrivateNamespace( PVOID pvBoundaryDescriptor, PCTSTR pszAliasPrefix); |
1 2 3 |
BOOLEAN ClosePrivateNamespace( HANDLE hNamespace, DWORD dwFlags); |
- 对于使用ClosePrivateNamespace关闭命名空间时,如果希望关闭后该空间仍然可见,dwFlags传入0。
否则传入PRIVATE_NAMESPACE_FLAG_DESTROY。 - 边界的话,将在两种情况下关闭:
- 进程终止运行
- 调用了DeleteBoundaryDescriptor
- 需要注意的是,如果还有内核对象在被使用,一定吧不要关闭命名空间。
四 跨进程边界共享内核对象
复制对象句柄
1 2 3 4 5 6 7 8 |
BOOL DuplicateHandle( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, PHANDLE phTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); |
- 这个函数获得一个进程的句柄表中的一个记录项,然后在另一个句柄表中创建这个记录项的一个副本。
- 第一个和第三个参数是内核对象句柄。这两个句柄本身必须相对于调用这个函数的那个进程。另外,这两个参数标识的必须是进程内核对象。如果传递的句柄指向的是其他类型的句柄,函数调用就会失败。
- 第二个参数指向的是任何类型的内核对象的一个句柄。需要注意的是,这个句柄必须不能与调用这个函数的那个进程相关。该句柄必须与hSourceProcessHandle句柄所标识的那个进程相关。
- 第四个参数是HANDLE变量的地址,用来接收复制得到的HANDLE值。
- 最后三个参数用来指定这个内核对象在目标进程中所对应的句柄表项,而且应该使用何种访问掩码和继承标志。
- dwOptions
- 0
- DUPLICATE_SAME_ACCESS
希望目标句柄拥有与源进程的句柄一样的访问掩码
使用这个标志后,会忽略掉dwDesiredAccess参数 - DUPLICATE_CLOSE_SOURCE
会关闭掉源进程中的句柄
使用这个标志可以轻松的将一个内核对象传给另一个进程
使用这个标志后,内核对象的使用计数不会受到影响
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Windbg:命令实践详解一03/27
- ♥ Windows 核心编程 _ 线程内幕07/06
- ♥ WinDbg命令标记、命令07/11
- ♥ SOUI源码:log4z06/24
- ♥ Soui七06/02
- ♥ Windows物理内存虚拟内存03/28