在WINDOWS 7 BETA(BUILD 7000)中,ntoskrnl!ZwTerminateProcess 仍是以KiSystemService stub的形式出现
即:
代码:
mov eax , IdOfZwTerminateProcess lea edx , [esp+arg_0] pushf push 8 call KiSystemService retn 0x8
即ZwTerminateProcess变成了一个真正实现的函数,而不是一个SSDT函数的转发
该函数大体被实现成了如下形式,即调用PsTerminateProcess实现结束进程,并且在内部称为ZwTerminateProcessAssist:
代码:
NTSTATUS ZwTerminateProcessAssist(HANDLE ProcessHandle, NTSTATUS ExitStatus) { NTSTATUS status ; PVOID ProcessObject; if ( ProcessHandle ) { status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_TERMINATE, PsProcessType, 0, &ProcessObject, 0); if ( NT_SUCESS(stat)) { status = PsTerminateProcess(ProcessObject, ExitCode); ObfDereferenceObject(ProcessObject); } } else { status = STATUS_NOT_SUPPORTED; } return status ; }
等价于RING0的调用绕过了SSDT HOOK对这个函数的拦截,同时,这个函数不允许对ProcessHandle = 0的进程进行结束
而此前ZwTerminateProcess是可以传入ProcessHandle = 0 的,当传入为0,WINDOWS默认认为要结束的是当前进程,即:
代码:
NtTerminateProcess .... ..... if (ARGUMENT_PRESENT (ProcessHandle)) { ProcessHandleSpecified = TRUE; } else { ProcessHandleSpecified = FALSE; ProcessHandle = NtCurrentProcess(); }
做这样的修改,可能的原因猜想是WINDOWS希望内核调用此函数时避过一些安全软件的SSDT HOOK,并达到对其的良好兼容
这样做确实是一个比较正确的做法,原因是系统的异常处理时,调用KiDispatchException函数,此函数将实现将内核中检测到的异常分发的到RING3的程序中,如果分发不成功,就调用ZwTerminateProcess结束此进程(也就是当前进程), KiDispatchException认为ZwTerminateProcess必然成功,如果ZwTerminateProcess返回(即未成功自杀),KiDispatchException则立即引发KeBugCheckEx
如果有一些安全软件保护了ZwTerminateProcess调用并拒绝来自KernelMode的请求,又遇到目标程序的异常处理没有正常分发,那么系统就会BSOD
当然,仅为了这一目的,替换KiDispatchException中调用的函数即可,但是可能MS觉得希望自己的调用不受到该死的HIPS的影响(其他WINDOWS组件,例如Windows User Mode framework reflector也使用了这个函数),所以做了这样一个改动
这样的改动使驱动级的进程结束更加轻松,但一些安全产品可能面临需要修改自己代码的问题~如果他们从nt!ZwTerminateProcss来定位ZwTerminateProcess的ID的话,那么就会失败了~
另外,一些使用0号HANDLE结束进程技巧的程序,例如著名的EVA同学的knlps,也将会失效了