当打开任务管理器时,选择一个进程并结束进程这个过程,可以详细的分为以下几步:
1) taskmgr 进程首先获取要结束的进程句柄,通过 OpenProcess()这个下API,OpenProcess 调用在Kernel32.dll 中;
2)系统捕获API调用,转到Ring0 级下,从 SSDT中取得对应的 RintOpenProcess 的入口地址,执行相应操作,此过程在 ntdll.dll 中;
3)完成NtOpenProcess 操作后转回Ring3 级下返回 OpenProcess 函数返回taskmgr进程,因此获取了要结束的进程的句柄;
4)taskmgr 执行 TerminateProcess()这个 Ring3 下的 API,传入进程句试结束进程;
5)系统捕获API调用,再次转到 Ring0 级下,从SSDT中取得对应的PI:NtTerminateProcess 的入口地址,执行结束进程操作;
6、完成 NtTerminateProcess 操作后转回 Ring3 级下返回 TerminatePro数,继而返回taskmgr 进程,完成结束进程过程;
在这一个流程中,SSDT起到了重要的作用。于是针对这一流程可以hook ssdt,改变这处流程的处理,从而达到无论是用taskkill命令还是任务管理器都不能杀死进程的效果
#include <ntddk.h>
#include <ntstatus.h>
// 记录原函数的地址
ULONG uOldNtOpenProcess;
//内核之SSDT-HOOK
//系统服务表
typedef struct _KSYSTEM_SERVICE_TABLE
{
PULONG ServiceTableBase; //函数地址表的首地址
PULONG ServiceCounterTableBase;//函数表中每个函数被调用的次数
ULONG NumberOfService; //服务函数的个数
ULONG ParamTableBase; //参数个数表首地址
}KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE;
//服务描述符
typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
KSYSTEM_SERVICE_TABLE ntoskrnl;//ntoskrnl.exe的服务函数,SSDT
KSYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数,ShadowSSDT
KSYSTEM_SERVICE_TABLE notUsed1;//暂时没用1
KSYSTEM_SERVICE_TABLE notUsed2;//暂时没用2
}KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
//定义HOOK的函数的类型
typedef NTSTATUS(NTAPI* FuZwOpenProcess)(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
);
//自写的函数声明
NTSTATUS NTAPI MyZwOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
);
// KeServiceDescriptorTable 为 ntoskrnl.exe 所导出的全局变量
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
//记录系统的该函数
FuZwOpenProcess g_OldZwOpenProcess;
//服务描述符表指针
KSERVICE_TABLE_DESCRIPTOR* g_pServiceTable = NULL;
//要保护进程的ID
ULONG g_Pid = 1624;
//安装钩子
NTSTATUS HookNtOpenProcess();
//卸载钩子
NTSTATUS UnHookNtOpenProcess();
//关闭页写入保护
void ShutPageProtect();
//开启页写入保护
void OpenPageProtect();
//卸载驱动
void DriverUnload(DRIVER_OBJECT* obj);
/***驱动入口主函数***/
NTSTATUS DriverEntry(DRIVER_OBJECT* driver, UNICODE_STRING* path)
{
KdPrint(("驱动启动成功!\n"));
//安装钩子
HookNtOpenProcess();
driver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
//卸载驱动
void DriverUnload(DRIVER_OBJECT* obj)
{
//卸载钩子
UnHookNtOpenProcess();
KdPrint(("驱动卸载成功!\n"));
}
NTSTATUS HookNtOpenProcess()
{
NTSTATUS Status;
Status = STATUS_SUCCESS;
//1.关闭页只读保护
ShutPageProtect();
//2.修改SSDT表
uOldNtOpenProcess = KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0x7a];
KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0x7a] =(ULONG)MyZwOpenProcess;
//3.开启页只读保护
OpenPageProtect();
return Status;
}
//卸载钩子
NTSTATUS UnHookNtOpenProcess()
{
NTSTATUS status;
status = STATUS_SUCCESS;
//1.关闭页只读保护
ShutPageProtect();
//2.写入原来的函数到SSDT表内
KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0x7a] = uOldNtOpenProcess;
//3.开启页只读保护
OpenPageProtect();
return status;
}
//关闭页只读保护
void _declspec(naked) ShutPageProtect()
{
__asm
{
push eax;
mov eax, cr0;
and eax, ~0x10000;
mov cr0, eax;
pop eax;
ret;
}
}
//开启页只读保护
void _declspec(naked) OpenPageProtect()
{
__asm
{
push eax;
mov eax, cr0;
or eax, 0x10000;
mov cr0, eax;
pop eax;
ret;
}
}
//自写的函数
NTSTATUS NTAPI MyZwOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
)
{
//当此进程为要保护的进程时
if (ClientId->UniqueProcess == (HANDLE)g_Pid)
{
//设为拒绝访问
DesiredAccess = 0;
}
//调用原函数
return NtOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);
}