设备描述表对象HDC,画刷对象HBRUSH,画笔对象HPEN等等,这些不是核心对象,是GDI绘图对象,也是用户对象。
区别用户对象和内核对象的通用方法是,创建内核对象的时候有个PSECURITY_ATTRIBUTES类型的参数,该参数是一个指向 SECURITY_ATTRIBUTES 结构的指针,该结构描述了所创建的内核对象的安全性,比如是否可以被子进程继承。
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES;
内核对象是属于windows的,而不是属于进程的,但进程中有一个句柄表,引用了内核对象。
内核对象有一个使用计数,一个进程的内核对象句柄表中引用了某个内核对象,该内核对象的使用计数就递增1,该进程调用CloseHandle(hHandle)时,引用计数递减,当引用计数为0时,内核对象被销毁,当进程退出时,进程所有内核对象的引用计数都递减。
常见的内核对象:文件对象,文件映射对象,事件(event)对象,互斥量(mutex)对象,进程对象,线程对象。
创建一个内核对象时,返回一个句柄,该句柄在32位windows时为一个无符号32位整数,讲该整数右移两位就得到了句柄在进程的句柄表中的索引值。
下面是如何在进程间共享内核对象。
跨进程边界共享内核对象有三种方法: 对象句柄继承, 为对象命名, 复制对象句柄。
1 对象句柄继承:
SECURYTY_ATTRIBUTES中的第三个成员 bInheritHandle 指定了创建的内核对象是否可被子进程共享,如果指定为TRUE,CreateProcess创建子进程的时候,指定参数bInheritHandle为TRUE,那么该对象句柄就会被共享。 (此时子进程与父进程的内核对象句柄在两个进程的句柄表中的位置一摸一样,所以相同的句柄值,都能知道句柄表中的那条句柄记录,并指向相同的内存地址,那个内存地址保存了内核对象,当然你不能直接修改那个内存地址的内容,因为你无权访问)。
句柄值一般通过创建子进程时候的命令行参数传递,并在子进程解析出句柄值。
可以用SetHandleInformation() 和 GetHandleInformation() 两个函数来重设句柄的继承标志 或者 获取继承标志。
2 通过对象名称
创建内核对象的时候最后一个参数为PCTSTR类型,可以为内核对象指定一个名称,在其他进程创建同名对象时,会先去系统内核对象列表中寻找是否存在同名同类型内核对象,如果找到就不创建新内核对象,直接在进程的内核对象句柄表新建一个句柄,内存地址指向该内核对象。并将内核对象的使用计数递增。
也可以通过Open*(DWORD dwDesiredAccess, BOOL bInheritHandle, PCTSTR pszName)函数来寻找指定名称的内核对象,如果没有找到,则返回一个NULL值。
好处是共享内核对象的两个进程可以不是父子进程的关系
3 复制对象句柄
区别用户对象和内核对象的通用方法是,创建内核对象的时候有个PSECURITY_ATTRIBUTES类型的参数,该参数是一个指向 SECURITY_ATTRIBUTES 结构的指针,该结构描述了所创建的内核对象的安全性,比如是否可以被子进程继承。
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES;
内核对象是属于windows的,而不是属于进程的,但进程中有一个句柄表,引用了内核对象。
内核对象有一个使用计数,一个进程的内核对象句柄表中引用了某个内核对象,该内核对象的使用计数就递增1,该进程调用CloseHandle(hHandle)时,引用计数递减,当引用计数为0时,内核对象被销毁,当进程退出时,进程所有内核对象的引用计数都递减。
常见的内核对象:文件对象,文件映射对象,事件(event)对象,互斥量(mutex)对象,进程对象,线程对象。
创建一个内核对象时,返回一个句柄,该句柄在32位windows时为一个无符号32位整数,讲该整数右移两位就得到了句柄在进程的句柄表中的索引值。
下面是如何在进程间共享内核对象。
跨进程边界共享内核对象有三种方法: 对象句柄继承, 为对象命名, 复制对象句柄。
1 对象句柄继承:
SECURYTY_ATTRIBUTES中的第三个成员 bInheritHandle 指定了创建的内核对象是否可被子进程共享,如果指定为TRUE,CreateProcess创建子进程的时候,指定参数bInheritHandle为TRUE,那么该对象句柄就会被共享。 (此时子进程与父进程的内核对象句柄在两个进程的句柄表中的位置一摸一样,所以相同的句柄值,都能知道句柄表中的那条句柄记录,并指向相同的内存地址,那个内存地址保存了内核对象,当然你不能直接修改那个内存地址的内容,因为你无权访问)。
句柄值一般通过创建子进程时候的命令行参数传递,并在子进程解析出句柄值。
可以用SetHandleInformation() 和 GetHandleInformation() 两个函数来重设句柄的继承标志 或者 获取继承标志。
2 通过对象名称
创建内核对象的时候最后一个参数为PCTSTR类型,可以为内核对象指定一个名称,在其他进程创建同名对象时,会先去系统内核对象列表中寻找是否存在同名同类型内核对象,如果找到就不创建新内核对象,直接在进程的内核对象句柄表新建一个句柄,内存地址指向该内核对象。并将内核对象的使用计数递增。
也可以通过Open*(DWORD dwDesiredAccess, BOOL bInheritHandle, PCTSTR pszName)函数来寻找指定名称的内核对象,如果没有找到,则返回一个NULL值。
好处是共享内核对象的两个进程可以不是父子进程的关系
3 复制对象句柄