句柄表和继承

句柄代表着备操作的对象

句柄的本质(handler)

句柄表可以看做一个非常大的结构体数组
句柄表的结构

索引值: 进程通过索引找到句柄表中对应的选项
内核对象地址: 通过地址直接找到对应的内核对象
访问掩码: 控制了访问权限
标志位: 标志改句柄能否被继承

句柄表是如何工作的:

每个进程的内核对象,都有一个句柄与之对应
操作对应进程,需要获得进程句柄。通过系统api操作

比如A要操作B进程
A会在A的句柄表中空白的位置存储B的内核地址,返回索引值 就是句柄
当操作B进程的时候 就使用句柄调用系统api操作B进程

类似于的 如果有C、D等进程和A进程一起操作B进程的话,这样一来 C.D自己的句柄表中都会存储B的内核对象地址。这么一来就带来一个问题
如果A C D 同时访问B的资源,突然间B的内核对象被销毁释放了,那么A C D三个都会出错

为了缓解此类错误,windows操作系统使用了内核对象使用计数机制:

内核对象的使用计数:

每一个内核对象都有一个使用计数的属性
每当内核对象被获得过一次,此内核对象的使用计数就会+1
当其他句柄中此内核对象的句柄销毁时,此内核对象并不会被销毁,而是使用计数-1
当内核对象的使用计数为0 的时候 就说明此时并没有其他地方再使用此内核对象了,此时内核对象就会被销毁

//销毁句柄 内核计数-1
BOOL CloseHandle
(
    HANDLE hObject //关闭的目标句柄
)

句柄的继承关系

当父进程创建子进程的时候,父进程标志位为0的,表示此条索引(句柄)不想被子进程继承

BOOL CreateProcess(
  LPCTSTR lpApplicationName,                // 路径
  LPTSTR lpCommandLine,                      // 命令行
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程安全属性
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 线程安全属性
  BOOL bInheritHandles,                        // 继承标志位
  DWORD dwCreationFlags,                    // 创建标志
  LPVOID lpEnvironment,                        // 环境块
  LPCTSTR lpCurrentDirectory,                // 驱动目录
  LPSTARTUPINFO lpStartupInfo,            // 启动信息
  LPPROCESS_INFORMATION lpProcessInformation // 进程信息
);

进程标志位参数 BOOL bInheritHandles
表示了新进程(子进程)是否继承父进程句柄表中的句柄,如果为true,那么就继承父句柄表中可被继承的句柄,并且继承的句柄具有和原始句柄相同的值和访问权限

进程安全属性和线程安全属性 参数,决定是否可以由子进程(线程)继承返回的句柄。如果是NULL 则表示不能被继承

//安全属性
SECURITY_ATTRIBUTE
{
    DWORD  nLength;  //结构体宽度
    LPVOID lpSecurityDescriptor;//安全描述符
    BOOL   bInheritHandle;//被创建的句柄能否被继承
}
//安全描述符:决定了用户的访问权限,可以由他指定哪些用  户可以访问,以及一些访问权限,一般填NULL
//句柄继承选项:决定了被创建的对象的句柄是否是可以被继  承的