在上一篇中说了一下ring3下简单的inline HOOK,写函数开头的方法还是比较通用的,而Call钩子虽然有隐蔽的优点,却需要对目标函数进行反汇编,都不适合大规模使用,还有push 、ret的方法,熟习的API的压栈原理,就很简单的,这些问题以后再讨论,这次我将上一篇文章里的代码移植到了ring0下,用来实现进程保护,ring3下破环进程的方法大致有下面几种:NtTerminateProcess/Thread,NtDuplicateObject(你不断的Dup并关闭对方句柄,对方最后也会退出的),NtWriteVirtualMemory在这之后创建一个远程线程让其ExitProcess,或者直接写入垃圾数据,就是内存填0杀进程了,UnmapViewOfSection,或者直接释放对方内存,ring3下常见的就是这几种了……这些函数都毫不例外的调用了ObReferenceObjectByHandle,函数,直接返回错误是最简单的方法,但是很显然不人性化,比如人家就查查你的信息,这个权限还是要给的(如360),当然了木马病毒除外了……,经过我的查看,对于线程我们要拦截的两个DesiredAccess=2和DesiredAccess=1的情况,前者用于暂停线程,后者用于结束线程,但是进程却要处理4个情况,分别对应暂停,结束,复制句柄,和写内存,UnmapView如下
//1 对应Terminate 800对应 Suspend 40对应Dumplicate 20对应ReadMemeory其中后面的UnMapView的权限和释放内存使用的是同样的权限,所以……
if(DesiredAccess==1||DesiredAccess==0x800||DesiredAccess==0x40||DesiredAccess==0x20||8)
所以很容易写出一个过滤函数来了
typedef NTSTATUS (__stdcall *DObReferenceObjectByHandle)(
HANDLE Handle,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
PVOID *Object,
POBJECT_HANDLE_INFORMATION HandleInformation
);
NTSTATUS __stdcall Detour_ObReferenceObjectByHandle(DObReferenceObjectByHandle Fun, IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
{
NTSTATUS Status;
PEPROCESS Eproc=0;
BOOLEAN Denied=FALSE;
if(*PsThreadType==ObjectType||*PsProcessType==ObjectType)
{
Status=Fun(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation);
if(NT_SUCCESS(Status)&&(*Object)!=NULL)
{
if(*PsThreadType==ObjectType)
{
Eproc=IoThreadToProcess((PETHREAD)(*Object));
if(DesiredAccess==2||DesiredAccess==1)
{
Denied=TRUE;
}
}
else
{
//1 对应Terminate 800对应 Suspend 40对应Dumplicate 20对应ReadMemeory8对应UnMapViewOfSection
if(DesiredAccess==1||DesiredAccess==0x800||DesiredAccess==0x40||DesiredAccess==0x20||DesiredAccess==8)
Denied=TRUE;
Eproc=(PEPROCESS)(*Object);
}
ULONG Pid=(ULONG)PsGetProcessId(Eproc);
PPROCESS_NODE Node=LookupPid(Pid);
if(Denied&&Node&&Node->Process!=PsGetCurrentProcess())
{
KdPrint(("Process:%d 尝试操作保护进程!!已拒绝\n",PsGetCurrentProcessId()));
ObDereferenceObject(*Object);
*Object=0;
return STATUS_ACCESS_DENIED;
}
}
return Status;
}
return Fun(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation);
}
过滤函数很简单,可能和大家以前看到的带了好多汇编指令的裸函数有很大不同,是不是看上去很爽啊?代码编写也很简单,原因就是我上一篇的那个Hook方法,来到ring0依然可行,并且可以大幅降低自己处理堆栈的难度……至于那个代码的移植,相信只要你看懂了ring3的,移植自然不在话下了,可以写成一个Hook库,以后就方便……嗯试试效果,达到了预期效果,当然了对付冰刃也是可以的,关键在于怎么保护自己的钩子不被恢复……这个问题就仁者见仁了……
有点废话的是Windows7下微软已经提供保护方法了,这个也就是在XP和Vista下玩玩了,主要并不是说明怎么保护进程,而是说明上一篇的HOOK结构的用途,以及实现人性化的过滤处理,因为如果为了保护进程还是可以做得更底层的……