Windows系统调用学习笔记(四)—— 系统服务表SSDT
Windows系统调用学习笔记(四)—— 系统服务表&SSDT
- 要点回顾
- 系统服务表
- 实验:分析 KiSystemService 与 KiFastCallEntry 共同代码
- SSDT
- 实验:在SSDT中查找内核函数信息
- 第一步:查看函数地址
- 第二步:查看参数个数
- 第三步:查看内核函数反汇编
- 练习
要点回顾
API进入0环后调用的函数:
- 中断门 – KiSystemService
- 快速调用 – KiFastCallEntry
上一篇留了几个练习:
- 进0环后,原来的寄存器存在哪里?
- 如何根据系统服务号(eax中存储)找到要执行的内核函数?
- 调用时参数是存储到3环的堆栈,如何传递给内核函数?
- 两种调用方式是如何返回到3环的?
本篇将对第二个和第三个练习进行说明
系统服务表
描述:
- 系统服务表:System Service Table
- 系统服务表共有两张,第一张表后紧接第二张表
- 系统服务表里的函数都是来自内核文件导出的函数
- 它并不包含内核文件导出的所有函数,而是3环最常用的内核函数
- 系统服务表位于 _KTHREAD +00xE0
结构体:
typedef struct _SERVICE_DESCRIPTOR_TABLE
{PULONG ServiceTableBase; // 指针,指向函数地址,每个成员占4字节PULONG ServiceCounterTableBase; // 当前系统服务表被调用的次数ULONG NumberOfService; // 服务函数的总数PUCHAR ParamTableBase; // 服务函数的参数总长度,以字节为单位,每个成员占一个字节// 如:服务函数有两个参数,每个参数占四字节,那么对应参数总长度为8// 函数地址成员 与 参数总长度成员 一一对应
} SSDTEntry, *PSSDTEntry;
结构图:
实验:分析 KiSystemService 与 KiFastCallEntry 共同代码
IDA反汇编:
.text:00406932 loc_406932: ; CODE XREF: _KiBBTUnexpectedRange+18↑j
.text:00406932 ; _KiSystemService+71↑j
.text:00406932 mov edi, eax ; 从 eax 寄存器中取出3环传进来的系统调用号
.text:00406934 shr edi, 8 ; 系统调用号右移8位
.text:00406937 and edi, 30h ; 右移后的值和0x30进行与运算; 目的是检测第12位是否为1; WindowsNT基本的(Native)系统调用有两百多个,编号都小于0x1000; 编号大于0x1000的系统调用号是微软扩展出来的; 这些扩展出的系统调用位于动态安装的模块中,即win32k.sys; 若第12位为0x00,则将低12位作为下标在 ntoskrl.exe 中寻找对应的系统调用; 若第12位为0x10,则将低12位作为下标在 win32k.sys 中寻找对应的系统调用
.text:0040693A mov ecx, edi ; 将运算结果赋值给 ecx
.text:0040693C add edi, [esi+0E0h] ; 将系统服务表的指针赋值给 edi; nt!_KTHREAD; +0x0e0 ServiceTable : Ptr32 Void; 这里将系统服务表所在地址直接加上edi的运算结果; 巧妙地得到要查哪张表(两张表是连续的),每张表占16字节
.text:00406942 mov ebx, eax ; 将系统调用号赋值给 ebx
.text:00406944 and eax, 0FFFh ; 将系统调用号与 0xFFF进行与运算; 目的是保留低12位,作为函数地址的下标
.text:00406949 cmp eax, [edi+8] ; typedef struct _SYSTEM_SERVICE_TABLE; {; PVOID ServiceTableBase; //这个指向系统服务函数地址表; PULONG ServiceCounterTableBase;; ULONG NumberOfService; //服务函数总数; ULONG ParamTableBase; //参数总长度; }SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE;;; +8 是服务函数的个数
.text:0040694C jnb _KiBBTUnexpectedRange ; 若大于系统调用号的个数则跳转,即系统调用号越界
.text:00406952 cmp ecx, 10h ; 将 ecx 与0x10进行比较; ecx 保存的是 edi 与0x30与运算后的结果,只能是0x00货0x10
.text:00406955 jnz short loc_406972 ; 若系统调用号小于0x1000,则跳转
.text:00406957 mov ecx, large fs:18h ; 只有当ecx == 0x10才会向下执行; 作用是动态加载GUI等图形相关函数
.text:0040695E xor ebx, ebx
.text:00406960
.text:00406960 loc_406960:
.text:00406960 or ebx, [ecx+0F70h]
.text:00406966 jz short loc_406972
.text:00406968 push edx
.text:00406969 push eax
.text:0040696A call ds:_KeGdiFlushUserBatch
.text:00406970 pop eax
.text:00406971 pop edx
.text:00406972
.text:00406972 loc_406972: ; CODE XREF: _KiFastCallEntry+B6↑j
.text:00406972 ; KiSystemServiceAccessTeb()+6↑j
.text:00406972 inc large dword ptr fs:638h ; _KPRCB -> +0x518 KeSystemCalls 增加1
.text:00406979 mov esi, edx ; edx保存的是3环参数的指针
.text:0040697B mov ebx, [edi+0Ch] ; edi指向要使用的系统服务表; +0Ch是ParamTableBase(参数表指针)
.text:0040697E xor ecx, ecx ;ecx清零
.text:00406980 mov cl, [eax+ebx] ; eax保存的是3环传入的系统调用号; ebx保存的是是参数表指针; 这条指令的目的是得到内核函数的参数总长度,存入cl
.text:00406983 mov edi, [edi] ; 取出系统调用表的第一个成员(函数地址指针)
.text:00406985 mov ebx, [edi+eax*4] ; 函数地址指针 + 系统调用号*4(乘4是因为每个成员占4字节); 目的是找到函数地址,存入ebx
.text:00406988 sub esp, ecx ; 提升堆栈,大小为参数总长度
.text:0040698A shr ecx, 2 ; 参数总长度/4 = 参数个数
.text:0040698D mov edi, esp ; 设置要COPY的目的地
.text:0040698F test byte ptr [ebp+72h], 2
.text:00406993 jnz short loc_40699B
.text:00406995 test byte ptr [ebp+6Ch], 1
.text:00406999 jz loc_4069A7
.text:0040699B
.text:0040699B loc_40699B: ; CODE XREF: KiSystemServiceAccessTeb()+33↑j
.text:0040699B cmp esi, ds:_MmUserProbeAddress ; 全局变量存储用户能访问的最大范围; 这条指令的作用是判断3环参数是否越界
.text:004069A1 jnb loc_406B4F ; 越界则跳转至异常处理
.text:004069A7
.text:004069A7 loc_4069A7:
.text:004069A7 rep movsd ; 将3环参数复制到0环堆栈
.text:004069A9 call ebx ; 调用函数
SSDT
描述:
- 全称:System Services Descriptor Table(系统服务描述符表)
- SSDT的每个成员叫做系统服务表
- SSDT的第一个成员是导出的,声明一下即可使用
- SSDT的第二个成员是未导出的,需要通过其它方式查找
- 在Windows中,SSDT的第三个成员和第四个成员未被使用
在WinDbg中查看已导出成员:
kd>dd KeServiceDescriptorTable
在WinDbg中查看未导出成员:
实验:在SSDT中查找内核函数信息
实验说明
- 在之前的实验中,我们通过分析三环的ReadProcessMemory函数,一步步了解三环函数是如何进入内核的
- 当ReadProcessMemory即将进入内核时,传递了一个系统服务号,为0BAh
- 本次实验查找编号 0BAh 在 SSDT 表中的相关信息
第一步:查看函数地址
函数地址表:
[函数地址表 + 系统服务号*4] = 内核函数地址
第二步:查看参数个数
参数表:
[参数表 + 系统服务号] = 内核函数参数个数(单位:字节)
第三步:查看内核函数反汇编
练习
要求:在SSDT表中追加一个函数地址(NtReadVirtualMemory),自己编写API的3环部分调用这个新增的函数(注意:使用2-9-9-12分页)。
答案:略(待补充)
Windows系统调用学习笔记(四)—— 系统服务表SSDT相关推荐
- Windows系统调用学习笔记(三)—— 保存现场
Windows系统调用学习笔记(三)-- 保存现场 要点回顾 基本概念 Trap Frame 结构 线程相关的结构体 ETHREAD KTHREAD CPU相关的结构体 KPCR _NT_TIB KP ...
- Windows系统调用学习笔记(二)—— 3环进0环
Windows系统调用学习笔记(二)-- 3环进0环 要点回顾 基本概念 _KUSER_SHARED_DATA 0x7FFE0300 实验:判断CPU是否支持快速调用 第一步:修改EAX=1 第二步: ...
- Windows系统调用学习笔记(一)—— API函数调用过程
Windows系统调用学习笔记(一)-- API函数调用过程 Windows API 实验1:分析ReadProcessMemory 第一步:定位函数 第二步:开始分析 总结 实验2:分析NtRead ...
- Windows驱动开发学习笔记(五)—— SSDT HOOK
Windows驱动开发学习笔记(五)-- SSDT HOOK 系统服务表 系统服务描述符表 实验一:通过代码获取SSDT表地址 通过页表基址修改页属性 方法1:修改页属性 方法2:修改CR0寄存器 实 ...
- Windows异常学习笔记(四)—— 编译器扩展SEH
Windows异常学习笔记(四)-- 编译器扩展SEH 要点回顾 编译器支持的SEH 过滤表达式 实验一:理解_try_except 实验二:_try_except 嵌套 拓展SEH结构体 scope ...
- Windows异常学习笔记(一)—— CPU异常记录模拟异常记录
Windows异常学习笔记(一)-- CPU异常记录 基础知识 异常的分类 CPU异常 分析中断处理函数 _KiTrap00 分析 CommonDispatchException 总结 软件模拟异常 ...
- Windows APC学习笔记(二)—— 挂入过程执行过程
Windows APC学习笔记(二)-- 挂入过程&执行过程 基础知识 挂入过程 KeInitializeApc ApcStateIndex KiInsertQueueApc Alertabl ...
- Windows异常学习笔记(五)—— 未处理异常
Windows异常学习笔记(五)-- 未处理异常 要点回顾 最后一道防线 实验一:理解最后一道防线 实验二:新线程的最后一道防线 总结 UnhandledExceptionFilter 实验三:理解U ...
- Windows异常学习笔记(二)—— 内核异常处理流程用户异常的分发
Windows异常学习笔记(二)-- 内核异常处理流程&用户异常分发 用户层与内核层异常 内核异常 分析 KiDispatchException 分析 RtlDispatchException ...
最新文章
- Wiener Filter
- gtk移植到嵌入式_入行嵌入式研发10多年,一位工程师悟出了这些道理
- python专科就业难吗-听说Python就业难,是真的吗?
- hutool 读取扩展名文件_用卓语言实现中文编程显示隐藏文件扩展名
- bash删除文件中含指定内容的行
- SpringCloud Feign实战(二)
- 【小白冲冲冲!!!】37. ORBSLAM初始化时为什么要同时初始化H矩阵和F矩阵?
- paip.提升开发效率---事件化V0829
- 域名和IP地址的区别
- html横菜单中菜单均匀分布,html – 如何在flexbox中的行间均匀分布元素?
- c语言中整形的最大最小值,c语言整数和浮点数的最大最小值
- PHP在线网课问答题库搜索,推荐一个大学mooc网课答案题库在线查询公众号
- VS2010:X64和X86冲突问题
- 【原生】JS 获取今天日期
- 简单明了理解交叉验证
- 软件实施工作个人看法
- excel中联系人转换为csv导入手机出现乱码的解决方法
- 以下哪些不是Linux操作系统特点,Linux系统都有哪些特点?很多人不知道!
- 【BZOJ2002】【HNOI2010】弹飞绵羊(LCT)
- 上古卷轴3晨风职业_上古卷轴3晨风
热门文章
- AI:2020年6月21日北京智源大会演讲分享之14:50-15:15穗志方教授《从语言到知识——构建语言智能的基石》
- DL之AE:自编码器AutoEncoder的简介、应用、经典案例之详细攻略
- 成功解决Python3版UnicodeDecodeError: ‘ascii‘ codec can‘t decode byte 0x90 in position 614: ordinal not in
- Android的Intent你知道多少?
- 201312-1- 出现次数最多的数
- 第九章 字符串,字符和字节
- 小程序 常用快捷键
- Android IllegalStateException: The specified child already has a parent问题解决办法
- 【自译】八步成为数据科学家
- 常用代码整理(重要)