参考:《Windows内核情景分析》

0x01  ObReferenceObjectByHandle

  这个函数从句柄得到对应的内核对象,并递增其引用计数。

  1. NTSTATUS
  2. ObReferenceObjectByHandle(
  3. IN HANDLE Handle,
  4. IN ACCESS_MASK DesiredAccess,
  5. IN POBJECT_TYPE ObjectType,IN
  6. KPROCESSOR_MODE AccessMode,
  7. OUT PVOID* Object,
  8. OUT POBJECT_HANDLE_INFORMATION
  9. HandleInformation)
  10. {
  11. *Object = NULL;
  12. //若句柄是一个内核句柄或当前进程、线程的句柄
  13. if (HandleToLong(Handle) < 0)
  14. {
  15. if (Handle == NtCurrentProcess())//若句柄值是当前进程的句柄(-1),特殊处理
  16. {
  17. if ((ObjectType == PsProcessType) || !(ObjectType))
  18. {
  19. CurrentProcess = PsGetCurrentProcess();
  20. GrantedAccess = CurrentProcess->GrantedAccess;
  21. //if内核模式/要求的权限<=进程对象支持的权限(权限检查)
  22. if ((AccessMode == KernelMode) ||!(~GrantedAccess & DesiredAccess))
  23. {
  24. if (HandleInformation)
  25. {
  26. HandleInformation->HandleAttributes = 0;
  27. HandleInformation->GrantedAccess = GrantedAccess;
  28. }
  29.  
  30. ObjectHeader = OBJECT_TO_OBJECT_HEADER(CurrentProcess);
  31. InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);//递增引用计数
  32. *Object = CurrentProcess;//返回得到的对象指针
  33. Status = STATUS_SUCCESS;
  34. }
  35. Else //权限检查不通过
  36. Status = STATUS_ACCESS_DENIED;
  37. }
  38. else
  39. Status = STATUS_OBJECT_TYPE_MISMATCH;
  40. return Status;
  41. }
  42. else if (Handle == NtCurrentThread())//若句柄值是当前线程的句柄(-2),特殊处理
  43. {
  44. if ((ObjectType == PsThreadType) || !(ObjectType))
  45. {
  46. CurrentThread = PsGetCurrentThread();
  47. GrantedAccess = CurrentThread->GrantedAccess;
  48. if ((AccessMode == KernelMode) ||!(~GrantedAccess & DesiredAccess))
  49. {
  50. if (HandleInformation)
  51. {
  52. HandleInformation->HandleAttributes = 0;
  53. HandleInformation->GrantedAccess = GrantedAccess;
  54. }
  55. ObjectHeader = OBJECT_TO_OBJECT_HEADER(CurrentThread);
  56. InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
  57. *Object = CurrentThread;
  58. Status = STATUS_SUCCESS;
  59. }
  60. else
  61. Status = STATUS_ACCESS_DENIED;
  62. }
  63. else
  64. Status = STATUS_OBJECT_TYPE_MISMATCH;
  65. return Status;
  66. }
  67. else if (AccessMode == KernelMode)//若句柄是一个内核句柄
  68. {
  69. Handle = ObKernelHandleToHandle(Handle);//去掉最高位的1,转为普通句柄
  70. HandleTable = ObpKernelHandleTable;//采用内核句柄表
  71. }
  72. }
  73. Else //最典型的情况,普通句柄,就使用当前进程的句柄表
  74. HandleTable = PsGetCurrentProcess()->ObjectTable;
  75. //以该句柄的值为“索引”,找到句柄表中对应的句柄表项
  76. HandleEntry = ExMapHandleToPointer(HandleTable, Handle)
  77. if (HandleEntry)//如果找到了,这就是一个有效句柄
  78. {
  79. ObjectHeader = ObpGetHandleObject(HandleEntry);//关键。获得该句柄指向的对应对象
  80. if (!(ObjectType) || (ObjectType == ObjectHeader->Type))
  81. {
  82. GrantedAccess = HandleEntry->GrantedAccess;
  83. if ((AccessMode == KernelMode) ||!(~GrantedAccess & DesiredAccess))//通过权限检查
  84. {
  85. InterlockedIncrement(&ObjectHeader->PointerCount);
  86. Attributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
  87. if (HandleInformation)
  88. {
  89. HandleInformation->HandleAttributes = Attributes;
  90. HandleInformation->GrantedAccess = GrantedAccess;
  91. }
  92. *Object = &ObjectHeader->Body;//返回的是对象体的地址
  93. return STATUS_SUCCESS;
  94. }
  95. Else //权限检查没通过
  96. Status = STATUS_ACCESS_DENIED;
  97. }
  98. else
  99. Status = STATUS_OBJECT_TYPE_MISMATCH;
  100. }
  101. Else //有可能用户给定的句柄值是一个无效句柄,在句柄表中找不到
  102. Status = STATUS_INVALID_HANDLE;
  103. *Object = NULL;
  104. return Status;
  105. }

  

两个特殊情况:

#define NtCurrentProcess()   (HANDLE)-1

#define NtCurrentThread()   (HANDLE)-2

这是两个伪句柄值,永远获得的是当前进程、线程的内核对象。

另外:若句柄值的最高位是1,则是一个内核句柄,各进程通用。内核型句柄是“System”进程的句柄表中的句柄。因此,要获得内核句柄对应的对象,系统会挂靠到“System”进程的地址空间中,去查询句柄表。

根据句柄值在句柄表中找到对应的表项是靠ExMamHandleToPointer这个函数实现的,这个函数又在内部调用ExpLookupHandleTableEntry来真正查找。句柄表组织为一个稀疏数组(目的用来节省内存),但可以

简单的看做一个一维数组,不影响理解,句柄值本身也可简单理解为一个索引。

调用方传递给驱动程序的句柄不会经过 I/O 管理器,因此 I/O 管理器不对这类句柄执行任何验证检查。决不要假设一个句柄有效;始终确保句柄拥有正确的对象类型、对于所需任务的合适的访问权、正确的访问模式,并且访问模式与请求的访问兼容。

  驱动程序应该谨慎使用句柄,特别是那些从用户模式应用程序接收到的句柄。
  第一,这种句柄特定于进程上下文,因此它们仅在打开句柄的进程中有效。当从不同的进程上下文或工作线程使用时,句柄可以引用不同的对象或者只是变得无效。
  第二,在驱动程序使用句柄期间,攻击者可以关闭和重新打开句柄来改变其引用的内容。
  第三,攻击者可以传入这样一个句柄来引诱驱动程序执行对于应用程序非法的操作,例如调用 ZwXxx 函数。对于这些函数的内核模式调用方,访问检查被跳过,因此攻击者可以使用这种机制绕过验证。

  驱动程序还应该确保用户模式应用程序不能误用驱动程序创建的句柄。为一个句柄设置 OBJ_KERNEL_HANDLE 属性使其成为内核句柄,内核句柄可以在任何进程上下文中使用,但是只能从内核模式进行访问(对于传递给ZwXxx 例程的句柄,这特别重要)。用户模式的进程不能访问、关闭或替换内核句柄。

几个常用内核函数(《Windows内核情景分析》)的更多相关文章

  1. Linux 内核和 Windows 内核有什么区别?

    Windows 和 Linux 可以说是我们比较常见的两款操作系统的. Windows 基本占领了电脑时代的市场,商业上取得了很大成就,但是它并不开源,所以要想接触源码得加入 Windows 的开发团 ...

  2. Windows内核原理系列01 - 基本概念

    1.Windows API Windows 应用编程接口(API)是针对WIndwos操作系统用户模式的系统编程接口,包含在WindwosSDK中. 2.关于.NET .NET由一个被称为FCL的类库 ...

  3. windows内核基础与异常处理

    前两日碰到了用异常处理来做加密的re题目 所以系统学习一下windows内核相关 windows内核基础 权限级别 内核层:R0 零环 核心态工作区域 大多数驱动程序 应用层:R3 用户态工作区域 只 ...

  4. windows内核情景分析之—— KeRaiseIrql函数与KeLowerIrql()函数

    windows内核情景分析之—— KeRaiseIrql函数与KeLowerIrql()函数 1.KeRaiseIrql函数 这个 KeRaiseIrql() 只是简单地调用 hal 模块的 KfRa ...

  5. windows内核编程之常用数据结构

    1.返回状态 绝大部分的内核api返回值都是一个返回状态,也就是一个错误代码.这个类型为NTSTATUS.我们自己写的函数也大部分这样做. NTSTATUS MyFunction() { NTSTAT ...

  6. [4]Windows内核情景分析---内核对象

    写过Windows应用程序的朋友都常常听说"内核对象"."句柄"等术语却无从得知他们的内核实现到底是怎样的, 本篇文章就揭开这些技术的神秘面纱. 常见的内核对象 ...

  7. [1]windows 内核情景分析---说明

    本文说明:这一系列文章(笔记)是在看雪里面下载word文档,现转帖出来,希望更多的人能看到并分享,感谢原作者的分享精神. 说明 本文结合<Windows内核情景分析>(毛德操著).< ...

  8. Windows内核-7-IRP和派遣函数

    Windows内核-7-IRP和派遣函数 IRP以及派遣函数是Windows中非常重要的概念.IRP 是I/O Request Pocket的简称,意思是I/O操作的请求包,Windows中所有Use ...

  9. Windows 驱动发展基金会(九)内核函数

    Windows 驱动发展基金会系列,转载请注明出处:http://blog.csdn.net/ikerpeng/article/details/38849861 这里主要介绍3类Windows的内核函 ...

随机推荐

  1. Java后台判断是否是ajax请求,并进行处理

    Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求 >>>>>>>>>>>>>>&g ...

  2. HDU 1560 DNA sequence(DNA序列)

    HDU 1560 DNA sequence(DNA序列) Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K  ...

  3. 使用SpringMVC框架实现文件上传和下载功能

    使用SpringMVC框架实现文件上传和下载功能 (一)单个文件上传 ①配置文件上传解释器 <!—配置文件上传解释器 --> <mvc:annotation-driven>&l ...

  4. Linux操作系统的VI命令

    Linux操作系统的VI命令 VI是Linux系统的一个文本编辑器,该编辑器可以通过使用VI命令来操作,从而完成对文本的编辑.熟练掌握一些常用的VI命令,可以大大简化编辑操作并提高操作Linux文本的 ...

  5. 解决idea的.gitignore有时不起作用的问题

    有时候,.gitignore会对部分文件/文件夹失效,大概原因是由于新创建的文件已经出现在git本地仓库的缓存,所以.gitignore就失效了 解决办法就是清空一下git仓库的缓存,重新提交一次就好 ...

  6. heartbeat 非联网安装(通过配置本地yum文件库安装heartbeat)

    软件环境:centos6.5 一.下载rpm包 首先找一台联网的centos6.5机器 安装epel扩展源: yum install -y epel-release 安装yum-plugin-down ...

  7. C#socket编程之实现一个简单的TCP通信

    TCP(TransmissionControl Protocol)传输控制协议. 是一种可靠的.面向连接的协议(eg:打电话).传输效率低全双工通信(发送缓存&接收缓存).面向字节流.使用TC ...

  8. Android studio 使用startService报错:IllegalStateException

    Android 8.0启动service报错:java.lang.RuntimeException和java.lang.IllegalStateException 错误信息: java.lang.Ru ...

  9. Hibernate实例——Customer表的展示

    Hibernate.cfg.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibe ...

  10. java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details

    Caused by: java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Except ...