打造自己的HOOK引擎 之一 --- SSDT HOOK引擎
SSDT HOOK已经是老生常谈的话题了,这里我就不对其进行介绍了,其实HOOK技术已经被大牛们分析的淋漓尽致,无以复加了,我也只是个初学者,失误之处,还望大牛们多多指教
读者可以通过后面的参考连接得到更多的关于SSDT HOOK的信息
我就相当于在这里对论坛的关于SSDT的精华贴做个总结了 呵呵
【原创】扫盲贴,HOOK SSDT 短文一篇。
【原创】分享比较完整的ROOTKIT DEMO! 原来Shadow Hook和SSDT Hook一样容易!
【原创】SSDT Hook的妙用-对抗ring0 inline hook
【原创】寻找原始表,恢复 ssdt 表
【原创】RootKit hook之[二] SSDT hook
【原创】用DDDK编写驱动,修改SSDT表HOOK NTDebugActiveProcess函数
【转帖】城里城外看SSDT
关于HOOK的文章实在是太多了,但是不同的文章由于作者的不同,导致文章的写作风格不同,代码的风格也各不相同,这样就导致了同样的技术,不同的作者用代码表现出来的形式却大相径庭,这样对我们初学者来讲实在是很不方便,于是便有了打造自己的HOOK引擎的想法,将技术细节封装起来,因为这个本来就不用去修改,需要修改的仅仅是用户自定义的HOOK例程
这个也就是我的HOOK引擎的基本思想,将HOOK的具体实现封装在引擎中,用户想HOOK某个函数时,不用去想HOOK的技术细节了,直接编写自己的HOOK函数然后调用引擎提供的某个接口即可
因为是第一次写,就写个最简单的,SSDT的HOOK
譬如如果用户想把NtOpenProcess HOOK成自己的MyNtOpenProcess
用户只需要在DriverEntry中调用HookService((ULONG)ZwOpenProcess, (ULONG)MyNtOpenProcess)
然后编写自己的钩子函数即可 接口很简单也易于实现
这里是个调用的例子
// Unload例程 卸载钩子 VOID Unload(IN PDRIVER_OBJECT DriverObject) { KdPrint(("Unload Routine.\n")); UnHookService((ULONG)ZwSetInformationFile); UnHookService((ULONG)ZwOpenProcess); } // DriverEntry例程 初始化并安装钩子 NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { DriverObject->DriverUnload = Unload; InitServicesTable(); HookService((ULONG)ZwSetInformationFile, (ULONG)MyZwSetInformationFile); HookService((ULONG)ZwOpenProcess, (ULONG)MyNtOpenProcess); return STATUS_SUCCESS; }
// 定义HOOK的函数原型 typedef NTSTATUS (__stdcall *ZWSETINFORMATIONFILE)(IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass); typedef NTSTATUS (__stdcall *NTOPENPROCESS)( OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId); // 对于ntddk.h中未定义的函数 // 可以根据<<Undocument>>一书在这里给出定义 NTSYSAPI NTSTATUS NTAPI ZwOpenProcess( OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId); // ============================================================== // 用户自定义HOOK例程 NTSTATUS MyZwSetInformationFile(IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass) { PFILE_OBJECT pFileObject; // 在OldServiceAddressTable中取出原服务函数地址 ZWSETINFORMATIONFILE OldZwSetInformationFile = (ZWSETINFORMATIONFILE)OldServiceAddressTable[SERVICE_ID(ZwSetInformationFile)]; NTSTATUS ret = ObReferenceObjectByHandle(FileHandle, GENERIC_READ, *IoFileObjectType, KernelMode, (PVOID*)&pFileObject, 0); if(NT_SUCCESS(ret)) { KdPrint(("%S opened.\n", pFileObject->FileName.Buffer)); if (wcsstr(pFileObject->FileName.Buffer, L"test.txt")) { KdPrint(("test.txt opened. Deny it.\n")); return STATUS_ACCESS_DENIED; } } ObDereferenceObject(pFileObject); // 调用原服务函数 return OldZwSetInformationFile( FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); } NTSTATUS MyNtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId ) { NTSTATUS rc; ULONG PID; KPROCESSOR_MODE PreMode; NTOPENPROCESS OldNtOpenProcess = (NTOPENPROCESS)OldServiceAddressTable[SERVICE_ID(ZwOpenProcess)]; PreMode = ExGetPreviousMode(); if(PreMode != KernelMode) { __try { ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); } __except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } if(ClientId != NULL) { PID = (ULONG)ClientId->UniqueProcess; if(PID > 1000) { return STATUS_ACCESS_DENIED; } } return OldNtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); }
然后说明一点,就是HookService()的第一个参数都应该是以Zw开头的函数,因为代码是根据这个函数来计算服务ID的
还有就是在调用HookService()之前应该先调用InitServicesTalbe()来对SSDT进行一次性的保存,避免后面多次HOOK就要保存多次
附件中是全部代码 写的很烂 还望大大们批评指正。