大家好,本篇文章讨论XP/WIN7 32位下通过SSDTHook实现对系统调用的监控,所以得先知道什么是SSDT,而明白SSDT得先懂门的机制,懂门的机制得先懂GDT表....=.=
作者也是小白, 如有错误恳请指正,谢谢你的时间!
[专题四]Rootkit的学习与研究-编程技术-看雪-安全社区|安全招聘|kanxue.com,我发现查阅windwos基础的文章得从后往前翻。翻到前辈的文章后就陷入了自我怀疑,别人08年玩烂的东西现在学是否有意义,大家怎么看呢?
SSDT(System Service Descriptor Table)是Windows内核维护的系统服务分发表,记录了所有系统调用(Nt*函数)的内核实现地址。
WRK中观察,SSDT和ShadowSSDT是两个导出的表结构。 //win7 32位后不导出

windbg中观察 输入dd nt!KeServiceDescriptorTable L4 ,第一个值就是他的函数地址表地址,第三个值代表地址有几项

我们dds 地址表地址 ,解析成函数指针,就可以查阅SSDT。

既然SSDT表存储的是所有系统调用的函数地址,那么如果我们修改SSDT表中的函数指针,不就能改变系统调用最终的去向吗?
我们的目的是通过hook 内核函数实现对R3的监控,有几种思路:
1:可以通过Ntdll拿到想要hook的R3的API call的服务编号,去改相应的SSDT表项。
2:inlinehook内核API。
由于内核API不像R3的API在开头有mov edi edi.push ebp,mov ebp,esp这样主动提供的5字节hook点,inlineHook不好找点。显然修改表项更稳定。
3.替换MSR
MSR[175]是EIP,我们可以替换这个值,实现对系统快速调用的代理函数Hook,同时对EAX(系统服务号)做判断来选择针对的api。显然这种方法很好检查,读一下MSR的值就知道对不对劲了。
4.直接对KiFastCallEntry函数inlineHook,但是这样兼容性也不好,这个代码会更新
5.对某个进程做个假表 Ethread->ServiceTable

监控目标程序的创建进程,把他的服务表替换了。这也不难检测,可以遍历枚举进程,对比所有进程的服务表做判断。
6.新时代的对抗 不懂不懂....
SSDTHook的缺陷
这里有个Nt* 与Zw*函数的问题:
在R3(用户层)时,Zw和Nt其实是同一个导出地址,最终通过int 2Eh或syscall指令,带着服务号进入内核,由SSDT查表找到真正的内核实现。
在R0(内核层)时,Zw函数会无条件地通过SSDT查表,即使已经在内核态,也会走一遍“查表”流程。
Nt函数(如NtOpenProcess)内部是具体实现功能的代码,不会再通过SSDT查表。
举例说明
用户层调用ZwOpenProcess:
R3 → ZwOpenProcess → 系统调用指令(int 2Eh/syscall)→ SSDT查表 → NtOpenProcess实现
内核层调用ZwOpenProcess:
R0 → ZwOpenProcess → SSDT查表 → NtOpenProcess实现
内核层调用NtOpenProcess:
R0 → NtOpenProcess(直接实现,不查表)
如果内核驱动强制调Nt,就可以绕过SSDT表的Hook,结果就是hook不到驱动。
所以,SSDT hook适合监控用户层的系统调用,但对内核层直接调用Nt无能为力。
下图可以看到ZwOpenProcess内部也是传一个服务号然后call系统服务。

本文具体实现通过修改SSDT表中的函数指针实现hook
拆解一下思路 :
1.获取SSDT表地址
2.R3通过控制码传服务号
3.R0收到服务号后修改SSDT[服务号]的值为我们干活的函数地址,并保存原函数指针。
4.在hook函数内部收集信息并调用原函数指针(否则破坏系统功能),将信息放到R3能读取到的一块缓冲区
5.R3读取数据显示在UI上,实现对系统调用的监控。
6.干完活或者软件关闭,需要恢复被修改的SSDT表项为保存的原函数指针。
第一种方法,特征KeAddSystemServiceTable
第二种方法,拿全局变量直接用,但是win7 32位后就不导出了,要解析pdb
但是通过这个结构体,我们只能拿到函数地址和知道有几项服务函数,不知道函数名。
由于我写的玩具要在XP上跑,所以让ai把windbg的SSDT表信息硬编码为数组。高版本系统可以集成网上各种的开源pdb解析工具(基本都是64位的) 获取函数名。
这没什么好说的,确认好要hook什么函数写个枚举类表示服务号,非常老实
由于我们hook函数后需要发监控的数据给R3,所以我使用mdl申请了一块共享内存,每次R3发控制码,R0都返回了这个共享内存的地址。后续R0写入,R3读取。
注意:MmMapLockedPagesSpecifyCache必须在目标用户进程的上下文下调用,才能把内核内存映射到R3进程空间。我一开始把这个初始化函数放在了DriverEntry,排查了好几个小时- -
主要是拿到符号号后替换SSDT中函数指针,伪代码:
这里需要考虑重入和引用计数问题:
如果有线程进入FakeNtCreateProcessEx但是在还没返回,此时驱动卸载了,线程继续跑被释放的代码内存,导致蓝屏。
所以我们需要确保所有函数调用完才DriverUnload。
重入问题:比如你在HookedNtOpenProcess里做日志、权限检查、甚至调用其他API时,间接又触发了NtOpenProcess,就会再次进入Hook函数本身,所以我们需要添加引用计数。
我最后是搞了张表存储Hook需要的数据,详细代码请看文末。
通过收到的服务号查表进行函数指针的替换实现hook
我在hook函数内部拿信息信息,封装成PROCESS_EVENT,R3也按这个格式读。
这里我纯属折腾,给共享内存维护了一个环形缓冲区,R0控制WriteIndex只写,R3控制ReadIndex只读。
假设R0写完7,WriteIndex就会变为0从头开始覆写,实现固定缓冲区大小的生产消费。数据结构不是主题,下文会贴出代码。
最省事的可以R3调Readfile读。也可以让R3调DeviceIoControl,R0收到后拷贝数据到systembuffer,在缓冲区满时清空这个缓冲区。
这里有同步问题:现在不仅仅是R0和R3两个线程在操作缓冲区,而是R0侧的每个被 hook 的 SSDT 函数都可能在不同的线程中并发地往同一个缓冲区写入数据。
这意味着R0端是多生产者(多线程写),R3端是单消费者(单线程读),存在数据竞争,记得加锁?有没有什么比较优雅的方法....0.0
这里顺便查阅了一下内核的读写锁:
KSPIN_LOCK:自旋锁,适合保护极短临界区,不支持多读单写。
KMUTEX / FAST_MUTEX:互斥体,只能单线程独占,不支持多读。
KSEMAPHORE:信号量,可实现计数型同步,但不直接支持读写锁语义。
KEVENT:事件,适合信号通知,不适合实现锁。
ERESOURCE:专为多读单写设计的内核对象,支持递归、死锁检测。这个XP能用
SpinLock从vista开始支持读取器/写入器自旋锁 - Windows drivers | Microsoft Learn,Xp好像只能用ERESOURCE。ERESOURCE 例程简介 - Windows drivers | Microsoft Learn
读锁允许多个线程同时读取同一份数据,但禁止写线程在此期间修改数据,避免写线程正在修改时,读线程读到不完整数据。
一般是开一个线程轮询读共享内存的数据写到数据结构,UI再读缓冲区展示数据,这样会导致日志线程和UI主线程的读写同步问题,记得处理。好奇:由于imgu每一帧都会刷新UI。可以在每一帧渲染前/后,顺便轮询一次共享内存,把新日志读出来,推到UI展示队列,会不会卡?
展示在UI上的结构体:
1)手动控制hook,R3发控制码,让R0将函数指针替换回去。
2)上文描述过的引用计数问题:程序退出的时候,如果贸然卸载驱动,线程继续跑被释放的代码内存,导致蓝屏。先卸载hook,再依靠引用计数确保hook函数都跑完了代码,最后卸载驱动。
拿的信息比较简陋


其实写ssdthook的时候感觉麻烦的是代码的设计和多线程数据竞争的处理方式,安全知识倒是不复杂。
SSDTHook在XP虚拟机里多hook几个函数就会非常的卡,让我分辨不出是hook导致的卡还是我代码写的不好,蓝廋~
后续应该是注册系统回调
//WRK中他就长这样
typedef struct _KSERVICE_TABLE_DESCRIPTOR {
PULONG_PTR Base;//函数地址表指针
PULONG Count; // 指向计数器的指针 不管它就行
ULONG Limit; // 实际的服务数量 这个和"Count"很容易混淆
PUCHAR Number;
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable //声明直接用
//WRK中他就长这样
typedef struct _KSERVICE_TABLE_DESCRIPTOR {
PULONG_PTR Base;//函数地址表指针
PULONG Count; // 指向计数器的指针 不管它就行
ULONG Limit; // 实际的服务数量 这个和"Count"很容易混淆
PUCHAR Number;
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable //声明直接用
R3 R0
| |
|通过DeviceIoCtl传服务号i|
|--------------------->|
| | 获取SSDT表地址
| | 保存原始函数指针SSDT[i]
| | 修改SSDT表项为Hook函数
| |
| | 系统服务会调用Hook函数,收集信息
| | 写入共享缓冲区
|<---------------------|
| 开线程轮询读取缓冲区
| 展示在UI上
结束的时候
| 发送卸载命令(DeviceIoCtl)
|--------------------->|
| | 等待所有hook调用结束
| | 恢复SSDT表项
| | 释放共享缓冲区
|<---------------------|
R3 R0
| |
|通过DeviceIoCtl传服务号i|
|--------------------->|
| | 获取SSDT表地址
| | 保存原始函数指针SSDT[i]
| | 修改SSDT表项为Hook函数
| |
| | 系统服务会调用Hook函数,收集信息
| | 写入共享缓冲区
|<---------------------|
| 开线程轮询读取缓冲区
| 展示在UI上
结束的时候
| 发送卸载命令(DeviceIoCtl)
|--------------------->|
| | 等待所有hook调用结束
| | 恢复SSDT表项
| | 释放共享缓冲区
|<---------------------|
void GetSSDT() {
UNICODE_STRING ustrName;
RtlInitUnicodeString(&ustrName, L"KeAddSystemServiceTable");
UCHAR* pCode = MmGetSystemRoutineAddress(&ustrName);
for (int i = 0; i < 100; i++) {
if (pCode[i] == 0x83 && pCode[i + 1] == 0xB8) {
KeServiceDescriptorTable = *(PKSERVICE_TABLE_DESCRIPTOR*)(pCode + i + 2);
break;
}
}
}
void GetSSDT() {
UNICODE_STRING ustrName;
RtlInitUnicodeString(&ustrName, L"KeAddSystemServiceTable");
UCHAR* pCode = MmGetSystemRoutineAddress(&ustrName);
for (int i = 0; i < 100; i++) {
if (pCode[i] == 0x83 && pCode[i + 1] == 0xB8) {
KeServiceDescriptorTable = *(PKSERVICE_TABLE_DESCRIPTOR*)(pCode + i + 2);
break;
}
}
}
typedef struct _KSERVICE_TABLE_DESCRIPTOR {
PULONG_PTR Base;
PULONG Count;
ULONG Limit;
PUCHAR Number;
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable
typedef struct _KSERVICE_TABLE_DESCRIPTOR {
PULONG_PTR Base;
PULONG Count;
ULONG Limit;
PUCHAR Number;
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable
SSDT_INFO g_SSDT_XP_SP3_Table[] = {
{0, (PVOID)0x805a5614, "NtAcceptConnectPort"},
{1, (PVOID)0x805f1adc, "NtAccessCheck"},
{2, (PVOID)0x805f5312, "NtAccessCheckAndAuditAlarm"},
{3, (PVOID)0x805f1b0e, "NtAccessCheckByType"},
....
SSDT_INFO g_SSDT_XP_SP3_Table[] = {
{0, (PVOID)0x805a5614, "NtAcceptConnectPort"},
{1, (PVOID)0x805f1adc, "NtAccessCheck"},
{2, (PVOID)0x805f5312, "NtAccessCheckAndAuditAlarm"},
{3, (PVOID)0x805f1b0e, "NtAccessCheckByType"},
....
typedef enum : ULONG {
HOOK_CREATE_PROCESS = 48,
HOOK_OPEN_PROCESS = 122,
HOOK_DEBUG_PROCESS = 57,
HOOK_SUSPEND_PROCESS = 253,
HOOK_RESUME_PROCESS = 205,
HOOK_TERMINATE_PROCESS = 257
} HOOK_SSDT_Index, * PHOOK_SSDT_Index;
typedef enum : ULONG {
HOOK_CREATE_PROCESS = 48,
HOOK_OPEN_PROCESS = 122,
HOOK_DEBUG_PROCESS = 57,
HOOK_SUSPEND_PROCESS = 253,
HOOK_RESUME_PROCESS = 205,
HOOK_TERMINATE_PROCESS = 257
} HOOK_SSDT_Index, * PHOOK_SSDT_Index;
BOOL ArkR3::StartSSDTHook(HOOK_SSDT_Index flag)
{
PVOID sharedMemAddr = NULL;
DWORD dwRetBytes = 0;
BOOL bResult = DeviceIoControl(m_hDriver, CTL_START_SSDTHOOK,
&flag, sizeof(HOOK_SSDT_Index),
&sharedMemAddr,sizeof(PVOID),
&dwRetBytes, NULL);
...
BOOL ArkR3::StartSSDTHook(HOOK_SSDT_Index flag)
{
PVOID sharedMemAddr = NULL;
DWORD dwRetBytes = 0;
BOOL bResult = DeviceIoControl(m_hDriver, CTL_START_SSDTHOOK,
&flag, sizeof(HOOK_SSDT_Index),
&sharedMemAddr,sizeof(PVOID),
&dwRetBytes, NULL);
...
PVOID g_SharedMemory = NULL; //共享内存地址 R0用
PVOID g_SharedLogBuffer = NULL;//映射到R3的内存地址 R3用
PMDL g_SharedMdl = NULL;
// 初始化共享内存
NTSTATUS InitSharedMemory() {
// 分配内核内存
g_SharedMemory = ExAllocatePoolWithTag(NonPagedPool, sizeof(LOG_BUFFER), 'SLOG');
if (!g_SharedMemory) {
Log("[test] InitSharedMemory: !g_SharedMemory");
return STATUS_NO_MEMORY;
}
RtlZeroMemory(g_SharedMemory, sizeof(LOG_BUFFER));
// 创建MDL
g_SharedMdl = IoAllocateMdl(g_SharedMemory, sizeof(LOG_BUFFER), FALSE, FALSE, NULL);
if (!g_SharedMdl) {
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
Log("[test] InitSharedMemory: IoAllocateMdl STATUS_NO_MEMORY");
return STATUS_NO_MEMORY;
}
// 构建MDL
MmBuildMdlForNonPagedPool(g_SharedMdl);
// 映射到用户空间
g_SharedLogBuffer = MmMapLockedPagesSpecifyCache(g_SharedMdl, UserMode,
MmNonCached, NULL, FALSE, NormalPagePriority);
if (!pSharedLogBuffer_) {
Log("[test] InitSharedMemory: 映射到用户空间失败");
IoFreeMdl(g_SharedMdl);
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
return STATUS_NO_MEMORY;
}
Log("[test] 共享内存初始化成功: 内核地址=%p, 用户地址=%p", g_SharedMemory, pSharedLogBuffer_);
return STATUS_SUCCESS;
}
// 清理共享内存
void CleanupSharedMemory() {
if (g_SharedLogBuffer) {
MmUnmapLockedPages(g_SharedLogBuffer, g_SharedMdl);
g_SharedLogBuffer = NULL;
}
if (g_SharedMdl) {
IoFreeMdl(g_SharedMdl);
g_SharedMdl = NULL;
}
if (g_SharedMemory) {
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
g_SharedMemory = NULL;
}
}
PVOID g_SharedMemory = NULL; //共享内存地址 R0用
PVOID g_SharedLogBuffer = NULL;//映射到R3的内存地址 R3用
PMDL g_SharedMdl = NULL;
// 初始化共享内存
NTSTATUS InitSharedMemory() {
// 分配内核内存
g_SharedMemory = ExAllocatePoolWithTag(NonPagedPool, sizeof(LOG_BUFFER), 'SLOG');
if (!g_SharedMemory) {
Log("[test] InitSharedMemory: !g_SharedMemory");
return STATUS_NO_MEMORY;
}
RtlZeroMemory(g_SharedMemory, sizeof(LOG_BUFFER));
// 创建MDL
g_SharedMdl = IoAllocateMdl(g_SharedMemory, sizeof(LOG_BUFFER), FALSE, FALSE, NULL);
if (!g_SharedMdl) {
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
Log("[test] InitSharedMemory: IoAllocateMdl STATUS_NO_MEMORY");
return STATUS_NO_MEMORY;
}
// 构建MDL
MmBuildMdlForNonPagedPool(g_SharedMdl);
// 映射到用户空间
g_SharedLogBuffer = MmMapLockedPagesSpecifyCache(g_SharedMdl, UserMode,
MmNonCached, NULL, FALSE, NormalPagePriority);
if (!pSharedLogBuffer_) {
Log("[test] InitSharedMemory: 映射到用户空间失败");
IoFreeMdl(g_SharedMdl);
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
return STATUS_NO_MEMORY;
}
Log("[test] 共享内存初始化成功: 内核地址=%p, 用户地址=%p", g_SharedMemory, pSharedLogBuffer_);
return STATUS_SUCCESS;
}
// 清理共享内存
void CleanupSharedMemory() {
if (g_SharedLogBuffer) {
MmUnmapLockedPages(g_SharedLogBuffer, g_SharedMdl);
g_SharedLogBuffer = NULL;
}
if (g_SharedMdl) {
IoFreeMdl(g_SharedMdl);
g_SharedMdl = NULL;
}
if (g_SharedMemory) {
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
g_SharedMemory = NULL;
}
}
OriginalNtOpenProcess = SSDT[0x23];
SSDT[0x23] = HookedNtOpenProcess;
NTSTATUS HookedNtOpenProcess(...) {
...
return OriginalNtOpenProcess(...);
}
OriginalNtOpenProcess = SSDT[0x23];
SSDT[0x23] = HookedNtOpenProcess;
NTSTATUS HookedNtOpenProcess(...) {
...
return OriginalNtOpenProcess(...);
}
NTSTATUS NTAPI FakeNtCreateProcessEx(...) {
NTSTATUS Status = g_NtCreateProcessEx(...);
return Status;
}
NTSTATUS NTAPI FakeNtCreateProcessEx(...) {
NTSTATUS Status = g_NtCreateProcessEx(...);
return Status;
}
volatile LONG RefCount = 0;
NTSTATUS HookedNtOpenProcess(...) {
InterlockedIncrement(&RefCount);
NTSTATUS status = OriginalNtOpenProcess(...);
InterlockedDecrement(&RefCount);
return status;
}
LARGE_INTEGER Time = { 0 };
Time.QuadPart = 10000;
while (g_nRefCount != 0) {
KeDelayExecutionThread(KernelMode, FALSE, &Time);
}
volatile LONG RefCount = 0;
NTSTATUS HookedNtOpenProcess(...) {
InterlockedIncrement(&RefCount);
NTSTATUS status = OriginalNtOpenProcess(...);
InterlockedDecrement(&RefCount);
return status;
}
LARGE_INTEGER Time = { 0 };
Time.QuadPart = 10000;
while (g_nRefCount != 0) {
KeDelayExecutionThread(KernelMode, FALSE, &Time);
}
typedef struct _HOOK_ENTRY {
HOOK_SSDT_Index SsdtIndex;
PVOID* OriginalFunction;
PVOID HookFunction;
const char* FunctionName;
BOOLEAN IsHooked;
LONG RefCount;
} HOOK_ENTRY;
HOOK_ENTRY g_HookTable[] = {
{ HOOK_CREATE_PROCESS, (PVOID*)&g_NtCreateProcessEx, HookedNtCreateProcessEx, "NtCreateProcessEx", FALSE, 0 },
{ HOOK_OPEN_PROCESS, (PVOID*)&g_NtOpenProcess, HookedNtOpenProcess, "NtOpenProcess", FALSE, 0 },
...
};
#define HOOK_TABLE_SIZE (sizeof(g_HookTable) / sizeof(HOOK_ENTRY))
typedef struct _HOOK_ENTRY {
HOOK_SSDT_Index SsdtIndex;
PVOID* OriginalFunction;
PVOID HookFunction;
const char* FunctionName;
BOOLEAN IsHooked;
LONG RefCount;
} HOOK_ENTRY;
HOOK_ENTRY g_HookTable[] = {
{ HOOK_CREATE_PROCESS, (PVOID*)&g_NtCreateProcessEx, HookedNtCreateProcessEx, "NtCreateProcessEx", FALSE, 0 },
{ HOOK_OPEN_PROCESS, (PVOID*)&g_NtOpenProcess, HookedNtOpenProcess, "NtOpenProcess", FALSE, 0 },
...
};
#define HOOK_TABLE_SIZE (sizeof(g_HookTable) / sizeof(HOOK_ENTRY))
NTSTATUS SetHookByFlag(HOOK_SSDT_Index flag) {
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].SsdtIndex == flag && g_HookTable[i].HookFunction) {
if (g_HookTable[i].IsHooked) {
Log("[test] Hook已存在,跳过: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
*(ULONG*)g_HookTable[i].OriginalFunction = KeServiceDescriptorTable->Base[flag];
KeServiceDescriptorTable->Base[flag] = (ULONG)g_HookTable[i].HookFunction;
g_HookTable[i].IsHooked = TRUE;
Log("[test] Hook设置成功: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
}
Log("[test] 未找到Hook项: %d ", flag);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS UnsetHookByFlag(HOOK_SSDT_Index flag) {
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].SsdtIndex == flag && g_HookTable[i].OriginalFunction) {
if (!g_HookTable[i].IsHooked) {
Log("[test] Hook不存在,跳过: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
KeServiceDescriptorTable->Base[flag] = *(ULONG*)g_HookTable[i].OriginalFunction;
g_HookTable[i].IsHooked = FALSE;
Log("[test] Hook恢复成功: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS NTAPI HookedNtCreateProcessEx(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ParentProcess, ULONG Flags, HANDLE SectionHandle, HANDLE DebugPort, HANDLE ExceptionPort, ULONG JobMemberLevel)
{
InterlockedIncrement(&g_HookTable[0].RefCount);
NTSTATUS status = STATUS_UNSUCCESSFUL;
if (g_NtCreateProcessEx) {
status = g_NtCreateProcessEx(ProcessHandle, DesiredAccess,
ObjectAttributes, ParentProcess, Flags, SectionHandle,
DebugPort, ExceptionPort, JobMemberLevel);
}
AddProcessEvent(HOOK_CREATE_PROCESS, *ProcessHandle, status);
InterlockedDecrement(&g_HookTable[0].RefCount);
return status;
}
NTSTATUS SetHookByFlag(HOOK_SSDT_Index flag) {
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].SsdtIndex == flag && g_HookTable[i].HookFunction) {
if (g_HookTable[i].IsHooked) {
Log("[test] Hook已存在,跳过: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
*(ULONG*)g_HookTable[i].OriginalFunction = KeServiceDescriptorTable->Base[flag];
KeServiceDescriptorTable->Base[flag] = (ULONG)g_HookTable[i].HookFunction;
g_HookTable[i].IsHooked = TRUE;
Log("[test] Hook设置成功: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
}
Log("[test] 未找到Hook项: %d ", flag);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS UnsetHookByFlag(HOOK_SSDT_Index flag) {
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].SsdtIndex == flag && g_HookTable[i].OriginalFunction) {
if (!g_HookTable[i].IsHooked) {
Log("[test] Hook不存在,跳过: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
KeServiceDescriptorTable->Base[flag] = *(ULONG*)g_HookTable[i].OriginalFunction;
g_HookTable[i].IsHooked = FALSE;
Log("[test] Hook恢复成功: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS NTAPI HookedNtCreateProcessEx(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ParentProcess, ULONG Flags, HANDLE SectionHandle, HANDLE DebugPort, HANDLE ExceptionPort, ULONG JobMemberLevel)
{
InterlockedIncrement(&g_HookTable[0].RefCount);
NTSTATUS status = STATUS_UNSUCCESSFUL;
if (g_NtCreateProcessEx) {
status = g_NtCreateProcessEx(ProcessHandle, DesiredAccess,
ObjectAttributes, ParentProcess, Flags, SectionHandle,
DebugPort, ExceptionPort, JobMemberLevel);
}
AddProcessEvent(HOOK_CREATE_PROCESS, *ProcessHandle, status);
InterlockedDecrement(&g_HookTable[0].RefCount);
return status;
}
typedef struct PROCESS_EVENT {
CHAR SourceProcessName[16];
ULONG SourceProcessId;
ULONG Action;
ULONG TargetProcessId;
LONG Result;
} PROCESS_EVENT, * PPROCESS_EVENT;
typedef struct PROCESS_EVENT {
CHAR SourceProcessName[16];
ULONG SourceProcessId;
ULONG Action;
ULONG TargetProcessId;
LONG Result;
} PROCESS_EVENT, * PPROCESS_EVENT;
void AddProcessEvent(ULONG Action, HANDLE TargetHandle, NTSTATUS Result){
PEPROCESS CurrentProcess = PsGetCurrentProcess();
HANDLE CurrentPid = PsGetCurrentProcessId();
PUCHAR CurrentProcessName = PsGetProcessImageFileName(CurrentProcess);
PLOG_BUFFER pLogBuffer = (PLOG_BUFFER)g_SharedMemory;
ULONG currentReadIndex = pLogBuffer->ReadIndex;
ULONG TargetPid = 0;
if (TargetHandle) {
PEPROCESS TargetProcess = NULL;
NTSTATUS lookupStatus = ObReferenceObjectByHandle(TargetHandle,
PROCESS_QUERY_INFORMATION,
*PsProcessType,
KernelMode,
(PVOID*)&TargetProcess,
NULL);
if (NT_SUCCESS(lookupStatus)) {
TargetPid = (ULONG)PsGetProcessId(TargetProcess);
ObDereferenceObject(TargetProcess);
}
}
}
void AddProcessEvent(ULONG Action, HANDLE TargetHandle, NTSTATUS Result){
PEPROCESS CurrentProcess = PsGetCurrentProcess();
HANDLE CurrentPid = PsGetCurrentProcessId();
PUCHAR CurrentProcessName = PsGetProcessImageFileName(CurrentProcess);
PLOG_BUFFER pLogBuffer = (PLOG_BUFFER)g_SharedMemory;
ULONG currentReadIndex = pLogBuffer->ReadIndex;
ULONG TargetPid = 0;
if (TargetHandle) {
PEPROCESS TargetProcess = NULL;
NTSTATUS lookupStatus = ObReferenceObjectByHandle(TargetHandle,
PROCESS_QUERY_INFORMATION,
*PsProcessType,
KernelMode,
(PVOID*)&TargetProcess,
NULL);
if (NT_SUCCESS(lookupStatus)) {
TargetPid = (ULONG)PsGetProcessId(TargetProcess);
ObDereferenceObject(TargetProcess);
}
}
}
+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
^ ^
ReadIndex WriteIndex
+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
^ ^
ReadIndex WriteIndex
typedef struct PROCESS_EVENT {
CHAR SourceProcessName[16];
ULONG SourceProcessId;
ULONG Action;
ULONG TargetProcessId;
LONG Result;
} PROCESS_EVENT, * PPROCESS_EVENT;
typedef struct PROCESS_EVENT {
CHAR SourceProcessName[16];
ULONG SourceProcessId;
ULONG Action;
ULONG TargetProcessId;
LONG Result;
} PROCESS_EVENT, * PPROCESS_EVENT;
VOID Unload(__in struct _DRIVER_OBJECT* DriverObject)
{
UNREFERENCED_PARAMETER(DriverObject);
UNICODE_STRING usSymbolicLinkName;
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].IsHooked) {
UnsetHookByFlag(g_HookTable[i].SsdtIndex);
Log("[test] 恢复Hook: %s", g_HookTable[i].FunctionName);
}
}
LARGE_INTEGER Time = { 0 };
Time.QuadPart = -100000;
Log("[test] 开始等待Hook函数调用完成...");
while (1) {
BOOLEAN allClear = TRUE;
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].RefCount > 0) {
allClear = FALSE;
break;
}
}
if (allClear) {
break;
}
KeDelayExecutionThread(KernelMode, FALSE, &Time);
}
RtlInitUnicodeString(&usSymbolicLinkName, SYMBOL_NAME);
IoDeleteSymbolicLink(&usSymbolicLinkName);
if (DriverObject->DeviceObject != nullptr) {
IoDeleteDevice(DriverObject->DeviceObject);
}
Log("[test] Unload 完成 ");
}
VOID Unload(__in struct _DRIVER_OBJECT* DriverObject)
{
UNREFERENCED_PARAMETER(DriverObject);
UNICODE_STRING usSymbolicLinkName;
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].IsHooked) {
UnsetHookByFlag(g_HookTable[i].SsdtIndex);
Log("[test] 恢复Hook: %s", g_HookTable[i].FunctionName);
}
}
LARGE_INTEGER Time = { 0 };
Time.QuadPart = -100000;
Log("[test] 开始等待Hook函数调用完成...");
while (1) {
BOOLEAN allClear = TRUE;
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].RefCount > 0) {
allClear = FALSE;
break;
}
}
if (allClear) {
break;
}
KeDelayExecutionThread(KernelMode, FALSE, &Time);
}
RtlInitUnicodeString(&usSymbolicLinkName, SYMBOL_NAME);
IoDeleteSymbolicLink(&usSymbolicLinkName);
if (DriverObject->DeviceObject != nullptr) {
IoDeleteDevice(DriverObject->DeviceObject);
}
Log("[test] Unload 完成 ");
}
case CTL_START_SSDTHOOK:
{
PHOOK_SSDT_Index pIndex = (PHOOK_SSDT_Index)Irp->AssociatedIrp.SystemBuffer;
__try {
if (g_isInitShareMemory == false) {
InitSharedMemory();
g_isInitShareMemory = true;
}
HOOK_SSDT_Index index = *pIndex;
Log("[test] CTL_START_SSDTHOOK: index=%d funcname=%s ", index, GetHookNameByIndex(index));
status = SetHookByFlag(index);
if (NT_SUCCESS(status)) {
* (PVOID*)Irp->AssociatedIrp.SystemBuffer = pSharedLogBuffer_;
info = sizeof(pSharedLogBuffer_);
Log("[test]返回共享内存地址: %p ", pSharedLogBuffer_);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = STATUS_UNSUCCESSFUL;
Log("[test] CTL_START_SSDTHOOK exception ");
}
}
break;
case CTL_END_SSDTHOOK:
{
PHOOK_SSDT_Index pIndex = (PHOOK_SSDT_Index)Irp->AssociatedIrp.SystemBuffer;
__try {
HOOK_SSDT_Index index = *pIndex;
Log("[test] CTL_END_SSDTHOOK: index=%d funcname=%s", index, GetHookNameByIndex(index));
status = UnsetHookByFlag(index);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = STATUS_UNSUCCESSFUL;
Log("[test] CTL_START_SSDTHOOK exception ");
}
}
break;
NTSTATUS(NTAPI* g_NtCreateProcessEx)(
__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(NTAPI* g_NtOpenProcess)(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__in_opt PCLIENT_ID ClientId
);
NTSTATUS(NTAPI* g_NtDebugActiveProcess)(
__in HANDLE ProcessHandle,
__in HANDLE DebugObjectHandle
);
NTSTATUS(NTAPI* g_NtSuspendProcess)(
__in_opt HANDLE ProcessHandle
);
NTSTATUS(NTAPI* g_NtResumeProcess)(
__in_opt HANDLE ProcessHandle
);
NTSTATUS(NTAPI* g_NtTerminateProcess)(
__in_opt HANDLE ProcessHandle,
__in NTSTATUS ExitStatus
);
typedef struct _HOOK_ENTRY {
HOOK_SSDT_Index SsdtIndex;
PVOID* OriginalFunction;
PVOID HookFunction;
const char* FunctionName;
BOOLEAN IsHooked;
LONG RefCount;
} HOOK_ENTRY;
HOOK_ENTRY g_HookTable[] = {
{ HOOK_CREATE_PROCESS, (PVOID*)&g_NtCreateProcessEx, HookedNtCreateProcessEx, "NtCreateProcessEx", FALSE, 0 },
{ HOOK_OPEN_PROCESS, (PVOID*)&g_NtOpenProcess, HookedNtOpenProcess, "NtOpenProcess", FALSE, 0 },
{ HOOK_DEBUG_PROCESS, (PVOID*)&g_NtDebugActiveProcess, HookedNtDebugActiveProcess, "NtDebugActiveProcess", FALSE, 0 },
{ HOOK_SUSPEND_PROCESS, (PVOID*)&g_NtSuspendProcess, HookedNtSuspendProcess, "NtSuspendProcess", FALSE, 0 },
{ HOOK_RESUME_PROCESS, (PVOID*)&g_NtResumeProcess, HookedNtResumeProcess, "NtResumeProcess", FALSE, 0 },
{ HOOK_TERMINATE_PROCESS, (PVOID*)&g_NtTerminateProcess, HookedNtTerminateProcess, "NtTerminateProcess", FALSE, 0 }
};
#define HOOK_TABLE_SIZE (sizeof(g_HookTable) / sizeof(HOOK_ENTRY))
const char* GetHookNameByIndex(HOOK_SSDT_Index index) {
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].SsdtIndex == index) {
return g_HookTable[i].FunctionName;
}
}
return "Unknown";
}
void AddProcessEvent(ULONG Action, HANDLE TargetHandle, NTSTATUS Result)
{
if (!g_SharedMemory) {
Log("[EVENT] 错误:g_SharedMemory 为空");
return;
}
PEPROCESS CurrentProcess = PsGetCurrentProcess();
HANDLE CurrentPid = PsGetCurrentProcessId();
PUCHAR CurrentProcessName = PsGetProcessImageFileName(CurrentProcess);
PLOG_BUFFER pLogBuffer = (PLOG_BUFFER)g_SharedMemory;
ULONG currentReadIndex = pLogBuffer->ReadIndex;
ULONG TargetPid = 0;
if (TargetHandle) {
PEPROCESS TargetProcess = NULL;
NTSTATUS lookupStatus = ObReferenceObjectByHandle(TargetHandle,
PROCESS_QUERY_INFORMATION,
*PsProcessType,
KernelMode,
(PVOID*)&TargetProcess,
NULL);
if (NT_SUCCESS(lookupStatus)) {
TargetPid = (ULONG)PsGetProcessId(TargetProcess);
ObDereferenceObject(TargetProcess);
}
}
ULONG nextWriteIndex = (pLogBuffer->WriteIndex + 1) % 1000;
if (nextWriteIndex == currentReadIndex) {
Log("[EVENT] 缓冲区满,nextWriteIndex:%d currentReadIndex:%d", nextWriteIndex, currentReadIndex);
pLogBuffer->ReadIndex = (currentReadIndex + 1) % 1000;
}
PPROCESS_EVENT pEvent = &pLogBuffer->Logs[pLogBuffer->WriteIndex];
pEvent->Action = Action;
pEvent->SourceProcessId = (ULONG)CurrentPid;
pEvent->TargetProcessId = TargetPid;
pEvent->Result = Result;
RtlStringCbCopyA(pEvent->SourceProcessName, sizeof(pEvent->SourceProcessName), (const char*)CurrentProcessName);
pLogBuffer->WriteIndex = nextWriteIndex;
Log("[EVENT] Action=%d, SourcePid=%d, TargetPid=%d, Result=0x%08X,SourceName=%s",
pEvent->Action, pEvent->SourceProcessId, pEvent->TargetProcessId, pEvent->Result,pEvent->SourceProcessName);
if (pLogBuffer->LogCount < 1000) {
InterlockedIncrement((LONG*)&pLogBuffer->LogCount);
}
}
NTSTATUS SetHookByFlag(HOOK_SSDT_Index flag) {
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].SsdtIndex == flag && g_HookTable[i].HookFunction) {
if (g_HookTable[i].IsHooked) {
Log("[test] Hook已存在,跳过: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
*(ULONG*)g_HookTable[i].OriginalFunction = KeServiceDescriptorTable->Base[flag];
KeServiceDescriptorTable->Base[flag] = (ULONG)g_HookTable[i].HookFunction;
g_HookTable[i].IsHooked = TRUE;
Log("[test] Hook设置成功: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
}
Log("[test] 未找到Hook项: %d ", flag);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS UnsetHookByFlag(HOOK_SSDT_Index flag) {
for (ULONG i = 0; i < HOOK_TABLE_SIZE; i++) {
if (g_HookTable[i].SsdtIndex == flag && g_HookTable[i].OriginalFunction) {
if (!g_HookTable[i].IsHooked) {
Log("[test] Hook不存在,跳过: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
KeServiceDescriptorTable->Base[flag] = *(ULONG*)g_HookTable[i].OriginalFunction;
g_HookTable[i].IsHooked = FALSE;
Log("[test] Hook恢复成功: %s (索引:%d) ", g_HookTable[i].FunctionName, flag);
return STATUS_SUCCESS;
}
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS InitSharedMemory() {
g_SharedMemory = ExAllocatePoolWithTag(NonPagedPool, sizeof(LOG_BUFFER), 'SLOG');
if (!g_SharedMemory) {
Log("[test] InitSharedMemory: !g_SharedMemory");
return STATUS_NO_MEMORY;
}
RtlZeroMemory(g_SharedMemory, sizeof(LOG_BUFFER));
g_SharedMdl = IoAllocateMdl(g_SharedMemory, sizeof(LOG_BUFFER), FALSE, FALSE, NULL);
if (!g_SharedMdl) {
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
Log("[test] InitSharedMemory: IoAllocateMdl STATUS_NO_MEMORY");
return STATUS_NO_MEMORY;
}
MmBuildMdlForNonPagedPool(g_SharedMdl);
pSharedLogBuffer_ = MmMapLockedPagesSpecifyCache(g_SharedMdl, UserMode,
MmNonCached, NULL, FALSE, NormalPagePriority);
if (!pSharedLogBuffer_) {
Log("[test] InitSharedMemory: 映射到用户空间失败");
IoFreeMdl(g_SharedMdl);
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
return STATUS_NO_MEMORY;
}
Log("[test] 共享内存初始化成功: 内核地址=%p, 用户地址=%p", g_SharedMemory, pSharedLogBuffer_);
return STATUS_SUCCESS;
}
void CleanupSharedMemory() {
if (pSharedLogBuffer_) {
MmUnmapLockedPages(pSharedLogBuffer_, g_SharedMdl);
pSharedLogBuffer_ = NULL;
}
if (g_SharedMdl) {
IoFreeMdl(g_SharedMdl);
g_SharedMdl = NULL;
}
if (g_SharedMemory) {
ExFreePoolWithTag(g_SharedMemory, 'SLOG');
g_SharedMemory = NULL;
}
}
case CTL_START_SSDTHOOK:
{
PHOOK_SSDT_Index pIndex = (PHOOK_SSDT_Index)Irp->AssociatedIrp.SystemBuffer;
__try {
if (g_isInitShareMemory == false) {
InitSharedMemory();
g_isInitShareMemory = true;
}
HOOK_SSDT_Index index = *pIndex;
Log("[test] CTL_START_SSDTHOOK: index=%d funcname=%s ", index, GetHookNameByIndex(index));
status = SetHookByFlag(index);
if (NT_SUCCESS(status)) {
* (PVOID*)Irp->AssociatedIrp.SystemBuffer = pSharedLogBuffer_;
info = sizeof(pSharedLogBuffer_);
Log("[test]返回共享内存地址: %p ", pSharedLogBuffer_);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = STATUS_UNSUCCESSFUL;
Log("[test] CTL_START_SSDTHOOK exception ");
}
}
break;
case CTL_END_SSDTHOOK:
{
PHOOK_SSDT_Index pIndex = (PHOOK_SSDT_Index)Irp->AssociatedIrp.SystemBuffer;
__try {
HOOK_SSDT_Index index = *pIndex;
Log("[test] CTL_END_SSDTHOOK: index=%d funcname=%s", index, GetHookNameByIndex(index));
status = UnsetHookByFlag(index);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = STATUS_UNSUCCESSFUL;
Log("[test] CTL_START_SSDTHOOK exception ");
}
}
break;
NTSTATUS(NTAPI* g_NtCreateProcessEx)(
__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(NTAPI* g_NtOpenProcess)(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__in_opt PCLIENT_ID ClientId
);
NTSTATUS(NTAPI* g_NtDebugActiveProcess)(
__in HANDLE ProcessHandle,
__in HANDLE DebugObjectHandle
);
NTSTATUS(NTAPI* g_NtSuspendProcess)(
__in_opt HANDLE ProcessHandle
);
NTSTATUS(NTAPI* g_NtResumeProcess)(
__in_opt HANDLE ProcessHandle
);
NTSTATUS(NTAPI* g_NtTerminateProcess)(
__in_opt HANDLE ProcessHandle,
__in NTSTATUS ExitStatus
);
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
最后于 2025-8-13 21:39
被X66iaM编辑
,原因: