Windows句柄表学习笔记 —— 句柄表&全局句柄表

  • 句柄表
    • 实验一:在WinDbg中查看句柄表
      • 第一步:打开一个Win32窗口程序
      • 第二步:编译并运行以下代码
      • 第三步:查看运行结果
      • 第四步:在WinDbg中定位句柄表
    • 句柄表结构
    • 实验二:在WinDbg中查看并分析句柄表结构
      • 第一步:打开一个Win32窗口程序
      • 第二步:编译以下代码并运行
      • 第三步:查看运行结果
      • 第四步:在WinDbg中定位最后一个句柄
      • 第五步:通过句柄定位内核对象
  • 全局句柄表
    • 全局句柄表结构
    • 实验:在WinDbg中观察全局句柄表
      • 第一步:打开一个Win32窗口程序
      • 第二步:获得进程PID
      • 第三步:获得全局句柄表
      • 第四步:查看_EPROCESS结构体

句柄表

描述

  1. 当一个进程创建或者打开一个内核对象时,将获得一个句柄,通过这个句柄可以访问对应的内核对象
  2. 句柄表存储在零环,一个进程使用了几个句柄,在该进程的句柄表中就会存储几个句柄
  3. 所有的句柄所对应的内核对象,都包含在 _OBJECT_HEADER 中,真正的内核对象保存在 _OBJECT_HEADER +0x018 body 的位置

例如

HANDLE g_hMutex = ::CreateMutex(NULL,FALSE, "XYZ");
HANDLE g_hMutex = ::OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");
HANDLE g_hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
HANDLE g_hThread = ::CreateThread(NULL, 0, Proc, NULL, 0, NULL);

思考:为什么微软不直接把内核对象的地址返回给用户,而是通过句柄的形式
答案:句柄存在的目的是为了避免在应用层直接修改内核对象,如果直接返回内核对象的地址,那么就意味着我们可以在应用层修改这个地址,一旦指向了无效的内核内存地址就会蓝屏

注意

  1. 窗口字体笔刷等句柄与本章所学句柄是两码事
  2. 创建句柄不等同于打开句柄,当创建的时候,操作系统会在零环为内核对象分配一个结构体(例如CreateEvent),如果自己或他人打开了这个内核对象(例如OpenProcess),那么将不会再次为这个内核对象分配一个结构体,而是返回一个句柄的索引值
  3. 若同一个内核对象被引用了100次,那么在句柄表中就会存储100个内核对象的地址
  4. 句柄的值并非如上图所显示的只占4个字节,而是占8个字节,但是句柄表的值仍然按照4个字节进行计算

句柄索引定位对应句柄的计算公式handle = index / 4 * 8

实验一:在WinDbg中查看句柄表

第一步:打开一个Win32窗口程序

本实验选择进程为计算器(calc.exe)

第二步:编译并运行以下代码

#include <stdio.h>
#include <windows.h>int main()
{DWORD PID;HANDLE hPro = NULL;HWND hWnd = ::FindWindow(NULL, "计算器");::GetWindowThreadProcessId(hWnd, &PID);for(int i=0; i<100 ;i++){hPro = ::OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, TRUE, PID);printf("句柄:%x\n", hPro);}getchar();return 0;
}

第三步:查看运行结果

第四步:在WinDbg中定位句柄表

kd> !process 0 0

kd> dt _EPROCESS 862adda0

kd> dt _HANDLE_TABLE 0xe12ca370

kd> dd 0xe1b6f000


第一个句柄地址 = 0xe1b6f000 + 0x7cc / 4 * 8 = 0xe1b6ff98

kd> dq 0xe1b6ff98

句柄表结构


1:共两个字节,低字节保留恒为0,高位字节是给SetHandleInformation这个函数用的,比如写成SethandleInformation(Handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE),那么这个位置将被写入0x02HANDLE_FLAG_PROTECT_FROM_CLOSE宏的值为0x00000002,取最低字节,最终这块是0x0200

2:这块是访问掩码,是给OpenProess这个函数用的
OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId)具体存的就是这个函数第一个参数的值

3&4:共4个字节,其中bit0bit2存储句柄的属性,默认为0,bit1表示该句柄是否可继承(参考OpenProcess的第二个参数)

实验二:在WinDbg中查看并分析句柄表结构

第一步:打开一个Win32窗口程序

本实验选择进程为计算器(calc.exe)

第二步:编译以下代码并运行

#include <stdio.h>
#include <windows.h>int main()
{DWORD PID;HANDLE hPro = NULL;HWND hWnd = ::FindWindow(NULL, "计算器");::GetWindowThreadProcessId(hWnd, &PID);for(int i=0; i<100 ;i++){hPro = ::OpenProcess(PROCESS_CREATE_THREAD, TRUE, PID);printf("句柄:%x\n", hPro);}//HANDLE_FLAG_PROTECT_FROM_CLOSE:句柄不可用CloseHandle关闭SetHandleInformation(hPro, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);getchar();return 0;
}

第三步:查看运行结果

第四步:在WinDbg中定位最后一个句柄

定位过程参考实验一

第五步:通过句柄定位内核对象

句柄值0200003a 8617c7e3
清理后三位bit,后四个字节为地址: 8617c7e0
注意:此时该地址指向 _OBJECT_HEADER ,若想查看真正的内核对象结构体还要加上0x18
实验中我们使用OpenProcess打开句柄,因此查看_EPROCESS结构体

kd> dt _EPROCESS 8617c7e0 + 0x18

全局句柄表

描述

  1. 进程的句柄表是私有的,每个进程都有一个自己的句柄表
  2. 除此之外,系统还有一个全局句柄表:PsdCidTable,为 _HANDLE_TABLE 结构,所有的进程和线程无论无论是否打开,都在这个表中
  3. 每个进程和线程都有一个唯一的编号:PIDCID 这两个值其实就是全局句柄表中的索引
  4. 进程和线程的查询,主要是以下三个函数,按照给定的PIDCIDPspCidTable从查找相应的进线程对象:

    PsLookupProcessThreadByCid()
    PsLookupProcessByProcessId()
    PsLookupThreadByThreadId()

全局句柄表结构

描述:

  1. 若TableCode的值为0,说明handle_max = 4KB / 8 = 512,此时,句柄表为一级句柄表
  2. 若打开句柄数量超过512个,TableCode的值就会置为1,此时,句柄表变为两级句柄表。第一级句柄表中每个成员存储着第二级句柄表的地址,第二级句柄表中才真正存储着内核对象的地址,handle_max = 1024 * 512
  3. 若打开句柄数量超过1024 * 512个,TableCode的值就会置为3,此时,句柄表变为三级句柄表,第一级为地址,第二级也为地址,第三级才是句柄,handle_max = 1024 * 1024 * 512

实验:在WinDbg中观察全局句柄表

第一步:打开一个Win32窗口程序

本实验选择进程为计算器(calc.exe)

第二步:获得进程PID


index = 1048 / 4 = 0x106

第三步:获得全局句柄表

kd> dd PspCidTable

kd> dt _HANDLE_TABLE e1003c58

第四步:查看_EPROCESS结构体

kd> dq e1005000 + 0x106*8

kd> dt _EPROCESS 85e2d540 //后三位属性位清零

Windows句柄表学习笔记 —— 句柄表全局句柄表相关推荐

  1. Windows保护模式学习笔记(一)—— 段寄存器GDT表

    Windows保护模式学习笔记(一)-- 段寄存器&GDT表 保护模式 参考书籍: 一.段寄存器 段寄存器的结构 段寄存器的读写 段寄存器的属性 1)探测Attribute: 2)探测Base ...

  2. Windows系统调用学习笔记(四)—— 系统服务表SSDT

    Windows系统调用学习笔记(四)-- 系统服务表&SSDT 要点回顾 系统服务表 实验:分析 KiSystemService 与 KiFastCallEntry 共同代码 SSDT 实验: ...

  3. Windows保护模式学习笔记(八)—— 页目录表基址/页表基址

    Windows保护模式学习笔记(八)-- 页目录表基址/页表基址 要点回顾 一.页目录表基址 实验:拆分线性地址C0300000,并查看其对应的物理页 第一步:打开一个进程,获得它的Cr3 第二步:查 ...

  4. oracle查看表空间的内容,学习笔记:Oracle查看object对象 表空间 表 索引 数据文件的使用空间...

    天萃荷净 运维DBA咨询想要查看Oracle的object对象的使用空间大小,包括表空间 表 索引 数据文件的使用空间 1.查看Oracle表空间大小 Select Tablespace_Name,S ...

  5. MySQL学习笔记-约束以及修改数据表

    MySQL学习笔记-约束以及修改数据表 约束: 按功能划为: NOT NULL , PRIMARY KEY , UNIQUE KEY , DEFAULT , FOREIGN KEY 按数据列的数目划为 ...

  6. Windows消息机制学习笔记(二)—— 窗口与线程

    Windows消息机制学习笔记(二)-- 窗口与线程 要点回顾 消息从哪里来? 实验一:Spy++捕获消息 实验二:消息捕获 消息到哪里去? 窗口在哪? 实验:分析CreateWindowExW 窗口 ...

  7. Windows消息机制学习笔记(三)—— 消息的接收与分发

    Windows消息机制学习笔记(三)-- 消息的接收与分发 要点回顾 消息循环 消息队列 消息的接收 GetMessage 实验1:理解GetMessage 第一步:编译并运行程序A 第二步:编译并运 ...

  8. Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析

    Windows事件等待学习笔记(三)-- WaitForSingleObject函数分析 要点回顾 WaitForSingleObject NtWaitForSingleObject KeWaitFo ...

  9. Windows保护模式学习笔记(十)—— TLB

    Windows保护模式学习笔记(十)-- TLB 地址解析 10-10-12分页 2-9-9-12分页 TLB TLB结构 TLB种类 练习1:体验TLB的存在 第一步:运行代码 第二步:设置中断门描 ...

最新文章

  1. 腾讯十周年,看看你的QQ是什么时候注册的?
  2. MariaDB 加密特性及使用方法
  3. 【labelme】改造labelme
  4. [Jobdu] 题目1499:项目安排
  5. python菱形画法解释_用Python画棱形
  6. 想让马云成为你的老大?揭秘阿里面试情景
  7. 15 MM配置-BP业务伙伴-定义供应商主记录的编号范围
  8. vscode创建代码截图_如何在VSCode中创建代码配置文件
  9. 如何判断一个大佬值不值得跟随
  10. python画图颜色代码rgb_python – matplotlib 3D散点图,其标记颜色对应于RGB值
  11. python判断变量相等_Python判断两个对象相等的原理
  12. 请简要概括linux与windows在文件系统方面存在的不同点,简要回答下列与网络操作系统、网络安全和数据存储相关的问题,将解答填入答题纸对应栏内。br 【问题1】(10分)br (a)Win...
  13. Vue中导出Excel
  14. Qt入门教程【高级控件篇】QTreeView树形视图
  15. 抖音怎么投放广告,抖音广告投放效果
  16. 用python自动制作ppt——第三讲——插入文本框
  17. 工具说明书 - FTDI芯片的USB转UART串口线
  18. 川大 计算机学院 惠子,“挑战杯”四川大学2013年学生科技节之“纺兴未艾,织行天下”废物循环利用大赛决赛圆满落幕...
  19. Python爬取网易云音乐评论,反爬算啥啊!
  20. python爬虫win10程序_Python爬虫教程:批量提取Win10锁屏壁纸

热门文章

  1. Appendix之setup.py:附录文件内容记录setup.py
  2. Py之pyquery:pyquery的简介、安装、使用方法之详细攻略
  3. ML与math:机器学习与高等数学基础概念、代码实现、案例应用之详细攻略——基础篇
  4. pyhanlp 分词与词性标注
  5. php 数组元素快速去重
  6. cdh5.13.1 升/降级SPARK2 (parcel安装的同理)
  7. 【UVA 437】The Tower of Babylon(记忆化搜索写法)
  8. Java实现找出数组中重复次数最多的元素以及个数
  9. 砝码问题之一(回头发现貌似多重背包)
  10. __declspec(dllexport)的作用