【网络安全】网络安全编程:HOOK SSDT

科技工作者之家 2021-06-28

SSDT把用户层的Win32 API与内核层的Native API做了一个关联,而整个Native API都保存在SSDT中的一个函数指针数组中,只要修改函数指针数组中的某一项,就相当于HOOK了某个Native API函数。比如,修改SSDT中函数指针数组中的最后一个函数指针,就相当于HOOK了NtQueryPortInformationProcess()函数。


下面HOOK一个比较熟悉的函数,即创建进程函数NtCreateProcessEx()。该函数在指针数组的第0x30项(该编号根据系统版本的不同而不同,是系统相关的)。通过编程获取SSDT表,然后找到Native API的函数指针数组,再修改其中第0x30项的内容为自己的函数地址。为了不影响进程的正常创建,在函数中调用NtCreateProcessEx()函数。代码如下:

#include <ntddk.h>typedef struct _SERVICE_DESCRIPTOR_TABLE{ PULONG ServiceTableBase; PULONG ServiceCounterTableBase; ULONG NumberOfServices; PUCHAR ParamTableBase;}SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE;extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;typedef NTSTATUS (*NTCREATEPROCESSEX)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,HANDLE, ULONG, HANDLE, HANDLE, HANDLE, ULONG);// 保存 NtCreateProcessEx 函数的地址NTCREATEPROCESSEX ulNtCreateProcessEx = 0;// 在指针数组中 NtCreateProcessEx 的地址ULONG ulNtCreateProcessExAddr = 0;VOID UN_PROTECT(){ __asm { push eax mov eax, CR0 and eax, 0FFFEFFFFh mov CR0, eax pop eax }}VOID RE_PROTECT(){ __asm { push eax mov eax, CR0 or eax, 0FFFEFFFFh mov CR0, eax pop eax }}VOID DriverUnload(PDRIVER_OBJECT pDriverObject){ UN_PROTECT(); // 替换 NtCreateProcessEx 的地址为 MyNtCreateProcessEx *(PULONG)ulNtCreateProcessExAddr = (ULONG)ulNtCreateProcessEx; RE_PROTECT();}NTSTATUSMyNtCreateProcessEx( __out PHANDLE ProcessHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in HANDLE ParentProcess, __in ULONG Flags, __in_opt HANDLE SectionHandle, __in_opt HANDLE DebugPort, __in_opt HANDLE ExceptionPort, __in ULONG JobMemberLevel){ NTSTATUS Status = STATUS_SUCCESS; KdPrint(("Enter MyNtCreateProcessEx! \r\n")); Status = ulNtCreateProcessEx(ProcessHandle, DesiredAccess, ObjectAttributes, ParentProcess, Flags, SectionHandle, DebugPort, ExceptionPort,  JobMemberLevel);  return Status;}VOID HookCreateProcess(){ ULONG ulSsdt = 0; // 保存 NtCreateProcess 的地址 // 获取 SSDT ulSsdt = (ULONG)KeServiceDescriptorTable->ServiceTableBase; // 获取 NtCreateProcessEx 地址的指针 ulNtCreateProcessExAddr = ulSsdt + 0x30 * 4; // 备份 NtCreateProcessEx 的原始地址 ulNtCreateProcessEx = (NTCREATEPROCESSEX) *(PULONG)ulNtCreateProcessExAddr; UN_PROTECT(); // 替换 NtCreateProcessEx 的地址为 MyNtCreateProcessEx *(PULONG)ulNtCreateProcessExAddr = (ULONG)MyNtCreateProcessEx; RE_PROTECT();}NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath ){ NTSTATUS Status = STATUS_SUCCESS; pDriverObject->DriverUnload = DriverUnload; HookCreateProcess(); return Status;}

DriverEntry()中调用了HookCreateProcess()函数,该函数的作用是将指针数组中NtCreateProcessEx()函数的地址替换为MyNtCreateProcessEx()函数的地址。而MyNtCreateProcessEx()函数是用来取代NtCreateProcessEx()函数的函数,在这里的函数中调用了一条KdPrint()用于输出代码。整个HOOK的过程非常简单,只要找到指针数组的位置,保存原地址后修改为新的地址即可。代码中出现了两个函数,分别是UN_PROTECT()和RE_PROTECT()。这两个函数的作用是禁止和开启CPU向标志为只读的内存页进行写入的操作。执行UN_PROTECT后, CPU可以向标志为只读的内存页进行写入操作。当写入完成后,调用RE_PROTECT()函数恢复到原来的状态。把它放到虚拟机中,打开DebugView,然后加载该驱动,加载成功后随便运行一个可执行程序。可以看到,DebugView中显示了在MyNtCreateProcessEx()中的输出,如图1所示,说明HOOK成功了。

图1  MyNtCreateProcessEx()函数的输出


来源:计算机与网络安全


来源:gh_c593f21141e2 鹤岗科普

原文链接:http://mp.weixin.qq.com/s?__biz=MzUxNDUzOTk5Mw==&mid=2247514697&idx=8&sn=e24e5c0baad563bf5868c92eaa4825a4

版权声明:除非特别注明,本站所载内容来源于互联网、微信公众号等公开渠道,不代表本站观点,仅供参考、交流、公益传播之目的。转载的稿件版权归原作者或机构所有,如有侵权,请联系删除。

电话:(010)86409582

邮箱:kejie@scimall.org.cn