SSDT Hook实现简单的进程隐藏和保护【转载】
原文链接:http://www.blogfshare.com/ssdthook-hide-protect.html
原文作者:AloneMonkey
SSDT Hook实现简单的进程隐藏和保护
有前面对SSDT的了解之后,如果还有不是很了解的同学,请参考SSDT详解及Win32 API到系统服务描述符表调用的完整过程。已经讲的很详细了。
一、SSDT HOOK原理
其实 SSDT Hook 的原理是很简单,从前篇的分析,我们可以知道在 SSDT 这个数组中呢,保存了系统服务的地址,比如对于 Ring0 下的 NtQuerySystemInformation 这个系统服务的地址,就保存在 KeServiceDescriptorTable[105h] 中,既然是 Hook 的话,我们就可以将这个 KeServiceDescriptorTable[105h] 下保存的服务地址替换掉,将我们自己的 Hook 处理函数的地址来替换掉原来的地址,这样当每次调用 KeServiceDescriptorTable[105h]时就会调用我们自己的这个 Hook 处理函数(MyHookNtQuerySystemInformation )了。
这样的话,每次系统调用 NtQuerySystemInformation 这个系统服务时,实质上调用的就是 MyHookNtQuerySystemInformation 了,而我们为了保证系统的稳定性(至少不让其崩溃),一般会在 MyHookNtQuerySystemInformation 中调用系统中原来的服务,也就是NtQuerySystemInformation。
这里借用网上一张图让大家有更加清晰的认识:
![]()
其实Hook的原理差不多都是这样的,替换当前函数地址,修改成自定义的函数地址,然后再调用回原来函数的地址。
二、常用的应用层获取进程的方法
①使用ToolHelp遍历获取到所有进程。
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
②使用 PSAPI 下的 EnumProcesses 获取到所有进程的 PID,然后提升进程权限为 SE_DEBUG 权限,
再调用 OpenProcess 即可打开进程,从而获取到进程的基本信息。
③使用Ntdll.dll 中的未文档化的 API – NtQuerySystemInformation,而Windows 任务管理器就是通过这种方式来获取到所有的进程信息的。
所以隐藏进程最简单的办法就是Hook 掉 NtQuerySystemInformation 函数 。
至于进程保护的话,第一种则是该进程自行终止,第二种情况则是该进程被其他进程给杀掉,第一种情况基本上对于窗口应用程序来说,一般都是用 户点击了右上角的 x 按钮,然后产生 WM_CLOSE 消息,最后由窗口过程退出进程,这种情况下,我们应该是需要允许退出的,也就是进程是可以正常退出的。而第二种情况的话,就是进程被别的进程杀掉,比如在 任务管理器中就可以杀掉绝大部分的应用程序进程,而这里的进程保护就是要实现进程不能够被任务管理器或者其他的进程管理工具杀掉。在 Ring3 中,由一个进程结束其他进程,先会调用API OpenProcess这个我已经在前篇说的很详细了,然后再去调用Kernel32.dll 中的 TerminateProcess,如果追溯这个 TerminateProcess,可以发现,其调用了 Ntdll.dll 中的 NtTerminateProcess API,然后再追溯下去就可以到 ntoskrnl.exe 中的 ZwTerminateProcess 和系统服务NtTerminateProcess 了。所以这里我们选择Hook掉NtTerminateProcess 函数。
三、代码说明
口说还不如来点实际的代码实际。
首先我们来定义SSDT需要用到的结构体:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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 } KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR; //导出由 ntoskrnl.exe 所导出的 SSDT |
在 Hook 任意的系统服务之前,将 SSDT 中的所有系统服务的地址保存或者说是备份到 ULONG 数组中即可。而后在解除 Hook 时,我们就可以从这个 ULONG 数组中取出原有系统服务的地址。
|
1
2 3 4 5 6 |
//定义 SSDT(系统服务描述表) 中服务个数的最大数目
//这里定义为 1024 个,实际上在win7 32是 0x0191个 #define MAX_SYSTEM_SERVICE_NUMBER 1024 //用来保存 SSDT 中所有的旧的服务函数的地址 ULONG oldSysServiceAddr[MAX_SYSTEM_SERVICE_NUMBER]; |
我们还需要备份、安装、解除的函数
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
//=====================================================================================//
//Name: VOID BackupSysServicesTable() // // // //Descripion: 用来备份 SSDT 中原有服务的地址,因为我们在解除 Hook 时需要还原 SSDT 中原有地址 // // // //=====================================================================================// VOID BackupSysServicesTable() { ULONG i; for(i = 0; (i < KeServiceDescriptorTable->ntoskrnl.NumberOfService) && (i < MAX_SYSTEM_SERVICE_NUMBER); i++) //=====================================================================================// EnableWriteProtect(&uOldAttr); SYSCALL_FUNCTION(oldService) = newService; DisableWriteProtect(uOldAttr); return STATUS_SUCCESS; //=====================================================================================// EnableWriteProtect(&uOldAttr); SYSCALL_FUNCTION(oldService) = oldSysServiceAddr[SYSCALL_INDEX(oldService)]; DisableWriteProtect(uOldAttr); return STATUS_SUCCESS; |
然后,SSDT 在内存中是具有只读属性保护的,如果你想修改 SSDT 中的内容,你必须先要解除只读属性,也就是要赋予 SSDT 所在的这块内存具有可写属性才行。而这个属性保存在寄存器CR0的第17位,index为16.如果为1表示只读,置为0才可写。
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
//=====================================================================================//
//Name: VOID DisableWriteProtect() // // // //Descripion: 用来去掉内存的可写属性,从而实现内存只读 // // // //=====================================================================================// VOID DisableWriteProtect(ULONG oldAttr) { _asm { mov eax, oldAttr mov cr0, eax sti; } } //=====================================================================================// _asm //保存原有的 CRO 属性 |
注意到上面有两个很重要的宏,即 SYSCALL_FUNCTION 和 SYSCALL_INDEX 宏。
|
1
2 3 4 5 6 |
//根据 Zw_ServiceFunction 获取 Zw_ServiceFunction 在 SSDT 中所对应的服务的索引号
#define SYSCALL_INDEX(ServiceFunction) (*(PULONG)((PUCHAR)ServiceFunction + 1)) //根据 Zw_ServiceFunction 来获得服务在 SSDT 中的索引号, |
上面的事情做完后, 实现进程隐藏只需要Hook NtQuerySystemInformation函数,并实现我们自定义的函数即可。
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
NTSTATUS HookNtQuerySystemInformation (
__in SYSTEM_INFORMATION_CLASS SystemInformationClass, __out_bcount_opt(SystemInformationLength) PVOID SystemInformation, __in ULONG SystemInformationLength, __out_opt PULONG ReturnLength ) { NTSTATUS rtStatus; pOldNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)oldSysServiceAddr[SYSCALL_INDEX(ZwQuerySystemInformation)]; //执行原来的函数 while(pCurrProcessInfo != NULL) //判断当前遍历的这个进程是否为需要隐藏的进程 //遍历下一个 SYSTEM_PROCESS_INFORMATION 节点 //遍历结束 |
上面我们看到是先调用原来的NtQuerySystemInformation得到返回结果,然后根据我们需要隐藏的进程id,遍历返回结果的进程链表,从链表中摘除该节点,然后在返回给应用层。
从下面的代码中,我们看到在安装 Hook 和解除 Hook 时参数传递进去的是
ZwQuerySystemInformation,这样很有可能会让很多朋友认为我们在 Ring0 下的 Hook 的是
ZwQuerySystemInformation,如果你这样认为的话,那就大错特错了,我们这里传入
ZwQuerySystemInformation ,是因为我们需要调用
SYS_INDEX(ZwQuerySystemInformation)来获得 NtQuerySystemInformation 在 SSDT
中的地址所在的索引号,然后我们根据这个索引号来 Hook
NtQuerySystemInformation,所以我们Hook的是NtQuerySystemInformation!!!
InstallSysServiceHook((ULONG)ZwQuerySystemInformation, (ULONG)HookNtQuerySystemInformation);
进程保护呢其实也是比较简单的,因为从上面一层的调用会传递一个进程句柄下来,而后我们可以根据这个进程句柄来获得进程的
EPROCESS 对象(进程位于执行体层得对象),通过这个 EPROCESS 对象,我们就可以获得这个请求被结束的进程的 PID,我们再判断这个
PID 是否是我们已经保护了的 PID,如果是的话,直接返回一个请求被拒绝即可,而如果这个 PID 未被保护,自然我们就交给原来的
NtTerminateProcess 处理即可。
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
NTSTATUS HookNtTerminateProcess(
__in_opt HANDLE ProcessHandle, __in NTSTATUS ExitStatus ) { ULONG uPID; NTSTATUS rtStatus; PCHAR pStrProcName; PEPROCESS pEProcess; ANSI_STRING strProcName; //通过进程句柄来获得该进程所对应的 FileObject 对象,由于这里是进程对象,自然获得的是 EPROCESS 对象 //保存 SSDT 中原来的 NtTerminateProcess 地址 //通过该函数可以获取到进程名称和进程 ID,该函数在内核中实质是导出的(在 WRK 中可以看到) //通过进程名来初始化一个 ASCII 字符串 if(ValidateProcessNeedProtect(uPID) != -1) //对于非保护的进程可以直接调用原来 SSDT 中的 NtTerminateProcess 来结束进程 return rtStatus; |
四、效果演示
隐藏进程的效果就不演示了,反正隐藏之后在任务管理器就找不到你隐藏的进程了。
如果进程被保护了的话,如果你从任务管理器结束该进程,则会返回:
![]()
本文链接:http://www.blogfshare.com/ssdthook-hide-protect.html
转载提示:除非注明,AloneMonkey的文章均为原创,转载请以链接形式注明作者和出处。谢谢合作!
SSDT Hook实现简单的进程隐藏和保护【转载】的更多相关文章
- 进程隐藏与进程保护(SSDT Hook 实现)(二)
文章目录: 1. 引子 – Demo 实现效果: 2. 进程隐藏与进程保护概念: 3. SSDT Hook 框架搭建: 4. Ring0 实现进程隐藏: 5. Ri ...
- linux进程隐藏手段及对抗方法
1.命令替换 实现方法 替换系统中常见的进程查看工具(比如ps.top.lsof)的二进制程序 对抗方法 使用stat命令查看文件状态并且使用md5sum命令查看文件hash,从干净的系统上拷贝这些工 ...
- HOOK技术之SSDT hook(x86/x64)
x86 SSDT Hook 32位下进行SSDT Hook比较简单,通过修改SSDT表中需要hook的系统服务为自己的函数,在自己的函数中进行过滤判断达到hook的目的. 获取KeServiceDes ...
- 进程隐藏与进程保护(SSDT Hook 实现)(三)
文章目录: 1. 引子: 2. 获取当前系统下所有进程: 3. 服务管理(安装,启动,停止,卸载): 4. 应用程序和内核程序通信: 5. 小结: 1. 引子: 关于这个 SSDT Hook 实现进程 ...
- 进程隐藏与进程保护(SSDT Hook 实现)(一)
读了这篇文章终于明白大致怎么回事了 文章目录: 1. 引子 – Hook 技术: 2. SSDT 简介: 3. 应用层调用 Win32 API 的完整执行流程: 4 ...
- 通过SSDT HOOK实现进程保护和进程隐藏
---恢复内容开始--- 首先,我要说一件很重要的事,本人文采不好,如果哪里说的尴尬了,那你就尴尬着听吧...... SSDT HOOK最初貌似源于Rookit,但是Rookit之前有没有其他病毒使用 ...
- SSDT Hook实现内核级的进程保护
目录 SSDT Hook效果图 SSDT简介 SSDT结构 SSDT HOOK原理 Hook前准备 如何获得SSDT中函数的地址呢 SSDT Hook流程 SSDT Hook实现进程保护 Ring3与 ...
- SSDT Hook结构
目录 SSDT Hook效果图 SSDT简介 SSDT结构 SSDT HOOK原理 Hook前准备 如何获得SSDT中函数的地址呢 SSDT Hook流程 SSDT Hook实现进程保护 Ring3与 ...
- Windows2003 内核级进程隐藏、侦测技术
论文关键字: 内核 拦截 活动进程链表 系统服务派遣表 线程调度链 驱动程序简介 论文摘要:信息对抗是目前计算机发展的一个重要的方向,为了更好的防御,必须去深入的了解敌人进攻的招式.信息对抗促使 ...
随机推荐
- javascript中prototype、constructor以及__proto__之间的三角关系
三者暧昧关系简单整理 在javascript中,prototype.constructor以及__proto__之间有着“著名”的剪不断理还乱的三角关系,楼主就着自己对它们的浅显认识,来粗略地理理以备 ...
- 面试官的七种武器:Java篇
起源 自己经历过的面试也不少了,互联网的.外企的,都有.总结一下这些面试的经验,发现面试官问的问题其实不外乎几个大类,玩不出太多新鲜玩意的.细细想来,面试官拥有以下七种武器.恰似古龙先生笔下的武侠世界 ...
- .net截取两个字符串中间的内容
做模拟登录时,需要截取html代码中的名字,返回的字符串内容如下 <span class="welcome">您好<span style="font-s ...
- java数组的增删改查
import java.util.List; import java.util.ArrayList; import java.util.Set; import java.util.HashSet; p ...
- 每天一个linux命令(9):nl命令
nl命令在linux系统中用来计算文件中行号.nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等 ...
- 事务四大特征:原子性,一致性,隔离性和持久性(ACID)
一.事务 定义:所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位. 准备工作:为了说明事务的ACID原理,我们使用银行账户及资金管理的案例进行分析. [sql] ...
- Eclipse属性文件编辑器---Properties Editor
今天在用 Eclipse 来编辑 .properties 文件时,写的中文会自动转为 Unicode 编码,完全不知道自己的中文写的是什么!! 于是查了一下,网上推荐,在Eclipse 中 安装一个 ...
- Java Filter过滤器的简单总结
1.Filter的介绍 Filter技术是servlet 2.3新增加的功能.它能够对Servlet容器的请求和响应对象进行检查和修改. Filter本身并不生成请求和响应对象,只是提供过滤功能. F ...
- 34.Android之资源文件res里drawable学习
我们经常看到android工程资源文件res下drawable如ldpi.mdpi.hdpi.xhdpi.xxhdpi文件,今天我们学习了解下. (1)drawable-hdpi里面存放高分辨率的图片 ...
- opencv笔记3:trackbar简单使用
time:2015年 10月 03日 星期六 13:54:17 CST # opencv笔记3:trackbar简单使用 当需要测试某变量的一系列取值取值会产生什么结果时,适合用trackbar.看起 ...