欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Windows学习(010)--内核对象(一)

程序员文章站 2022-06-03 18:19:09
...

内核对象概述

  • Windows操作系统分为Ring3和Ring0层
  • Ring3层是全开放的, 无监管的
  • Ring0层是有监管的
    • 是操作系统以及软件正在运行的地方
    • 在软件运行的时候, 我们正真的操作都是在Ring0发生的
    • 可通过WinAPI向Ring0层发送请求
    • 当Ring0层检测到这是一个合理的请求时,内核对象会被Ring0层进行改变
  • 通过句柄可以操作Ring0层指定的内核对象
    • 但是句柄不代表Ring0层的某个具体的内核对象
    • 句柄的值是不透明的, 无人知道它代表了什么意思
    • 句柄是属于当前进程的

使用计数

  • 每一个内核对象中, 都会有一个使用计数
  • 内核对象是属于操作系统的
  • 内核对象属于全局的,不同进程可以使用同一个内核对象
  • 但是进程不能决定任何一个内核对象的生死
  • 内核对象的生死却是由操作系统来决定

    • 当内核对象没有意义的时候, 操作系统会清理内核对象以节约资源
    • 但是Ring0和Ring3又无法交互
    • 所以使用计数出现了
    • 使用计数会在使用的时候+1, 在不使用的时候-1
    • 当使用计数为0时, 操作系统会对内核对象进行回收
    • 回收不是实时的, 是当系统空闲的时候, 优先来清理的
  • 使用计数使得内核对象可以被多个进程所拥有, 并且能正确的释放

句柄表以及句柄的本质

  • 先前也说过,我们可以通过句柄来操作内核对象,但句柄不代表内核对象本身,当一个句柄走出了一个进程,就毫无意义.
  • 句柄是属于进程的,它存在于进程的句柄表中.通常创建一个内核对象的情景是,先在ring0中创建了一个内核对象,然后在进程句柄表中,找一个空白的索引的位置创建一个句柄,然后由此句柄中一个指针指向这个内核对象

句柄表存在的意义

  • 在CloseHandle的时候,它会去进程的句柄表中找到索引对应的内核对象,找到后给内核对象发送一个使用计数递减的指令
  • 当我们进程中的句柄在进程将要结束时,未被Closehandle,这样就回造成内核对象泄露.此时,句柄表就有了作用,它会根据其中的值,挨个CloseHandle

Signal状态

  • 有Signal状态的内核对象
    • 进程内核对象
    • 线程内核对象
      • 进程和线程内核对象在初始化的时候, Signal为FALSE
      • 等到它们运行完成, Signal为TRUE
      • 进程和线程内核对象就进入可受信(可接受信号)状态
      • 进程和线程内核对象的Signal状态是系统来控制的
    • 标准输入输出流对象
    • 事件
    • 互斥体
    • 信号
    • 可等待计时器
    • 作业
  • Signal的两种状态
    • 可通知状态
    • 不可通知状态
    • 两种状态的改变可让系统来做,也可手动来做

WaitForSingleObject函数

  • 函数原型

    DWORD WINAPI WaitForSingleObject(
    _In_ HANDLE hHandle,
    _In_ DWORD dwMilliseconds
    );
  • 此函数是用来等待一个内核对象的Signal,如果等待的内核对象是可通知状态,此函数则立马返回,否则,则会阻塞dwMillisecond毫秒的时间,阻塞会导致当前线程变为不可调度
  • 返回值
    • WAIT_TIMEOUT 等待超时
    • WAIT_FAILED 等待失败, 需要调用GetLastError
    • WAIT_OBJECT_0 等待完成, 指定的对象变为有信号了
    • WAIT_ABANDONED 等待Mutex(互斥体)对象, 具体稍候了解

WaitForMultipleObjects函数

  • 函数原型

    DWORD WINAPI WaitForMultipleObjects(
      _In_       DWORD  nCount,
      _In_ const HANDLE *lpHandles,
      _In_       BOOL   bWaitAll,
      _In_       DWORD  dwMilliseconds
    );  
  • 此函数是用来等待多一组内核对象,对参数设置不同,功能不同,总体功能类似WaitForSingleObject

  • 参数
    • nCount等待个数
    • lpHandles等待数组的地址
    • bWaitAll是否全部等待,当此参数为FALSE时,它只会等待最先为可通知状态的内核对象,等到了立即返回
    • dwMilliseconds等待时间
  • 返回值
    • WAIT_OBJECT_0 到 WAIT_OBJECT_0 + nCount - 1也就是说, 返回值是一个范围
    • 最大的返回是 WAIT_OBJECT_0 + nCount - 1
      nCount是要等待的内核对象数量
    • WAIT_ABANDONED_0 到 WAIT_ABANDONED_0 + nCount - 1
      也是等待互斥体的, 稍候了解
    • WAIT_TIMEOUT 等待超时
    • WAIT_FAILED 等待失败, 需要调用GetLastError