最近在学习Ring0层Hook的一些知识点,很久就写完SSDTHook的代码了,但是一直没有整理成笔记,最近有时间也就整理整理。
介绍:
SSDTHook 实质是利用Ntoskrnl.exe 中全局导出的SSDT来进行Hook,SSDT(SystemServiceDescriptorTable,系统服务描述表),为什么要去用到SSDT表呢?
我们看一下ZwOpenProcess实现就明白了。为什么不用Nt系列函数,可以看我之前的文章。
kd> u 0x8485acd8 nt!ZwOpenProcess: 8485acd8 b8 be000000 mov eax,0BEh 8485acdd 8d542404 lea edx,[esp+4] 8485ace1 9c pushfd 8485ace2 6a08 push 8 8485ace4 e8d5190000 call nt!KiSystemService (8485c6be) 8485ace9 c21000 ret 10h nt!ZwOpenProcessToken: 8485acec b8bf000000 mov eax,0BFh 8485acf1 8d542404 lea edx,[esp+4]
KiSystemService是系统调用的内核入口,也是从Ring3陷入Ring0的关键点。在第一句中mov eax,0BEh 中的BEh在我看来就是一个序号,相当于中断向量表中的中断类型号一样,在SSDT表中通过这序号,才找到真正的NtOpenProcess函数的代码出。很容易就能理解,我们为什么要找这个。原因在于:我们要把SSDT表中相应位置的函数地址替换掉,就实现了Hook。
(一)
?首先找到全局导出的KeServiceDescriptorTable。
?然后从MmGetSystemRoutineAddress函数中获取ZwOpenProcess函数地址。
?从ZwOpenProcess中获取序号。
?将SSDT表所在页属性改为可读可写的状态。
?将自己写好的Fake函数地址替换进去即可。
Hook之前: Hook之后:
(二)
/* typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_ { PVOID ServiceTableBase; //这个指向系统服务函数地址表 PULONG ServiceCounterTableBase; ULONG NumberOfService; //服务函数的个数 ULONG ParamTableBase; }SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE; 0x84988b00 struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_ * ServiceTableBase 0x8489d43c ServiceCounterTableBase 0x00000000 NumberOfService 0x191 ParamTableBase 0x8489da84 */ extern PSYSTEM_SERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable; PUCHAR __ZwOpenProcess = NULL; PMDL __MDL = NULL; PVOID *__ServiceTableBase = NULL; LPFN_NTOPENPROCESS __NtOpenProcess = NULL; BOOLEAN __IsHook = FALSE; #define SSDT_INDEX(ZwFunctionAddress) * (PULONG)((PUCHAR)ZwFunctionAddress +1) #define SSDT_HOOK(ZwFunctionAddress,FakeFunctionAddress,OriginalFunctionAddress)\ OriginalFunctionAddress = (PVOID) InterlockedExchange((PLONG)&__ServiceTableBase[SSDT_INDEX(ZwFunctionAddress)],(LONG)FakeFunctionAddress) #define SSDT_UNHOOK(ZwFunctionAddress,OriginalFunctionAddress)\ (PVOID) InterlockedExchange((PLONG)&__ServiceTableBase[SSDT_INDEX(ZwFunctionAddress)],(LONG)OriginalFunctionAddress) NTSTATUS SSDTHook(BOOLEAN IsOk) { NTSTATUS Status = STATUS_UNSUCCESSFUL; UNICODE_STRING v1; RtlInitUnicodeString(&v1, L"ZwOpenProcess"); if (IsOk) { __ZwOpenProcess = (PUCHAR)MmGetSystemRoutineAddress(&v1); /* 2: kd> u 0x8485acd8 nt!ZwOpenProcess: 8485acd8 b8 be000000 mov eax,0BEh 8485acdd 8d542404 lea edx,[esp+4] 8485ace1 9c pushfd 8485ace2 6a08 push 8 8485ace4 e8d5190000 call nt!KiSystemService (8485c6be) 8485ace9 c21000 ret 10h nt!ZwOpenProcessToken: 8485acec b8bf000000 mov eax,0BFh 8485acf1 8d542404 lea edx,[esp+4] */ if (__ZwOpenProcess) { if (__MDL == NULL) { __MDL = MmCreateMdl(NULL, KeServiceDescriptorTable->ServiceTableBase, KeServiceDescriptorTable->NumberOfService * sizeof(PVOID)); if (!__MDL) { return Status; } MmBuildMdlForNonPagedPool(__MDL); //设置标志让内存变成读写 __MDL->MdlFlags = __MDL->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; __ServiceTableBase = MmMapLockedPages(__MDL, KernelMode); } if (__ServiceTableBase) { if (!__IsHook) { //开始HOOK SSDT_HOOK(__ZwOpenProcess, FakeNtOpenProcess, __NtOpenProcess); Status = STATUS_SUCCESS; /* 2: kd> u 0x84a31ba1 nt!NtOpenProcess: 84a31ba1 8bff mov edi,edi 84a31ba3 55 push ebp 84a31ba4 8bec mov ebp,esp 84a31ba6 51 push ecx 84a31ba7 51 push ecx 84a31ba8 64a124010000 mov eax,dword ptr fs:[00000124h] 84a31bae 8a803a010000 mov al,byte ptr [eax+13Ah] 84a31bb4 8b4d14 mov ecx,dword ptr [ebp+14h] */ __IsHook = TRUE; } } } } else { if (__IsHook) { SSDT_UNHOOK(__ZwOpenProcess, __NtOpenProcess); __IsHook = FALSE; } if (__MDL) { MmUnmapLockedPages(__ServiceTableBase, __MDL); IoFreeMdl(__MDL); __MDL = NULL; Status = STATUS_SUCCESS; } } return Status; } NTSTATUS FakeNtOpenProcess( PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId) { __try { PEPROCESS EProcess = PsGetCurrentProcess(); if (EProcess != NULL && IsRealProcess(EProcess)) { char * ProcessName = (ULONG_PTR)EProcess + x86_IMAGEFILENAME_OFFSET; if (strcmp(ProcessName, "HookRing3.exe")==0) { return STATUS_ACCESS_DENIED; } } } __except (1) { return GetExceptionCode(); } return ((LPFN_NTOPENPROCESS)__NtOpenProcess)(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); }