Windows内核新手上路1――挂钩SSDT

Windows内核新手上路1――挂钩SSDT

        这个系列记录学习我学习windows内核的点点滴滴,高手请直接无视。

        文章核心内容:挂钩SSDT中函数列NtOpenProcess,NtDuplicateObject,NtCreateThread,NtOpenThread,NtWriteVirtualMemory,过滤进程操作来保护目标进程空间。

 

SSDT的全称是System Services Descriptor Table,系统服务描述符表。这个表把ring3的Win32 API和ring0的内核API联系起来。SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。

SSDT管的是与系统相关的函数(kernel32.dll、ntdll.dll)。通过修改此表的函数地址可以对常用windows函数及API进行hook,从而实现对一些关心的系统动作进行过滤、监控的目的。一些HIPS、防毒软件、系统监控、注册表监控软件往往会采用此接口来实现自己的监控模块。

SSDT在Win32子系统的内核实现是NTOSKRNL.EXE,导出表名是 KeServiceDescriptorTable,对应系统进程一般有System

SSDT结构:

typedef struct tagSSDT {

PULONG pSSDTBase;                                  //SSDT在内存中的基址

PVOID    pServiceCounterTable;

ULONG  uNumberOfServices;                 //SSDT项个数

PUCHAR         pParamTableBase;

} SSDT, *PSSDT; //SSDT

1    如何挂钩SSDT

首先关闭CR0写保护(通过改变CR0寄存器的WP位),然后用新的函数地址替换原来SSDT中的函数地址,最后恢复CR0写保护。

挂钩SSDT中函数列NtOpenProcess,NtDuplicateObject,NtCreateThread,NtOpenThread,NtWriteVirtualMemory,过滤进程操作来保护目标进程空间。

1.1NtOpenProcess

在Windows操作系统中,kernel32!OpenProcess通过调用ntdll!NtOpenProcess最终转到内核态的nt!NtOpenProcess,通过挂钩NtOpenProcess,可以过滤和拦截进程打开其他进程的操作。

在自定义的NtOpenProcess函数中,首先获取要打开的进程PID,判断该PID是否是被保护的进程,如果是被保护的进程,则去掉打开权限中的相应权限,如果是打开本系统R3进程,还要去掉结束进程的权限,最终,再调用真实的NtOpenProcess函数,最后返回给R3的进程句柄就无法读写操作受保护的进程,恶意程序也无法结束目标进程。

通过进程句柄获取PID

判断是否受保护的PID

如果是

        做一些权限的处理….

        调用真实NtOpenProcess

如果否

        调用真实的NtCreateThread

代码1.1 MyNtOpenProcess

1.2NtDuplicateObject

Windows系统提供了一个函数DuplicateHandle,用于从其他进程复制一个句柄到当前进程,而且csrss.exe进程会保存所有进程的句柄,通过调用DuplicateHandle从csrss中复制句柄,可以间接的达到调用OpenProcess获取目标进程句柄的目的。

在定义的NtDuplcateObject函数中,首先调用真实的NtDuplicateObject,如果调用成功,判断最后返回的句柄是不是受保护进程的句柄,如果是受保护的进程句柄,则关闭之。通过这样的过滤,恶意程序无法通过调用DuplicateHandle来打开受保护的进程。

1.3NtCreateThread

R3中在进程中和其他进程中创建线程(分别调用CreateThread和CreateRemoteThread)最终通过ntdll!NtCreateThread转到内核态的nt!CreateThread,通过过滤nt!CreateThread可以防止恶意程序在受保护的进程中创建远程线程(即调用CreateRemoteThread)。实现的MyNtCreateThread处理流程如代码1.2所示:

通过进程句柄获取PID

判断是否受保护的PID

如果是

        返回STATUS_ACCESS_DENIED

如果否

        调用真实的NtCreateThread

代码1.2 MyNtCreateThread

1.4NtOpenThread

在windows操作系统中,通过调用OpenThread可以获取目标线程的句柄,进一步通过此句柄操作目标线程。防密码窃取系统挂钩了NtOpenThread来防止恶意程序操作受保护进程的线程。

在自定义的NtOpenThread函数中,首先获取线程所在进程的PID,然后判断该PID是否被保护,如果是被保护的PID,则直接返回STATUS_ACCESS_DENIED,否则调用真实的NtOpenThread。

1.5NtWriteVirtualMemory

在windows操作系统中,进程可以调用kernel32!WriteProcessMemory来写其他进程内存,kernel32!WriteProcessMemory通过ntdll!NtWriteVirtualMemory转到内核态的nt!NtWriteVirtualMemory。通过挂钩nt!NtWriteVirtualMemory来防目恶意程序写受保护的进程内存。伪代码如代码1.3所示。

通过进程句柄获取PID

判断是否受保护的PID

如果是

        返回STATUS_ACCESS_DENIED

如果否

        调用真实的NtWriteVirtualMemory

代码1.3 MyNtWriteVirtualMemory

你可能感兴趣的:(Windows内核新手上路1――挂钩SSDT)