SSDT Hook实现内核级的进程保护
目录
- SSDT Hook效果图
- SSDT简介
- SSDT结构
- SSDT HOOK原理
- Hook前准备
- 如何获得SSDT中函数的地址呢
- SSDT Hook流程
- SSDT Hook实现进程保护
- Ring3与Ring0的通信
- 如何安装启动停止卸载服务
- 参考文献
- 源码附件
- 版权
SSDT Hook效果图

SSDT简介
这个表就是一个把 Ring3 的 Win32 API 和 Ring0 的内核 API 联系起来。
SSDT 并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。
通过修改此表的函数地址可以对常用 Windows 函数及 API 进行 Hook,从而实现对一些关心的系统动作进行过滤、监控的目的。
一些 HIPS、防毒软件、系统监控、注册表监控软件往往会采用此接口来实现自己的监控模块。
SSDT结构
// KSYSTEM_SERVICE_TABLE 和 KSERVICE_TABLE_DESCRIPTOR
// 用来定义 SSDT 结构
typedef struct _KSYSTEM_SERVICE_TABLE
{
PULONG ServiceTableBase; // SSDT (System Service Dispatch Table)的基地址
PULONG ServiceCounterTableBase; // 用于 checked builds, 包含 SSDT 中每个服务被调用的次数
ULONG NumberOfService; // 服务函数的个数, NumberOfService * 4 就是整个地址表的大小
ULONG ParamTableBase; // SSPT(System Service Parameter Table)的基地址
} KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE; 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;
SSDT HOOK原理
lkd> dd KeServiceDescriptorTable
8055ab80 804e3d20 0000011c 804d9f48
8055ab90
8055aba0
8055abb0
如上,80587691 805716ef 8057ab71 80581b5c 这些就是系统服务函数的地址了。比如当我们在ring3调用OpenProcess时,进入sysenter的ID是0x7A(XP SP2),然后系统查KeServiceDescriptorTable,大概是这样KeServiceDescriptorTable.ntoskrnel.ServiceTableBase(804e3d20) + 0x7A * 4 = 804E3F08,然后804E3F08 ->8057559e 这个就是OpenProcess系统服务函数所在,我们再跟踪看看:
lkd> u 8057559e
nt!NtOpenProcess:
8057559e 68c4000000 push 0C4h
805755a3 6860b54e80 push offset nt!ObReferenceObjectByPointer+0x127 (804eb560)
805755a8 e8e5e4f6ff call nt!InterlockedPushEntrySList+0x79 (804e3a92)
805755ad 33f6 xor esi,esi
嗯,如果我们把8057559e改为指向我们函数的地址呢?比如 MyNtOpenProcess,那么系统就会直接调用MyNtOpenProcess,而不是原来的NtOpenProcess了。这就是SSDT HOOK 原理所在。
Hook前准备
//设置为不可写
void DisableWrite()
{
__try
{
_asm
{
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
}
__except()
{
DbgPrint("DisableWrite执行失败!");
}
}
// 设置为可写
void EnableWrite()
{
__try
{
_asm
{
cli
mov eax,cr0
and eax,not 10000h //and eax,0FFFEFFFFh
mov cr0,eax
}
}
__except()
{
DbgPrint("EnableWrite执行失败!");
}
}
具体做法可以google下,这里就不介绍了
如何获得SSDT中函数的地址呢?
这里主要使用了两个宏:
①获取指定服务的索引号:SYSCALL_INDEX
②获取指定服务的当前地址:SYSCALL_FUNCTION
这两个宏的具体定义如下:
//根据 ZwServiceFunction 获取 ZwServiceFunction 在 SSDT 中所对应的服务的索引号 #define SYSCALL_INDEX(ServiceFunction) (*(PULONG)((PUCHAR)ServiceFunction + 1)) //根据ZwServiceFunction 来获得服务在 SSDT 中的索引号,然后再通过该索引号来获取ntServiceFunction的地址 #define SYSCALL_FUNCTION(ServiceFunction) KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[SYSCALL_INDEX(ServiceFunction)]
SSDT Hook流程
在驱动的入口函数中(DriverEntry),对未进行SSDT Hook前的SSDT表进行了备份(用一个数组保存),备份时,一个索引号对应一个当前地址,如上图所示。
这样,在解除Hook的时候,就可以从全局数组中根据索引号获取未Hook前的服务名的当前地址,以便将原来的地址写回去,这一步很重要。
当用户选择保护某个进程的时候,就会通过DeviceIoControl发送一个IO_INSERT_PROTECT_PROCESS控制码给驱动程序,此时驱动程序会生成一个IRP:IRP_MJ_DEVICE_CONTROL,我们事先已经在驱动程序中为
IRP_MJ_DEVICE_CONTROL指定了一个派遣函数:SSDTHook_DispatchRoutine_CONTROL。在该派遣函数中:我们通过获取控制码(是保护进程还是取消保护进程),如果是要保护某个进程,则通过
DeviceIoControl的第3个参数将要保护的进程的pid传递给驱动程序。然后在派遣函数SSDTHook_DispatchRoutine_CONTROL中从缓冲区中读取该pid,如果是要保护进程,则将要“保护进程”的pid添加到一个数组中,如果是要“取消保护进程”,则将要取消保护的进程PID从数组中移除。
在Hook NtTermianteProcess函数后,会执行我们自定义的函数:HookNtTerminateProcess,在HookNtTerminateProcess函数中,我们判断当前进程是否在要保护的进程数组中,如果该数组中存在该pid,则我们返回一个“权限不够”的异常,如果进程保护数组中不存在该pid,则直接调用原来 SSDT 中的 NtTerminateProcess 来结束进程。
SSDT Hook实现进程保护
// 实现 Hook 的安装,主要是在 SSDT 中用 newService 来替换掉 oldService
NTSTATUS InstallHook(ULONG oldService, ULONG newService)
{
__try
{
ULONG uOldAttr = ;
EnableWrite(); //去掉页面保护
KdPrint(("伪造NtTerminateProcess地址: %x\n",(int)newService));
//KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[SYSCALL_INDEX(oldService)] = newService;
SYSCALL_FUNCTION(oldService) = newService;//
DisableWrite(); //恢复页面保护
return STATUS_SUCCESS;
}
__except()
{
KdPrint(("安装Hook失败!"));
}
}
//************************************
// 函数名称 : HookNtTerminateProcess
// 描 述 : 自定义的 NtOpenProcess,用来实现 Hook Kernel API
// 日 期 : 2013/06/28
// 参 数 : ProcessHandle:进程句柄 ExitStatus:
// 返 回 值 :
//************************************
NTSTATUS HookNtTerminateProcess(__in_opt HANDLE ProcessHandle,__in NTSTATUS ExitStatus)
{
ULONG uPID;
NTSTATUS rtStatus;
PCHAR pStrProcName;
PEPROCESS pEProcess;
ANSI_STRING strProcName; // 通过进程句柄来获得该进程所对应的 FileObject 对象,由于这里是进程对象,自然获得的是 EPROCESS 对象
rtStatus = ObReferenceObjectByHandle(ProcessHandle, FILE_READ_DATA, NULL, KernelMode, (PVOID*)&pEProcess, NULL);
if (!NT_SUCCESS(rtStatus))
{
return rtStatus;
}
// 保存 SSDT 中原来的 NtTerminateProcess 地址
pOldNtTerminateProcess = (NTTERMINATEPROCESS)oldSysServiceAddr[SYSCALL_INDEX(ZwTerminateProcess)]; // 通过该函数可以获取到进程名称和进程 ID,该函数在内核中实质是导出的(在 WRK 中可以看到)
// 但是 ntddk.h 中并没有到处,所以需要自己声明才能使用
uPID = (ULONG)PsGetProcessId(pEProcess);
pStrProcName = _strupr((TCHAR *)PsGetProcessImageFileName(pEProcess));//使用微软未公开的PsGetProcessImageFileName函数获取进程名 // 通过进程名来初始化一个 ASCII 字符串
RtlInitAnsiString(&strProcName, pStrProcName); if (ValidateProcessNeedProtect(uPID) != -)
{
// 确保调用者进程能够结束(这里主要是指 taskmgr.exe)
if (uPID != (ULONG)PsGetProcessId(PsGetCurrentProcess()))
{
// 如果该进程是所保护的的进程的话,则返回权限不够的异常即可
return STATUS_ACCESS_DENIED;
}
}
// 对于非保护的进程可以直接调用原来 SSDT 中的 NtTerminateProcess 来结束进程
rtStatus = pOldNtTerminateProcess(ProcessHandle, ExitStatus);
return rtStatus;
}
Ring3与Ring0的通信
SSDT Hook实现内核级的进程保护的更多相关文章
- SSDT Hook结构
目录 SSDT Hook效果图 SSDT简介 SSDT结构 SSDT HOOK原理 Hook前准备 如何获得SSDT中函数的地址呢 SSDT Hook流程 SSDT Hook实现进程保护 Ring3与 ...
- linux0.11内核源码——用户级线程及内核级线程
参考资料:哈工大操作系统mooc 用户级线程 1.每个进程执行时会有一套自己的内存映射表,即我们所谓的资源,当执行多进程时切换要切换这套内存映射表,即所谓的资源切换 2.但是如果在这个进程中创建线程, ...
- SSDT Hook实现简单的进程隐藏和保护【转载】
原文链接:http://www.blogfshare.com/ssdthook-hide-protect.html 原文作者:AloneMonkey SSDT Hook实现简单的进程隐藏和保护 Alo ...
- 进程隐藏与进程保护(SSDT Hook 实现)(二)
文章目录: 1. 引子 – Demo 实现效果: 2. 进程隐藏与进程保护概念: 3. SSDT Hook 框架搭建: 4. Ring0 实现进程隐藏: 5. Ri ...
- 进程隐藏与进程保护(SSDT Hook 实现)(一)
读了这篇文章终于明白大致怎么回事了 文章目录: 1. 引子 – Hook 技术: 2. SSDT 简介: 3. 应用层调用 Win32 API 的完整执行流程: 4 ...
- 通过SSDT HOOK实现进程保护和进程隐藏
---恢复内容开始--- 首先,我要说一件很重要的事,本人文采不好,如果哪里说的尴尬了,那你就尴尬着听吧...... SSDT HOOK最初貌似源于Rookit,但是Rookit之前有没有其他病毒使用 ...
- 进程隐藏与进程保护(SSDT Hook 实现)(三)
文章目录: 1. 引子: 2. 获取当前系统下所有进程: 3. 服务管理(安装,启动,停止,卸载): 4. 应用程序和内核程序通信: 5. 小结: 1. 引子: 关于这个 SSDT Hook 实现进程 ...
- 【Hook技术】实现从"任务管理器"中保护进程不被关闭 + 附带源码 + 进程保护知识扩展
[Hook技术]实现从"任务管理器"中保护进程不被关闭 + 附带源码 + 进程保护知识扩展 公司有个监控程序涉及到进程的保护问题,需要避免用户通过任务管理器结束掉监控进程,这里使用 ...
- Windows2003 内核级进程隐藏、侦测技术
论文关键字: 内核 拦截 活动进程链表 系统服务派遣表 线程调度链 驱动程序简介 论文摘要:信息对抗是目前计算机发展的一个重要的方向,为了更好的防御,必须去深入的了解敌人进攻的招式.信息对抗促使 ...
随机推荐
- 【Java】Java批量文件打包下载zip
网上看了很多,本文使用ant.jar中的org.apache.tools.zip,页面用js表单提交 代码供参考: ACTION: /* * 另存为 */ @Request ...
- (转)忘记wamp-mysql数据库root用户密码重置方法
转自:http://www.jb51.net/article/28883.htm 1.打开任务管理器,结束进程 mysqld-nt.exe . 2.运行命令窗口 1)进行php服务管理器安装目录中的 ...
- (转)WCF中神秘的“8733"端口和“Design_Time_Addresses”
转自:http://blog.csdn.net/bitfan/article/details/4193319 如果使用Visual Studio 2008 SP1开发WCF应用程序时,会发现当使用Vi ...
- bzoj2938(ac自动机)
刚学了ac自动机,去hzwer上找了道练习题: 串是安全的就说明ac自动机不会找到匹配,考虑ac自动机的匹配过程: 我们把val等于1的点删掉和fail指针指向被删掉的点删掉: 如果剩下的图有环,就有 ...
- Async Return Types
Async methods have three possible return types: Task<TResult>, Task, and void. The Task<TRe ...
- 使用Servlet动态生成验证码
最近在重新看了一遍servlert,看到篇优质博客推荐给大家:https://www.cnblogs.com/xdp-gacl/p/3798190.html 顺便把学习过程中的知识记录下来. 今天是如 ...
- QOpenGLFunctions的相关的使用(1)
QOpenGLFunctions的使用 1. QOpenGLFunctions 说明 QOpenGLFunctions 类提供了跨平台的OpenGl ES2.0 API版本. OpenGL 2. ...
- HDU3572构造图的模型
第一次面对建模的图,也映照了我以前想的算法不是重点,问题的转化才是重点 Description: N个任务,M台机器,对于每一个任务有p,s,e表示该任务要做p个时长,要从[s,……)开始,从(……e ...
- 直接端口打印 支持USB接口的打印机吗?解决办法
直接端口打印 支持USB接口的打印机吗?解决办法 www.MyException.Cn 网友分享于:2013-09-15 浏览:488次 直接端口打印 支持USB接口的打印机吗?问题如 ...
- cnn的说明
概述 前面的练习中,解决了一些有关低分辨率图像的问题,比如:小块图像,手写数字小幅图像等.在这部分中,我们将把已知的方法扩展到实际应用中更加常见的大图像数据集. 全联通网络 在稀疏自编码章节中,我们介 ...