1、内核对象概念
内核对象
- 属于系统内核创建的对象,例如符号对象、事件对象、文件对象、文件映射对象、I / O完成端口对象、作业对象、信箱对象、互斥对象、管道对象、进程对象、信标对象、线程对象和等待计时器对象等.
用户对象或图形设备接口(GDI)对象
- 如如菜单、窗口、鼠标光标、刷子和字体等
区分
- 用于创建用户对象或GDI对象的函数都没有PSECURITY_ATTRIBUTES参数(内核对象有)
2、进程和内核对象的关系
- 内核对象是公用的,使用引用计数的方式来决定何时销毁,有可能内核对象的生命周期比进程的生命周期长
- 句柄表是进程用来管理内核的表,表里面每一项的值对应一个内核对象的信息
- 创建内核对象返回的handle对应句柄表中的索引,通过索引可以拿到内核对象在内存块中的指针
2.1、创建内核对象
CreateFileMapping,CreateFIle,CreateThread等方法创建
2.2、关闭内核对象
- 调用CloseHandle函数时将对应句柄表里面对应的内存块中的索引-1,如果索引为0,内核便撤销此对象,同时清空对应的句柄表里面的内容。
- 如果未调用CloseHandle函数有可能会资源泄露,在进程运行时泄露,进程终止时操作系统会扫描进程对应的句柄表,关闭对应对象句柄。
3、内核对象共享(进程通信?)
许多情况下,在不同进程中运行的线程需要共享内核对象。下面是为何需要共享的原因:
• 文件映射对象使你能够在同一台机器上运行的两个进程之间共享数据块。
• 邮箱和指定的管道使得应用程序能够在连网的不同机器上运行的进程之间发送数据块。
• 互斥对象、信标和事件使得不同进程中的线程能够同步它们的连续运行,这与一个应用程序在完成某项任务时需要将情况通知另一个应用程序的情况相同。
3.1、对象句柄的继承性
用于父子进程之间,父进程创建时在安全属性里面指定内核对象句柄可继承,例如:
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; //使返回的句柄可继承
HANDLE hMutex = CreateMutex(&sa, FALSE, NULL);
- hMutex是使用sa参数创建的,它在句柄表中对应的标志位变为1(默认是0)。
- 在调用CreateProcess创建子进程时会先检查父进程中句柄表中各个队形的标志位,如果标志位为1,则将此条记录拷贝到子进程的句柄表中,并且与在父进程中句柄表中的位置一样(如果在父进程中是第三条,在子进程中也是第三条,前面两条为空),确保在父子进程中该对象所用的句柄值是相同的。
- 此时内核对象的引用计数同样会递增。
此时只需要将父进程中的内核对象句柄传递给子进程(例如在创建时通过命令行传递),子进程即可访问它。
注:对象句柄的继承性只有在生成子进程的时候才能使用。如果父进程准备创建带有可继承句柄的新内核对象,那么已经在运行的子进程将无法继承这些新句柄。
3.2命名对象
创建对象时将pszName给一个特定的名字,该名字在内核中是唯一的。
HANDLE CreateMutex(
PSECURITY_ATTRIBUTES psa,
BOOL bInitialOwner,
PCTSTR pszName);
其他进程可以通过对应的open函数指定名称访问此内核对象。
命名对象常常用来防止运行一个应用程序的多个实例。若要做到这一点,只需要调用main或
WinMain函数中Create函数,以便创建一个命名对象(创建的是什么对象则是无所谓的)。当Create 函 数 返 回 时 , 调 用GetLastError 函 数 。 如 果GetLastError函 数 返 回RROR_ALREADY_EXIST,那么你的应用程序的另一个实例正在运行,新实例可以退出。
3.3、复制对象句柄
BOOL WINAPI DuplicateHandle(
__in HANDLE hSourceProcessHandle,
__in HANDLE hSourceHandle,
__in HANDLE hTargetProcessHandle,
__out LPHANDLE lpTargetHandle,
__in DWORD dwDesiredAccess,
__in BOOL bInheritHandle,
__in DWORD dwOptions
)