系统调用003 系统服务表
文章目录
- 前言
- SystemServiceTable 系统服务表
- 系统服务表在哪
- 判断调用的函数在哪个表
- API函数的调用过程
前言
我们现在已经知道API怎么从三环进入零环,从三环进零环需要带两个寄存器,分别是eax和edx。eax保存的是系统的服务号,edx保存的是三环的esp,通过esp可以找到三环的参数。
这次要解决的问题是如何通过eax找到零环的函数,零环的函数是怎么被调用的,并且零环的函数执行的时候是怎么使用三环的参数的。
SystemServiceTable 系统服务表
在操作系统里,有一张非常重要的表,SystemServiceTable 系统服务表 。系统服务表是操作系统内核的一张表,结构如图:
总共有四个成员:
- ServiceTable 这个成员是个地址,通过这个地址可以找到一个函数地址表。从三环进零环的eax的服务号就是函数地址表的索引
- count 当前的系统服务表被调用了多少次
- ServiceLimit:保存的是函数地址表的大小,也就是服务函数的个数
- ArgmentTable:函数参数表,里面保存的是函数地址表对应的参数个数,以字节为单位。例如函数地址表下标为1的函数需要三个参数,那么函数参数表下标为1的内容就是12
- 系统服务表有两份,其中一份函数来自于Ntoskrl.exe内核模块的导出函数,里面保存常用的系统服务;另外一份来自Win32k.sys的导出函数,里面是与图形以及用户界面相关的系统服务。向三环提供的内核函数全在这两张表里。
系统服务表在哪
系统服务表位于_KTHREAD
结构体0xE0的位置。
判断调用的函数在哪个表
问题在于系统服务表有两张,那么我们怎么判断需要调用的函数在哪个表呢
- 要找两张表取决于eax系统服务号。这个系统服务号总共有32位,但是真正只使用了13位。
- 系统服务号在使用的时候分为两部分,低12位表示的是函数地址表的索引,下标为12的位置的值,决定了使用哪张表
- 如果第12位为0,则找第一张表,如果第12位为1,则找第二张表。
API函数的调用过程
接下来就来分析零环代码是怎么通过服务号找到零环函数,并且零环的函数是如何使用在三环的参数的。
用IDA打开ntkrnlpa.exe,找到KiFastCallEntry函数。KiFastCallEntry和KiSystemService前面的代码都是用于保存现场,大致相同。
我们从保存现场之后开始分析。
.text:0046579D mov edi, eax ; 取出三环传进来的系统调用号
首先将三环传递过来的系统调用号保存到edi里
.text:0046579F shr edi, 8 ; 系统调用号右移8位
.text:004657A2 and edi, 30h ; 判断调用号的第12是0还是1
.text:004657A5 mov ecx, edi ; ecx存储的值是00或者0x10
然后将系统调用号右移8位,然后再和0x30做与运算。此时edi的结果只能有两种,要么是0x0,要么是0x10。如果是0的话,就说明调用号下标为12的位置是0,如果edi的结果是0x10,那久说明调用号下标为12的位置是1。
.text:004657A7 add edi, [esi+0E0h] ; edi指向KTHREAD--->ServiceTable
esi指向的是ETHREAD线程结构体,这个结构体+0xE的位置是ServiceTable系统服务表。用系统服务表直接加上edi的值。如果edi的值是0,加上ServiceTable的基址还是等于原来的值,这个时候就会找第一张系统服务表。
如果edi的值是0x10,再加上ServiceTable的基址指向的刚好是第二张表。因为系统服务表的大小正好是0x10,加上0x10就能找到第二张表。这个地方的算法非常巧妙。
.text:004657AD mov ebx, eax ; 把三环的系统服务号存到ebx备份
.text:004657AF and eax, 0FFFh ; 系统调用号 只保留后12位
接着把系统调用号备份到ebx,然后和0FFFh做与运算,保留后12位
.text:004657B4 cmp eax, [edi+8]
.text:004657B7 jnb _KiBBTUnexpectedRange
这里用eax和edi+0x8的位置做比较,此时的edx指向的是系统服务表,[edi+8]的位置是第三个成员ServiceLimit,是服务函数的个数。如果传入的调用号的低12位大于服务函数的个数,就跳转到_KiBBTUnexpectedRange。
这里是判断要找的函数有没有超过函数地址表的范围。如果没有越界,代码会继续往下走。
.text:004657BD cmp ecx, 10h ; 判断是否是查第二张系统服务表
.text:004657C0 jnz short loc_4657DC ; 如果是查第一张系统服务表则跳转
接着拿ecx和0x10进行比较,ecx的值来自于edi,存储的值是00或者0x10,如果ecx是10的话就说明要查第二张系统服务表。
如果是查第一张系统服务表就会跳转,查第二张则继续往下执行
.text:004657C2 mov ecx, ds:0FFDFF018h
.text:004657C8 xor ebx, ebx
.text:004657CA
.text:004657CA loc_4657CA: ; DATA XREF: _KiTrap0E+113↓o
.text:004657CA or ebx, [ecx+0F70h]
.text:004657D0 jz short loc_4657DC
.text:004657D2 push edx
.text:004657D3 push eax
.text:004657D4 call ds:_KeGdiFlushUserBatch
.text:004657DA pop eax
.text:004657DB pop edx
最后会调用_KeGdiFlushUserBatch
函数。继续往下分析,假设最后查的是第一张系统服务表
.text:004657DC loc_4657DC: ; CODE XREF: _KiFastCallEntry+B0↑j
.text:004657DC inc dword ptr ds:0FFDFF638h ; _KPCRB->0x518 KeSystemCall增加1
.text:004657E2 mov esi, edx ; edx存储的三环的参数指针
这里将edx保存到esi,edx存储的是三环的参数指针
.text:004657E4 mov ebx, [edi+0Ch] ;ebx指向参数表起始位置
此时的edi指向系统服务表的起始位置,[edi+0Ch]存储的是ParamTableBase 参数表的基址,此时ebx指向参数表起始位置。
.text:004657E9 mov cl, [eax+ebx] ; eax->函数地址表索引 ebx->参数表起始位置 cl->参数的个数
参数表的基址加上函数地址表的索引,再取内容得到的值就是要调用的函数的参数个数。
.text:004657EC mov edi, [edi] ; edi指向系统服务表 第一个成员是函数地址表
接下来取出函数地址表放到edi
.text:004657EE mov ebx, [edi+eax*4] ; ebx->零环的函数地址
接下来用函数地址表edi加上索引eax乘以4,这行代码执行完成之后ebx存储的是零环的函数地址
.text:004657F1 sub esp, ecx ; 提升堆栈 提升高度为CL
接着提升堆栈,提升的大小为CL,也就是参数的大小,为了容纳三环的参数
.text:004657F3 shr ecx, 2 ; 参数总长度/4=参数的个数
.text:00465804 rep movsd ; 开始拷贝参数
然后将ecx右移两位,右移两位相当于除以4,得到的结果是参数的个数。为什么要右移呢?原因很简单,因为后面的rep串操作指令的循环次数取决于ecx的值,而movsd一次复制4个字节。
.text:004657F8 cmp esi, ds:_MmUserProbeAddress ; 判断三环的参数的地址范围是否越界
.text:004657FE jnb loc_4659AC ; 越界跳转到错误处理模块
此时esi指向的是三环的函数指针,这里跟一个全局变量进行比较,这个全局变量是用户程序能访问地址的最大范围。
这里是为了判断三环的参数的地址范围是否越界,如果越界则跳转到错误处理的模块
.text:00465804 rep movsd ; 开始拷贝参数
.text:00465806 call ebx ; 调用函数
最后将三环的参数赋值到零环,开始调用真正的内核函数
系统调用003 系统服务表相关推荐
- Windows系统调用学习笔记(四)—— 系统服务表SSDT
Windows系统调用学习笔记(四)-- 系统服务表&SSDT 要点回顾 系统服务表 实验:分析 KiSystemService 与 KiFastCallEntry 共同代码 SSDT 实验: ...
- 4.API的调用过程(系统服务表)
SystemServiceTable(系统服务表) typedef struct _KSYSTEM_SERVICE_TABLE {PULONG ServiceTableBase; //这个指向系统服务 ...
- 《SQL高级应用和数据仓库基础(MySQL版)》学习笔记 ·003【表的约束、表的CRUD操作(DDL语句)】
文章目录 一.表的约束 1.约束类型 2.添加约束 二.表的CRUD操作(DDL语句) 1.C(Create):创建 2.R(Retrieve):查询 3.U(Update):更新 4.D(Delet ...
- 图解SQL面试题 (学习笔记) 003多表查询----2
这里写目录标题 一级目录 二级目录 三级目录 如何比较日期数据 如何交换数据 滴滴面试题:如何找出最小N个数 一级目录 二级目录 三级目录 如何比较日期数据 [题目] 下面是某公司每天的营业额,表名为 ...
- 《学活Linux》第一讲——系统调用和VFS
<学活LINUX> 第一讲 系统调用和VFS 自确定<学活LINUX>课程详情以来,已有两周时间.相信很多格友们已经准备好GDK8,等待课程的开始.2023年7月22日,上周六 ...
- SSDT表与ShadowSSDT表
实际上内核中存在两个系统服务描述符表,一个是KeServiceDescriptorTable(由ntoskrnl.exe导出):,一个是KeServieDescriptorTableShadow(没有 ...
- linux系统调用理解之摘录(2)
原文博客 http://blog.csdn.net/gatieme/article/details/50779184 Linux系统调用的实现机制分析 本文介绍了系统调用的一些细节. 首先,分析了系统 ...
- (52)系统调用阶段测试——基于 SSDT HOOK 的 FindWindowA 监视器
一.项目说明 SSDT HOOK 内核函数我们已经会了,请看这两篇博客: SSDT HOOK 实现进程保护 补充内容:SSDT HOOK 模板 此次考试和 hook NtOpenProcess 或 N ...
- Windows系统调用学习笔记(三)—— 保存现场
Windows系统调用学习笔记(三)-- 保存现场 要点回顾 基本概念 Trap Frame 结构 线程相关的结构体 ETHREAD KTHREAD CPU相关的结构体 KPCR _NT_TIB KP ...
最新文章
- Java案例:生成指定目录下某种类型文件的列表
- 消息称《绝地求生》开发商Krafton将启动IPO 腾讯是大股东
- 编程范式之rotate操作
- 【 Hibernate3-摘要 】 【 第1节 】:JPA常用注解
- python的优点有哪些-python语言有什么优势
- pytorch 向量转化为one-hot编码
- BZOJ2115 [WC2011]最大XOR和路径
- Matlab中的c2d函数用法
- C++--struct的用法
- chrome浏览器F12 Network中Timing参数含义
- python爬虫从入门到放弃(一)初识爬虫
- 动态水印跟踪去除_视频动态水印如何去除 视频中不定时出现的图片加文字广告如何尽量模糊处理...
- 硬件知识:独立显卡和集成显卡的区别
- Driver的prob的调用顺序
- 施坦威D4三角钢琴-e-instruments Session Keys Grand S Kontakt
- 边缘基础设施还差点什么?
- 微软面试题:五个囚犯抓绿豆
- vlive android app,v live app
- 新概念英语第二册课文电子版_新概念英语第二册音频+视频讲解:Lesson 24
- 沉没的蜀山---探索东方神话传说中的泰坦尼克
热门文章
- 成功解决raise XGBoostError(_LIB.XGBGetLastError()) xgboost.core.XGBoostError: b'[22:08:00] C:\\Users\\Ad
- 成功解决ValueError: Parameter values for parameter (n_estimators) need to be a sequence.
- ML之DT:基于DT算法对泰坦尼克号乘客数据集进行二分类(是否获救)预测
- CV:基于keras利用cv2自带两步检测法对《跑男第六季第五期》之如花片段(或调用摄像头)进行实时性别脸部表情检测
- Python中的argparse模块
- os_mem.c(全)
- MongoDB学习笔记【2】-- 试用
- 板邓:wordpress建站不得不知的安全防护(二)
- jQuery Event.stopPropagation() 函数详解
- 最长公共子序列 nyoj-36