1.什么是内核对象
种类:访问令牌对象、事件对象、文件对象、文件映射对象、I/O完成端口对象、作业对象、信号量对象、线程对象、
邮件槽对象、互斥量对象、管道对象、 可等待的计时器对象、线程池工厂。
句柄来控制内核对象,内核对象由windows维护。
使用内核对象查看工具:WinObj.exe
句柄(Handle)标识了内核对象,进程相关。
内核对象的计数及销毁:和java垃圾回收系统机制类似。
内核对象的安全性:安全描述符(SD),谁创建,谁能使用,谁不能使用。
所有创建内核对象的函数几乎都有参数指向SECURITY_ATTRIBUTES结构:NULL默认安全性。[p35]
IpSecurityDescriptor:安全描述符
检查:访问内核对象时,会先告知打算进行的操作。若返回NULL,可以用getLastError。
错误:若告知的操作为KEY_ALL_ACCESS,会导致非管理员用户不能使用。要使用正确的安全访问标志。
区分内核对象及用户对象、GDI对象:看创建对象时是否有PSECURITY_ATTRIBUTES参数。
2.进程内核对象句柄表
句柄表:进程初始化时分配,供内核使用。
内存块指针:指向被分配的内核对象数据结构的地址。
访问掩码:权限。
句柄值:实际值=句柄值/4,从4开始。
创建内核对象:
1. 会增加句柄项
相关方法:CreateThread, CreatFile, CreateFileMapping, CreateSemaphore
返回的句柄可供进程内所有线程使用。
关闭内核对象:
1. BOOL CloseHandle(HANDLE hobject);
2. 先检查权限,再使“使用计数”减一
*需要将hobject置为NULL
*使用Process Explorer检查泄露的handles
3.跨进程共享内核对象
文件映射对象:进程间共享数据
邮件槽和命名管道:网络中进程发送数据块
互斥量信号量和事件:允许不同进程中的线程同步执行
---方法1,使用对象句柄继承---
1.父进程创建内核对象时,指出对象的句柄是可继承的(对象本身不可继承)。[p42]
父进程分配并初始化一个SECURITY_ATTRIBUTES,传给具体的Create函数。见句柄表的标志
2.父进程生成子进程,CreateProcess
BOOL bInheritHandles需要为TRUE
父进程和子进程中,对一个内核对象进行标识的句柄值是一样的。
子进程仍会将内核对象使用计数加1:子进程仍可访问被父进程关闭的内核对象
*系统上所有进程都共享内核空间
3.子进程获得它想要的内核对象句柄值
父进程将句柄值作为命令行参数传给子进程
父进程等待子进程完成初始化(WaitForInputIdle),发送消息
父进程向其环境块添加一个环境变量,子进程会继承环境变量,获得句柄值。适合反复继承。
---改变句柄标志---
控制句柄的继承标志
SetHandleInformation
可继承->不可继承
允许关闭句柄->不允许关闭句柄
获得标志:GetHandleInformation
---方法2,为对象命名---
1.通过函数创建命名的内核对象
CreateMutex
CreateEvent
CreateWaitableTimer......
参数pszName:NULL即匿名,否则命名
*没有机制防止重名
2.共享方法
2.1.进程A调用 CreateMutex(NULL, FALSE, TEXT("JeffMutex"));
2.2.另一个进程B调用CreateMutex(NULL, FALSE, TEXT("JeffMutex"));(前两个参数会被忽略)
2.3.系统检查类型,检查访问权限(限制权限,可以使用ex版本的dwDesiredAccess参数),若成功,则返回Handle
*两个进程的句柄值可能不同。
*可以使用GetLastError判断CreateMutex是否创建了新的对象。
*名称不可重复,可使用GUID防止重复
2.2.1也使用Open*函数搜索匹配对象,而不create
*利用命名对象来防止一个应用程序多开[p50]
---终端服务命名空间---
客户端会话拥有命名空间,防止名称重复导致问题
适用于远程桌面、快速用户切换、服务器
使用ProcessIdToSessionId(WinBase.h)来得知进程在那个会话中运行。
强制把命名对象放入全局命名空间:Global\ 命名前缀
强制把命名对象放入当前回话命名空间:Local\ 命名前缀
---专有命名空间---
命名对象使用自定义前缀防止命名劫持,并关联一个安全描述符,更安全的singleton程序
[p54]CheckInstaces函数
---方法3,复制对象句柄---
DuplicateHandle
催化剂进程C获得一个进程A句柄表中一个记录项,并在另一个进程B的句柄表中创建它的一个副本。