本节的目的是通过驱动程序修改 ntoskrnl.exe
程序的 SSDT
表中的函数地址表,以实现 SSDT Hook
。本次的测试函数为 R3 API
函数 ZwTerminateProcess
,通过 Hook
该函数,以实现任务管理器无法强制关闭进程,只有通过进程的关闭方法才可以正常结束进程。
Hook
该函数的关键是判断 ZwTerminateProcess
函数中的进程句柄 hProcess
。当进程是通过自身的关闭方法关闭的话,该句柄的值应为 0xffffffff
或 0x00
,而通过其他进程调用 ZwTerminateProcess
函数关闭的话,该句柄的值不为以上情况。因此,我们可以通过这种方法来判断,进程是主动关闭的,还是被动关闭的。
测试代码如下:
#include <ntddk.h>
#include <ntstatus.h>
/************************************************************************/
/* 类型声明 */
/************************************************************************/
// 系统服务表
typedef struct _KSYSTEM_SERVICE_TABLE
{
PULONG ServiceTableBase; // 函数地址表
PULONG ServiceCounterTableBase; // SSDT 函数被调用的次数
ULONG NumberOfService; // 函数个数
PULONG ParamTableBase; // 函数参数表
} KSYSTEM_SERVICE_TABLE, * PKSYSTEM_SERVICE_TABLE;
typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
KSYSTEM_SERVICE_TABLE ntoskrnl; // ntoskrnl.exe 函数
KSYSTEM_SERVICE_TABLE win32k; // win32k.sys 函数
KSYSTEM_SERVICE_TABLE unUsed1;
KSYSTEM_SERVICE_TABLE unUsed2;
} KSERVICE_TABLE_DESCRIPTOR, * PKSERVICE_TABLE_DESCRIPTOR;
// NTOPENPROCESS
typedef NTSTATUS(*NTOPENPROCESS) (HANDLE hProcess, UINT32 uExitCode);
/************************************************************************/
/* 函数声明 */
/************************************************************************/
VOID DriverUnload(PDRIVER_OBJECT pDriver);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path);
VOID PageProtectOff();
VOID PageProtectOn();
VOID HookZwTerminateProcess();
VOID UnHookZwTerminateProcess();
NTSTATUS MyHookZwTerminateProcess(HANDLE hProcess, UINT32 uExitCode);
/************************************************************************/
/* 全局变量 */
/************************************************************************/
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable; // ntoskrnl.exe 导出的全局变量
ULONG uOldZwTerminateProcess; // 旧的函数地址
/************************************************************************/
/* 函数定义 */
/************************************************************************/
// 驱动入口
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
// HOOK
HookZwTerminateProcess();
pDriver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
// 卸载驱动
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
UnHookZwTerminateProcess();
DbgPrint("Driver unloaded.\n");
}
// 关闭页保护
VOID PageProtectOff()
{
__asm
{
cli; // 关闭中断
mov eax, cr0;
and eax, not 0x10000; // WP位置0
mov cr0, eax;
}
}
// 开启页保护
VOID PageProtectOn()
{
__asm
{
mov eax, cr0;
or eax, 0x10000; // WP位置1
mov cr0, eax;
sti; // 恢复中断
}
}
// HOOK NtOpenProcess
VOID HookZwTerminateProcess()
{
PageProtectOff();
uOldZwTerminateProcess = KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0x101];
KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0x101] = (ULONG)MyHookZwTerminateProcess;
PageProtectOn();
}
// UnHOOK NtOpenProcess
VOID UnHookZwTerminateProcess()
{
PageProtectOff();
KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0x101] = uOldZwTerminateProcess;
PageProtectOn();
}
// 被修改的 NtOpenProcess 函数,简单打印参数
NTSTATUS MyHookZwTerminateProcess(HANDLE hProcess, UINT32 uExitCode)
{
DbgPrint("进程句柄:%x 退出码:%x\n", hProcess, uExitCode);
if (!(hProcess == 0xffffffff || hProcess == 0))
{
DbgPrint("拒绝关闭请求!\n");
return 0;
}
else
return ((NTOPENPROCESS)uOldZwTerminateProcess)(hProcess, uExitCode);
}
效果图如下: