【原创】拦截进程创建(不会卡死桌面)

  • Post author:
  • Post category:其他


之前看过很多关于进程创建的拦截,都是勾在NtCreateProcess或者NtCreateSection上,拦截到的往往都是Explorer进程中的线程,此时如果将线程卡在内核中,就会导致桌面卡死。这不是我想要的。

百度GOOGLE了好久,没找到类似的解决办法,逆又逆不出来,就只有自己翻书动脑子了(不知道各大安全卫士是怎么实现的:eek:)。

既然不能卡死Explorer的线程,那咱就卡别人去,卡谁?我想你已经知道了——被创建者的主线程:p:

相关知识:

每一个线程都是从内核空间的KiThreadStartup开始运行的,线程在被创建的时候就指定了它在系统空间的上下文以及返回用户空间的自陷框架。在KiThreadStartup中,线程将运行级别降低至APC_LEVEL后调用PspUserThreadStartup(如果是系统线程,这里调用的是PspSystemThreadStartup),PspUserThreadStartup将用户空间ntdll.dll中的函数LdrInitializeThunk作为APC函数挂入APC队列。当线程返回用户空间时,就会检测到APC函数的存在,并先加以执行,直到APC队列中不再有请求时才算正式回到用户空间。

回到用户空间的什么地方呢?这要看线程被创建的时候设定的自陷框架了。如果是主线程,则回到BaseProcessStartup,非主线程则是BaseThreadStartup。至于用户空间给定的线程入口(如主线程的OEP),则存放在寄存器EAX中,作为参数调用BaseProcessStartup或者BaseThreadStartup,再由这二者之一将其放在一个SEH保护域中加以调用。

实现:

如果上面看晕了,没关系,只需知道每个线程都是在KiThreadStartup中开始运行的,如果是用户线程,则会调用PspUserThreadStartup。注意此时的IRQL为APC_LEVEL。

而我选择的挂钩地点就是PspUserThreadStartup。E9跳转需要5个字节,我选择在PspUserThreadStartup+2的位置JMP,即

kd> u PspUserThreadStartup

nt!PspUserThreadStartup:

805c7050 6a20 push 20h

805c7052 6870ae4d80 push offset nt!ObWatchHandles+0x61c (804dae70)

805c7057 e8c41ef7ff call nt!_SEH_prolog (80538f20)

805c705c 64a124010000 mov eax,dword ptr fs:[00000124h]

805c7062 8bf0 mov esi,eax

805c7064 8975e0 mov dword ptr [ebp-20h],esi

805c7067 8b7e44 mov edi,dword ptr [esi+44h]

805c706a 897ddc mov dword ptr [ebp-24h],edi

相关函数:

程序中的g_uStartSign,是用来判断线程是否是进程的主线程的。它记录的是线程在用户空间的开始地址,如果是主线程,它就是BaseProcessStartup,非主线程就是BaseThreadStartup。ETHREAD结构中有这个值。g_uStartSign的赋值是通过创建一个线程(肯定不是主线程)调用DeviceIoControl,然后通过ETHREAD活得,这个值是BaseThreadStartup的地址。BaseProcessStartup和BaseThreadStartup是kernel32.dll中的函数,kernel32.dll在每个进程中映射的位置都相同,因此这两个函数的地址也在每个进程中也都相同。



版权声明:本文为myworldbig原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。