也谈SSDT Hook(二)
一、实战篇
本不想摘代码,既然实战,就不多讲废话了,还是贴上吧,谁都有违背原则的时候:)。
代码一:经典案例,替换NtQuerySystemInformation,列取所有查询到的进程名,我使用修改CR0寄存器的方法。
#include <ntddk.h>
typedef struct _SYSTEM_THREADS
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientIs;
KPRIORITY Priority;
KPRIORITY BasePriority;
ULONG ContextSwitchCount;
ULONG ThreadState;
KWAIT_REASON WaitReason;
}SYSTEM_THREADS, *PSYSTEM_THREADS;
typedef struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters;
struct _SYSTEM_THREADS Threads[1];
}SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
NTSTATUS NewNtQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
// SDT Structure
typedef struct _ServiceDescriptorTableEntry
{
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
// import KeServiceDescriptorTable
extern PServiceDescriptorTableEntry KeServiceDescriptorTable;
PServiceDescriptorTableEntry pSDT;
// real NtQuerySystemInformation
typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
NTQUERYSYSTEMINFORMATION OldNtQuerySystemInformation;
UNICODE_STRING usLinkDeviceNameString;
VOID UnloadDriver(IN PDRIVER_OBJECT pDriverObject)
{
ULONG _cr0;
PDEVICE_OBJECT pDeviceObject;
// recovery SSDT
_asm
{
// WP off
cli
mov eax, cr0
mov _cr0, eax
and eax, 0fffeffffh
mov cr0,eax
// recovery SSDT
mov ecx, DWORD PTR [ZwQuerySystemInformation]
mov edx, [ecx+1]
mov eax, DWORD PTR [pSDT];
mov esi, [eax]
mov ebx, DWORD PTR [OldNtQuerySystemInformation]
mov [esi+edx*4],ebx
// WP on
mov eax, _cr0
mov cr0, eax
sti
}
pDeviceObject= pDriverObject->DeviceObject;
IoDeleteSymbolicLink(&usLinkDeviceNameString);
ASSERT(!pDeviceObject->AttachedDevice);
if ( pDeviceObject != NULL )
{
IoDeleteDevice(pDeviceObject);
}
}
NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING usRegistryPath)
{
ULONG _cr0;
NTSTATUS ntStatus;
PDEVICE_OBJECT pDeviceObject;
UNICODE_STRING usDeviceNameString;
RtlInitUnicodeString(&usDeviceNameString, L"//Device//SSDTHOOK" );
RtlInitUnicodeString(&usLinkDeviceNameString, L"//DosDevices//SSDTHOOK" );
ntStatus = IoCreateDevice(
pDriverObject,
0,
&usDeviceNameString,
FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&pDeviceObject);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = IoCreateSymbolicLink(&usLinkDeviceNameString,&usDeviceNameString);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(pDeviceObject);
return ntStatus;
}
pDriverObject->DriverUnload=UnloadDriver;
pSDT = KeServiceDescriptorTable;
// modify SSDT
_asm
{
// WP off
cli
mov eax, cr0
mov _cr0, eax
and eax, 0fffeffffh
mov cr0, eax
// replace NtQuerySystemInformation with NewNtQuerySystemInformation
mov ecx, DWORD PTR [ZwQuerySystemInformation]
mov edx, [ecx+1]
mov eax, DWORD PTR [pSDT]
mov esi, [eax]
mov edx, [esi+edx*4]
mov DWORD PTR [OldNtQuerySystemInformation], edx
mov ecx, [ecx+1]
mov eax, [eax]
mov dword ptr [eax+ecx*4], offset NewNtQuerySystemInformation
// WP on
mov eax, _cr0
mov cr0, eax
sti
}
return ntStatus;
}
NTSTATUS NewNtQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength)
{
ANSI_STRING asProcessName;
NTSTATUS ntQuerySystemInformation = (OldNtQuerySystemInformation)
(SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength);
if(NT_SUCCESS(ntQuerySystemInformation))
{
if(5 == SystemInformationClass)
{
PSYSTEM_PROCESSES curr = (PSYSTEM_PROCESSES)SystemInformation;
PSYSTEM_PROCESSES prev = NULL;
if(curr->NextEntryDelta)((char *)curr += curr->NextEntryDelta);
while(curr)
{
RtlUnicodeStringToAnsiString(&asProcessName, &(curr->ProcessName), TRUE);
DbgPrint(asProcessName.Buffer);
RtlFreeAnsiString(&asProcessName);
if(curr != NULL)
{
prev = curr;
if(curr->NextEntryDelta)((char *)curr += curr->NextEntryDelta);
else curr = NULL;
}
}
}
}
return ntQuerySystemInformation;
}
案例二:修改SDT中NtCreateSection的地址,列出所有创建SECTION的文件名称,我使用了MDL。其实,搞进程很麻烦凡的,windows的大麻烦之一。
#include <ntddk.h>
NTSYSAPI
NTSTATUS
NTAPI ZwCreateSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN PLARGE_INTEGER MaximumSize OPTIONAL,
IN ULONG SectionPageProtection,
IN ULONG AllocationAttributes,
IN HANDLE FileHandle OPTIONAL);
NTSTATUS NewNtCreateSection(
OUT PHANDLE SectionHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN PLARGE_INTEGER MaximumSize OPTIONAL,
IN ULONG PageAttributess,
IN ULONG SectionAttributes,
IN HANDLE FileHandle OPTIONAL);
// SDT Structure
#pragma pack(1)
typedef struct _ServiceDescriptorTableEntry
{
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
#pragma pack()
__declspec(dllimport) ServiceDescriptorTableEntry KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]
// real NtCreateSection
typedef NTSTATUS (*NTCREATESECTION)(
OUT PHANDLE SectionHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN PLARGE_INTEGER MaximumSize OPTIONAL,
IN ULONG PageAttributess,
IN ULONG SectionAttributes,
IN HANDLE FileHandle OPTIONAL);
NTCREATESECTION OldNtCreateSection;
UNICODE_STRING usLinkDeviceNameString;
// MDL define
PMDL g_pmdlSystemCall;
PVOID *pMappedSystemCallTable;
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
#define HOOK_SYSCALL(_Function, _Hook, _Orig)/
_Orig = (PVOID) InterlockedExchange( (PLONG) &pMappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
#define UNHOOK_SYSCALL(_Function, _Hook, _Orig)/
InterlockedExchange( (PLONG) &pMappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
VOID UnloadDriver(IN PDRIVER_OBJECT pDriverObject)
{
PDEVICE_OBJECT pDeviceObject;
// recovery SSDT
UNHOOK_SYSCALL(ZwCreateSection, OldNtCreateSection, NewNtCreateSection);
// Unlock and Free MDL
if(g_pmdlSystemCall)
{
MmUnmapLockedPages(pMappedSystemCallTable, g_pmdlSystemCall);
IoFreeMdl(g_pmdlSystemCall);
}
pDeviceObject= pDriverObject->DeviceObject;
IoDeleteSymbolicLink(&usLinkDeviceNameString);
ASSERT(!pDeviceObject->AttachedDevice);
if ( pDeviceObject != NULL )
{
IoDeleteDevice(pDeviceObject);
}
}
NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING usRegistryPath)
{
NTSTATUS ntStatus;
PDEVICE_OBJECT pDeviceObject;
UNICODE_STRING usDeviceNameString;
RtlInitUnicodeString(&usDeviceNameString, L"//Device//SSDTHOOK" );
RtlInitUnicodeString(&usLinkDeviceNameString, L"//DosDevices//SSDTHOOK" );
ntStatus = IoCreateDevice(
pDriverObject,
0,
&usDeviceNameString,
FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&pDeviceObject);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = IoCreateSymbolicLink(&usLinkDeviceNameString,&usDeviceNameString);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(pDeviceObject);
return ntStatus;
}
pDriverObject->DriverUnload=UnloadDriver;
OldNtCreateSection =(NTCREATESECTION)(SYSTEMSERVICE(ZwCreateSection));
g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
if(!g_pmdlSystemCall) return STATUS_UNSUCCESSFUL;
MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
// Change the flags of the MDL
g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
pMappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);
// hook system calls
HOOK_SYSCALL(ZwCreateSection, NewNtCreateSection, OldNtCreateSection);
return ntStatus;
}
NTSTATUS NewNtCreateSection(
OUT PHANDLE SectionHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN PLARGE_INTEGER MaximumSize OPTIONAL,
IN ULONG PageAttributess,
IN ULONG SectionAttributes,
IN HANDLE FileHandle OPTIONAL)
{
HANDLE hHandle;
PFILE_OBJECT pFileObject;
OBJECT_HANDLE_INFORMATION HandleInformationObject;
ANSI_STRING asFileName;
hHandle=(HANDLE)FileHandle;
ObReferenceObjectByHandle(hHandle,0,0,KernelMode,&pFileObject,&HandleInformationObject);
if(pFileObject != NULL)
{
RtlUnicodeStringToAnsiString(&asFileName,&(pFileObject->FileName),TRUE);
DbgPrint(asFileName.Buffer);
RtlFreeAnsiString(&asFileName);
}
return ((NTCREATESECTION)(OldNtCreateSection))(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, PageAttributess, SectionAttributes, FileHandle);
}
以上两个例子都是在XP SP2下测试,用来验证第一部分我说的那些废话。代码本身没任何破坏性,有兴趣可以尝试,如有疑问欢迎交流。
二、Anti-SSDT Hook
小学时,课本有一篇寓言《自相矛盾》,当时觉得不可思议,像现在想来,矛与盾的较量永未停止。对SSDT Hook最终都要修改掉KeServiceDescriptorTable的成员ServiceTableBase所指向的内存空间的Nt*系列函数地址,那么只要扫描这段内存空间,抓出非法居民即可。原理是这样的。
先看看‘ROOTKITS: SUVVERING THE WINDOWS KERNEL’的高招。首先,获取ntoskrnl.exe模块的内存地址范围,如果所检测的SDT中的函数地址不在这个范围内就是被HOOK了。不再重复人家的代码了。
Tan Chew Keong在他的’Win2K/XP SDT Restore’大作中的基本思路是不变的,但是,他的SDT是在ntoskrnl.exe的原始文件中加载的,然后使用这个SDT跟操作系统内核中正在使用的那个进行对比,这样更精确到位,而且可以对可疑的HOOK进行恢复。相关代码在网络上有提供。这种加载SDT的方法是90210在rootkit.com中‘A more stable way to locate real KiServiceTable’提出来的。
其他的方法我在师还没有注意到,应该是有的,如果发现新方法,欢迎交流。
三、参考资料
1. ‘ROOTKITS: SUVVERING THE WINDOWS KERNEL’, Greg Hoglund, James Butler
2. ‘Defeating Kernel Native API Hookers by Direct KiServiceTable Restoration’, Tan Chew Keong
3. ‘Win2K/XP SDT Restore 0.2 (Proof-Of-Concept)’, Tan Chew Keong
4. ‘SDT Hooking 무력화에 대한 연구’, Dual5651
‘A more stable way to locate real KiServiceTable’, 90210
也谈SSDT Hook(二)相关推荐
- 也谈SSDT Hook(一)
一.原理篇 1. 关于系统服务. 系统服务是由操作系统提供一组函数,使得开发者能够通过APIs直接或间接的调用.一个API可以对应一个系统服务,也可以一个API依赖多个系统服务. ...
- 进程隐藏与进程保护(SSDT Hook 实现)(二)
文章目录: 1. 引子 – Demo 实现效果: 2. 进程隐藏与进程保护概念: 3. SSDT Hook 框架搭建: 4. Ring0 实现进程隐藏: 5. Ring0 实现进程保护: 6. 隐藏进 ...
- 进程隐藏与进程保护(SSDT Hook 实现)(二) 转载自 Zachary.XiaoZhen - 梦想的天空
文章目录: 1. 引子 – Demo 实现效果: 2. 进程隐藏与进程保护概念: 3. SSDT Hook 框架搭建: 4. Ring0 实现进程隐藏: 5. Ri ...
- Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)
SHADOW SSDT HOOK HOOK 和 UNHOOK SHADOW SSDT 跟之前的 HOOK/UNHOOK SSDT 类似,区别是查找SSSDT的特征码,以及根据索引计算函数地址的公式,还 ...
- (52)系统调用阶段测试——基于 SSDT HOOK 的 FindWindowA 监视器
一.项目说明 SSDT HOOK 内核函数我们已经会了,请看这两篇博客: SSDT HOOK 实现进程保护 补充内容:SSDT HOOK 模板 此次考试和 hook NtOpenProcess 或 N ...
- (51)SSDT HOOK 实现进程保护
一.回顾 在前面的课程里,我们逆向分析了 KiSystemService / KiFastCallEntry 的部分代码,我们发现这两个函数找系统服务表 SystemServiceTable 的方法是 ...
- Windows驱动开发学习笔记(五)—— SSDT HOOK
Windows驱动开发学习笔记(五)-- SSDT HOOK 系统服务表 系统服务描述符表 实验一:通过代码获取SSDT表地址 通过页表基址修改页属性 方法1:修改页属性 方法2:修改CR0寄存器 实 ...
- 进程隐藏与进程保护(SSDT Hook 实现)(三)
文章目录: 1. 引子: 2. 获取当前系统下所有进程: 3. 服务管理(安装,启动,停止,卸载): 4. 应用程序和内核程序通信: 5. 小结: 1. 引子: 关于这个 SSDT Hook 实现进程 ...
- 进程隐藏与进程保护(SSDT Hook 实现)(一)
文章目录: 1. 引子 – Hook 技术: 2. SSDT 简介: 3. 应用层调用 Win32 API 的完整执行流程: 4. 详解 SSDT: 5. SSDT Hook 原理: 6. 小结: ...
最新文章
- iPhone 13 终于等到了!降价、新颜色、电池续航性能大提升
- 关于类和对象的进一步讨论 C++
- mysql5.6 python_Centos-6.5 + python3 + mysql5.6 环境搭建
- springcloud gateway ribbon使用_Github点赞接近 70k 的Spring Cloud学习教程+实战项目推荐!牛批!...
- jquery时期到计时插件
- meta标签的另一个用法
- Android 性能测试——Memory Monitor 工具
- 无模型自适应迭代学习控制原理和matlab代码仿真学习记录
- Junit介绍与实现
- typedef 定义函数指针
- rms 公式 有效值_有效值、真有效值、基波有效值、全有效值概念辨析
- Android反编译查看源文件
- Java8新特性之日期和时间
- unity3d FPS 枪的后座力
- 吐血分享:QQ群霸屏技术教程之霸屏实施细则
- 绝地求生2020服务器维护中,绝地求生2020最新维护公告几点开服?3月18日更新内容一览...
- cadence allegro 之如何隐藏/显示单个DRC
- C# ComboBox:组合框控件
- Vue实现图形化积木式编程(十二)
- 太乐地图下载器5.0.5(破解版)
热门文章
- Django模型层(models.py)之多表操作
- Maven远程仓库:pom依赖以及jar包下载
- 使用正則表達式对URL进行解析
- [转]Create Custom Exception Filter in ASP.NET Core
- 分页原理+分页代码+分页类制作
- android Studio 运行不显示avd 无法运行
- jquery实现定时调度(倒计时)
- Android和.NET通用的AES算法 (转) 好东东 收藏一下
- Page.LoadTemplate的使用
- 5.6 图像颜色映射