Windows系统调用中的系统服务表描述符
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
Windows系统调用中的系统服务表描述符(SSDT)
在前面,我们将解过 系统服务表。可是,我们有个疑问,系统服务表存储在哪里呢?
答案就是:系统服务表 存储在 系统服务描述符表中。(其又称为 SSDT Service Descriptor Table)

一、使用PELord函数从ntoskrnl.exe文件中查看SSDT导出函数
如图,可以看出KeServiceDescriptorTable导出函数。
通过该函数可以查找SSDT表的位置。

二、通过Windbg来内存中查看SSDT表
使用Windbg,可以使用 kd> dd nt!KeServiceDescriptorTable 指令来查看SSDT表。
但该指令存在缺点,可以看到第二张表为0,说明如果使用KeServiceDescriptorTable这个公开的导出函数,我们无法看到win32k.sys这张表结构
kd> dd nt!KeServiceDescriptorTable
83f759c0 83e89d9c 00000000 00000191 83e8a3e4
83f759d0 00000000 00000000 00000000 00000000
83f759e0 83ee86af 00000000 0327aa43 000000bb
83f759f0 00000011 00000100 5385d2ba d717548f
为了解决上面这个问题,我们只能使用另外一个指令,该指令对应的是一个未公开导出的函数。
如下,可以看到其第二行,win32k.sys系统服务表已经可见。
kd> dd KeServiceDescriptorTableShadow
83f75a00 83e89d9c 00000000 00000191 83e8a3e4
83f75a10 83b66000 00000000 00000339 83b6702c
83f75a20 00000000 00000000 83f75a24 00000340
83f75a30 00000340 855e8440 00000007 00000000
三、验证ReadMemory真正的内核实现部分
我们在这篇《Windows系统调用中API的三环部分(依据分析重写ReadProcessMemory函数)》中曾提到过直接使用快速调用来摒弃R3层层封装的API,其中给eax一个函数号,现在我们来实战刨析一下。
mov eax, 0x115
mov edx, 0X7FFE0300
如下,系统描述符的数据结构,其依次分别为

其依次分别为 ServiceTable 83e89d9c,Count 00000000,ServiceLimit 00000191,ServiceTable 83e8a3e4
使用Windbg来查看其115h序号的函数地址 115h*4 + 83e89d9c (ServiceTable)
得到函数地址为 8406c82c
kd> dd 115h*4 + 83e89d9c
83e8a1f0 8406c82c 840feb46 83fb488c 83fb6128
再对此进行反汇编可得
kd > u 8406c82c
nt!NtReadVirtualMemory:
8406c82c 6a18 push 18h
8406c82e 68282ae683 push offset nt!? ? ::FNODOBFM::`string'+0x3ea8 (83e62a28)
8406c833 e870e3e1ff call nt!_SEH_prolog4(83e8aba8)
8406c838 648b3d24010000 mov edi, dword ptr fs : [124h]
8406c83f 8a873a010000 mov al, byte ptr[edi + 13Ah]
8406c845 8845e4 mov byte ptr[ebp - 1Ch], al
8406c848 8b7514 mov esi, dword ptr[ebp + 14h]
8406c84b 84c0 test al, al
之后,我们查看该nt!NtReadVirtualMemory函数的参数个数
kd > db 83e8a3e4 + 115
83e8a4f9 14 08 04 04 14 04 10 08 - 0c 04 14 18 08 08 08 0c
83e8a509 0c 08 10 14 08 08 0c 08 - 0c 0c 04 08 08 08 08 08
83e8a519 08 0c 0c 24 00 08 08 08 - 0c 04 08 04 08 10 08 04
四、通过修改SSDT表增添系统服务函数
我们在 Windows系统调用中API的三环部分(依据分析重写ReadProcessMemory函数) 调用的是 115h 号函数。
现在,我们将该函数地址放到 191 号函数处(之前一共有191个函数,占据0-190位)。
修改思路:
1)将 nt!NtReadVirtualMemory 函数地址 8406c82c 放到 191号处(83e89d9 + 191h*4)
kd> ed 83e89d9 + 191h*4 8406c82c
2) 增大 服务表最大个数。 (因为我们上一节分析其反汇编代码的时候,发现其会进行最大个数的判断)
kd> ed 83f75a00+8 192
3) 修改参数个数表中对应的191号参数个数。(我们之前查阅过其为 14,以字节为单位)
kd> eb 83e8a3e4+191 14
4) 之后,我们运行下列代码。其与《Windows系统调用中API的三环部分(依据分析重写ReadProcessMemory函数)》唯一的不同调用函数号为192,最终效果完全一样。
#include "pch.h"
#include <iostream>
#include <algorithm>
#include <Windows.h>
void ReadMemory(HANDLE hProcess, PVOID pAddr, PVOID pBuffer, DWORD dwSize, DWORD *dwSizeRet)
{ _asm
{
lea eax, [ebp + 0x14]
push eax
push[ebp + 0x14]
push[ebp + 0x10]
push[ebp + 0xc]
push[ebp + ]
sub esp,
mov eax, 0x192 // 注意:修改的是这里
mov edx, 0X7FFE0300 //sysenter不能直接调用,我间接call的
CALL DWORD PTR[EDX]
add esp, }
}
int main()
{
HANDLE hProcess = ;
int t = ;
DWORD pBuffer;
//hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0,a);
ReadMemory((HANDLE)-, (PVOID)&t, &pBuffer, sizeof(int), );
printf("%X\n", pBuffer);
ReadProcessMemory((HANDLE)-, &t, &pBuffer, sizeof(int), );
printf("%X\n", pBuffer); getchar();
return ;
}
五、驱动代码实现
其中涉及页保护问题,可以查看我的博客其他文章,有介绍。
/*
利用IDT_HOOK技术,将115h号函数地址挂靠在191h处。
*/ #include <ntddk.h>
#include <ntstatus.h>
// 系统服务表的结构体
typedef struct _KSYSTEM_SERVICE_TABLE
{
PULONG ServiceTableBase; // SSDT (System Service Dispatch Table)的基地址
PULONG ServiceCounterTableBase; // 用于 checked builds, 包含 SSDT 中每个服务被调用的次数
ULONG NumberOfService; // 服务函数的个数, NumberOfService * 4 就是整个地址表的大小
// ParamTableBase[0x115],一个字节一个数,因此要使用PUCHAR数据类型而不是PULONG
PUCHAR ParamTableBase // SSPT(System Service Parameter Table)的基地址
} KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE;
// SSDT结构体
typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
KSYSTEM_SERVICE_TABLE ntoskrnl; // ntoskrnl.exe 的服务函数
KSYSTEM_SERVICE_TABLE win32k; // win32k.sys 的服务函数(GDI32.dll/User32.dll 的内核支持)
KSYSTEM_SERVICE_TABLE notUsed1;
KSYSTEM_SERVICE_TABLE notUsed2;
}KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
// KeServiceDescriptorTable 这个变量名不能改,其为 ntoskrnl.exe 导出的变量名
extern PKSYSTEM_SERVICE_TABLE KeServiceDescriptorTable;
//关闭内存保护裸函数
void _declspec(naked)OffMemoryProtect()
{
__asm { //关闭内存保护
push eax;
mov eax, cr0;
and eax, ~0x10000;
mov cr0, eax;
pop eax;
ret;
}
}
//开启内存保护裸函数
void _declspec(naked)OnMemoryProtect()
{
__asm { //恢复内存保护
push eax;
mov eax, cr0;
or eax, 0x10000;
mov cr0, eax;
pop eax;
ret;
}
} // 驱动卸载函数
NTSTATUS DriverUnload(PDRIVER_OBJECT Driver) {
return STATUS_SUCCESS;
} // 驱动入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT Driver, PUNICODE_STRING RegPath) {
NTSTATUS status; Driver->DriverUnload = DriverUnload;
DbgPrint("---> %x", KeServiceDescriptorTable); // 关闭内存保护
OffMemoryProtect(); // 修改服务表的最大个数
KeServiceDescriptorTable->NumberOfService++;
// 增加一个新地址
KeServiceDescriptorTable->ServiceTableBase[0x191] = KeServiceDescriptorTable->ServiceTableBase[0x115];
// 将参数地址也给同步更新
KeServiceDescriptorTable->ParamTableBase[0x191] = KeServiceDescriptorTable->ParamTableBase[0x115]; // 开启内存保护
OnMemoryProtect();
return STATUS_SUCCESS;
}
Windows系统调用中的系统服务表描述符的更多相关文章
- Windows系统调用中的系统服务表
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中的系统服务表 如果这部分不理解,可以查看 ...
- Windows系统调用中的现场保存
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中的现场保存 我们之前介绍过三环进零环的步骤 ...
- Windows系统调用中API从3环到0环(下)
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(下) 如果对API在 ...
- Windows系统调用中API从3环到0环(上)
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(上) 如果对API在三 ...
- 自学Linux Shell14.2-在脚本中使用其他文件描述符
点击返回 自学Linux命令行与Shell脚本之路 14.2-在脚本中使用其他文件描述符 在脚本中重定向输入和输出,并布局限于以上讲的3个默认的文件描述符,shell最多可以有9个打开的文件描述符.这 ...
- Windows系统调用中API的3环部分(依据分析重写ReadProcessMemory函数)
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API的3环部分 一.R3环API分析的重 ...
- 【windows 访问控制】二、安全描述符(Security Descriptors,SD)
安全描述符(Security Descriptors,SD) 定义 安全描述符是与安全对象的安全信息,它含有这个对象所有者的SID,以及一个访问控制列表(ACL,Access Control List ...
- Linux中通过Socket文件描述符寻找连接状态介绍
针对下文的总结:socket是一种文件描述符 进程的打开文件描述符表 Linux的三个系统调用:open,socket,pipe 返回的都是一个描述符.不同的进程中,他们返回的描述符可以相同.那么,在 ...
- 用 C# 在 Windows 7 中写注册表想到的
摘自:http://blog.163.com/dpj_001/blog/static/2742941520110251500753/ 某日做一个项目,需要在注册表中加入键,同时写值,操作系统环境为 W ...
随机推荐
- SpringBoot 2.0 + Apache Dubbo 2.7.3 最新版整合方案
前言 2018年2月16日,Apache Dubbo 加入 Apache 基金会孵化器.2019年5月16日,Apache 软件基金会董事会决议通过了 Apache Dubbo 的毕业申请,这意味着 ...
- (六十七)c#Winform自定义控件-柱状图
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- Hadoop学习笔记—20.网站日志分析项目案例
1.1 项目来源 本次要实践的数据日志来源于国内某技术学习论坛,该论坛由某培训机构主办,汇聚了众多技术学习者,每天都有人发帖.回帖,如图1所示. 图1 项目来源网站-技术学习论坛 本次实践的目的就在于 ...
- JavaScript中的this到底是怎样的?
this是困惑JavaScript开发者的一大‘毒瘤’,在开发过程中,但凡用到this的时候,我们都会很头疼,那么这个this在JavaScript中到底是怎么样的?身为一个前端coder,这是一个避 ...
- Python获取列表中的最后一个或者倒数第几个的方案
print(members[3]) 灵魂所在“ - (负号 )” 我们先来创建一个列表,和php中的数组一样. members = ['张三','李四','王五','芳芳','小明','小王'] 按照 ...
- linux 操作系统级别监控 free命令
free命令可以查看当前系统内存的使用情况 free -m 以MB为单位 free -k 以KB为单位 free -m 以MB为单位显示系统内存的使用情况,同理,也可以使用-k.-g等其他的单位显示 ...
- Redis专题(3):锁的基本概念到Redis分布式锁实现
拓展阅读:Redis闲谈(1):构建知识图谱 Redis专题(2):Redis数据结构底层探秘 近来,分布式的问题被广泛提及,比如分布式事务.分布式框架.ZooKeeper.SpringCloud等等 ...
- 后端(spring boot)解决跨区域问题
一.环境: 前端 vue element-ui 后端:spring boot 工具:IDEA Maven Node 数据库:MySql 二.首先我们需要了解什么叫跨区域访问问题 跨区域访问是指:不同域 ...
- 报错:ORA-25150:不允许对区参数执行ALERING
alter table 表名 MOVE storage ( next 128 ) ; -- Add/modify columns alter table 表名 add 列名 var ...
- 多智能体系统(MAS)简介
1.背景 自然界中大量个体聚集时往往能够形成协调.有序,甚至令人感到震撼的运动场景,比如天空中集体翱翔的庞大的鸟群.海洋中成群游动的鱼群,陆地上合作捕猎的狼群.这些群体现象所表现出的分布.协调.自 ...