查看: 694|回复: 5

[原创] 浅谈使用SSDT-HOOK保护进程

[复制链接]

4

技术

17

魅力

6

原创

版主

禁止发言

Rank: 7Rank: 7Rank: 7

积分
5370
人气
208
分享
36

最佳新人活跃会员

发表于 2022-8-28 02:29:58 | 显示全部楼层 |阅读模式
本帖最后由 YFSafe 于 2022-8-28 02:34 编辑

首先我们说下hook,什么是hook?hook的英文已经说明了,hook在英文中是钩的意思,计算机取其意叫钩子,而我的理解叫拦截
大家应该写过ring3下的程序,估计也写过一些ring3的hook.例如有一个API是OpenProcess,功能是打开进程得到进程句柄,比如我们要结束一个进程,需要调用TerminateProcess这个api,就必须知道进程的句柄
根据以上原理,我们可以写一下结束进程的伪代码
[AppleScript] 纯文本查看 复制代码
push PID       

push 0

push 114514 ;这个值代表权限

call OpenProcess

push 0

push eax

call TerminateProcess
执行这段代码,如果正常的话,对应这个pid的进程应该就会被结束.这里我们来设想一下:假如我是一个恶意软件,我要防止我自身被结束,那我的最好办法应该是什么?
在这里思考一下,然后我们继续往下走.

我们可以在call openprocess这里做一个修改,接管原来的openprocess,将每次调用的函数修改成我们自己的.写出如下代码:
[AppleScript] 纯文本查看 复制代码
push PID
push 0
push 114514
call MyOpenProcess
push 0
push eax
call TerminateProcess
myopenprocess是我们自己实现的函数.这个函数跟OpenProcess一样,也有三个参数,也有相同的返回值类型.在这个函数里,我把传入的三个参数(内核中的openprocess是四个参数,这里用用户层的openprocess讲原理)传递给真正的OpenProcess,而把OpenProcess的返回值做为myopenprocess的返回值,那么这套流程下来肯定也是可以执行的,写出如下的代码:
[C++] 纯文本查看 复制代码
HANDLE MyOpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId)
{
     return OpenProcess(dwDesiredAccess,bInheritHandle,dwProcessId);
}
有一些帅气的同学可能要问了:这样做执行是可以执行,但是何必费力做一个包装函数,再调用原函数?这样的意义是什么?
现在这套流程下来非常正常,我们做的这个包装函数没有意义.但是现在我们假设,如果有一个恶意进程PID=1145,你需要写个结束程序来结束这个PID=1145的进程,这个恶意进程却给你安装了这个拦截.但是,它稍微的修改了下函数,变成这样:
[C++] 纯文本查看 复制代码
HANDLE MyOpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId)
{
     if(dwProcessId == 1145)
     {
          return NULL;
     }
     return OpenProcess(dwDesiredAccess,bInheritHandle,dwProcessId);
}
这样下来,会怎么样?你还能结束恶意进程吗?
当然不能
因为你如果打开PID为1145的进程时候,得不到正确的句柄返回值,返回值为NULL.
这个方法叫hook.我们也可以在OpenProcess的函数头进行hook.
而我把这种方法叫拦截.截获后,可阻止,可改变,可放行.hook,无非是截获流程,根据自己的需要替换,阻止,放行而已
r3层的r0层的hook原理一样,大道至简,现在很多教驱动开发的讲hook一上来就说内核,ssdt,弄的大家一头雾水.驱动hook就是截获api在内核的执行流程,然后根据自己的需要替换,阻止,放行. 理论上你会r3的hook,你一定会r0的hook

明白了HOOK原理后,那么内核hook就很简单了,只要我们在API函数执行流程走到内核后在内核流程中进行截断,处理,就是内核hook了
我们在内核流程的位置选择了SSDT表,那么,SSDT表是什么?
SSDT(System Services Descriptor Table),系统服务描述符表。这个表就是一个把ring3的Win32 API和ring0的内核API联系起来。SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。
现在我们以OpenProcess来说明,看下SSDT表在函数执行流程中起的作用!
函数的执行流程以OpenProcess是这样.先说明,下面再解释
#r3 OpenProcess进入ntdll.dll的NtOpenProcess或ZwOpenProcess函数(是同一个地址)
#进入内核
#进入Ntoskrnl.exe的ZwOpenProcess
#根据ZwOpenProcess的索引值,在SSDT表中找到对应的地址,再根据SSDT表对应地址的数据(Ntoskrnl.exe的NtOpenProcess)执行函数
#也就是Ntoskrnl.exe的NtOpenProcess才是真正的执行主体
函数在由R3进R0后,要通过SSDT表来选择最终执行的内核函数.假设我们想在内核中HOOK OpenProcess这个函数,只需要修改ssdt表中存放的NtOpenProcess地址,放入我们自己写的newNtOpenProcess函数地址.在我们newNtOpenProcess函数中,进行了修改或替换或阻止或放行后执行真正的NtOpenProcess.这就是所谓的SSDT hook
简单说下ssdt表中 hook OpenProcess这个函数的步骤
1.先得到Ntoskrnl.exe的NtOpenProcess函数的地址(用MmGetSystemRoutineAddress函数得到内核导出函数地址)
2.再得到SSDT表中Ntoskrnl.exe的NtOpenProcess函数应该存放的位置
   (SSDT表的开始地址) +(索引)* 4(每个函数的间隔)
     SSDT表的开始地址 = [KeServiceDescriptorTable->SSDT表的指针]  
     索引 = [Ntoskrnl.exe的zwOpenProcess地址+1]
3.自己建立一个新函数,参数和返回值要和Ntoskrnl.exe的NtOpenProcess函数一模一样
4.把自己的新函数地址写到SSDT表中我们算出来的存放位置处(mov[(SSDT表的开始地址) + (索引) * 4(每个函数的间隔)],新函数地址)
代码如下(只给出关键代码):
声明挂钩宏:
[C++] 纯文本查看 复制代码
#pragma pack(1)        //SSDT表的结构
typedef struct ServiceDescriptorEntry {
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase; //Used only in checked build
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
PMDL m_MDL;
PVOID *m_Mapped;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;        //变量名是不能变的,因为是从外部导入
#define SYSTEMSERVICE(_function)  KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
#define HOOK_SYSCALL(_Function, _Hook, _Orig )  \
       _Orig = (PVOID) InterlockedExchange( (PLONG) &m_Mapped[SYSCALL_INDEX(_Function)], (LONG) _Hook)
声明需要被hook的函数:
[C++] 纯文本查看 复制代码
//新加
NTSYSAPI NTSTATUS NTAPI
  ZwOpenProcess(
    OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL
    );
 
typedef  (*ZWOPENPROCESS)(
    OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL
    );                 
        
ZWOPENPROCESS RealZwOpenProcess=NULL;        
ZWOPENPROCESS  OldZwOpenProcess=NULL;
挂载钩子:
[C++] 纯文本查看 复制代码
HOOK_SYSCALL(ZwOpenProcess,HookZwOpenProcess,RealZwOpenProcess);
恢复钩子:
[C++] 纯文本查看 复制代码
PVOID Oldfun = NULL;
HOOK_SYSCALL(ZwOpenProcess,RealZwOpenProcess,Oldfun);
HookZwOpenProcess的实现:
[C++] 纯文本查看 复制代码
NTSTATUS
HookZwOpenProcess(
OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL
)
{
     if(ClientId.UniqueProcess == 1145)
     {
          return STATUS_ACCESS_DENIED;
     }
     return ((ZWOPENPROCESS)(RealZwOpenProcess))(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);
}

评分

参与人数 3经验 +30 人气 +6 收起 理由
xiaomeng + 30
explore + 3 膜拜,赞一个!
xiaomeng242 + 3 很给力!

查看全部评分

YF工作室驻x64论坛分部
工作室曾开发的软件:YFSafe安全软件,YFChat在线聊天软件,MBRTools等。
欢迎有能力的你加入我们一起共同进步。请发邮件至yfstudio2021@outlook.com

0

技术

1

魅力

0

原创

略知一二

Rank: 3Rank: 3

积分
902
人气
25
分享
0
发表于 2022-8-28 13:37:25 | 显示全部楼层
汇编语言??????

4

技术

17

魅力

6

原创

版主

禁止发言

Rank: 7Rank: 7Rank: 7

积分
5370
人气
208
分享
36

最佳新人活跃会员

 楼主| 发表于 2022-8-28 13:50:31 | 显示全部楼层
xiaomeng242 发表于 2022-8-28 13:37
汇编语言??????

不需要用到汇编
开始的汇编只是伪代码
YF工作室驻x64论坛分部
工作室曾开发的软件:YFSafe安全软件,YFChat在线聊天软件,MBRTools等。
欢迎有能力的你加入我们一起共同进步。请发邮件至yfstudio2021@outlook.com

0

技术

1

魅力

0

原创

略知一二

Rank: 3Rank: 3

积分
902
人气
25
分享
0
发表于 2022-8-28 16:12:21 | 显示全部楼层
YFSafe 发表于 2022-8-28 13:50
不需要用到汇编
开始的汇编只是伪代码

啥是伪代码?

好高级

0

技术

7

魅力

1

原创

网站编辑

我最可铐

Rank: 8Rank: 8

积分
6877
人气
217
分享
594

最佳新人活跃会员

发表于 2022-8-28 17:01:55 | 显示全部楼层
xiaomeng242 发表于 2022-8-28 16:12
啥是伪代码?

好高级

解释流程用的,粗浅理解就是把程序用人话翻译一遍
(我怎么感觉流程图其实也可以算伪代码。。。)

基本目的是让讲不同语言的猿能理解同一段程序

评分

参与人数 1经验 +10 收起 理由
YFSafe + 10 精辟

查看全部评分

0

技术

1

魅力

0

原创

略知一二

Rank: 3Rank: 3

积分
902
人气
25
分享
0
发表于 2022-8-28 18:01:02 | 显示全部楼层
explore 发表于 2022-8-28 17:01
解释流程用的,粗浅理解就是把程序用人话翻译一遍
(我怎么感觉流程图其实也可以算伪代码。。。) ...

懂了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表