这种方法的关键在于给线程的ETHREAD.CrossThreadFlags设置PS_CROSS_THREAD_FLAGS_SYSTEM值,这样其它进程就无法结束它了,包括IceSword、RkU。至于原理,那就先看看wrk里结束进程的那几个内核函数源码,NtTerminateProcess、PsTerminateProcess、PspTerminateProcess最终都是调用PspTerminateThreadByPointer来将每个线程杀死,而在PspTerminateThreadByPointer里,如果线程是被其它进程强x结束的,就会有个这样的判断:
-
if (IS_SYSTEM_THREAD (Thread ) ) {
-
return STATUS_ACCESS_DENIED;
-
}
Thread类型是PETHREAD,IS_SYSTEM_THREAD是个宏,如下:
-
#define IS_SYSTEM_THREAD (Thread ) ( ( (Thread ) - >CrossThreadFlags &PS_CROSS_THREAD_FLAGS_SYSTEM ) ! = 0 )
也就是说当线程的ETHREAD.CrossThreadFlags包含PS_CROSS_THREAD_FLAGS_SYSTEM位时,就直接返回拒绝访问,这样线程就不会被结束了。具体参考代码请看wrk 1.2里的文件base\ntos\ps\psdelete.c。
好,现在只要给我们的进程里的每个线程都设置PS_CROSS_THREAD_FLAGS_SYSTEM,进程就不会被结束掉了。但是ETHREAD的结构没有文档化,所以还得自己找到CrossThreadFlags成员在ETHREAD结构里的偏移。可以通过在已导出的相关函数中找一些特征来定位CrossThreadFlags,黑防中是在PsIsSystemThread里找,但是这个函数在Windows 2000里没有,所以我们换个,换成PsTerminateSystemThread,先看下PsTerminateSystemThread的源码:
-
NTSTATUS
-
PsTerminateSystemThread (
-
__in NTSTATUS ExitStatus
-
)
-
{
-
PETHREAD Thread = PsGetCurrentThread ( );
-
-
if ( !IS_SYSTEM_THREAD (Thread ) ) {
-
return STATUS_INVALID_PARAMETER;
-
}
-
-
return PspTerminateThreadByPointer (Thread, ExitStatus, TRUE );
-
}
这里也用到了IS_SYSTEM_THREAD,那么也一定会有定位CrossThreadFlags的代码,如下:
-
kd> u PsTerminateSystemThread
-
nt!PsTerminateSystemThread :
-
805c89f8 8bff mov edi , edi
-
805c89fa 55 push ebp
-
805c89fb 8bec mov ebp , esp
-
805c89fd 64a124010000 mov eax , dword ptr fs : [ 00000124h ]
-
805c8a03 f6804802000010 test byte ptr [ eax + 248h ] , 10h
-
805c8a0a 7507 jne nt!PsTerminateSystemThread + 0x1b (805c8a13 )
-
805c8a0c b80d0000c0 mov eax , 0C000000Dh
-
805c8a11 eb09 jmp nt!PsTerminateSystemThread + 0x24 (805c8a1c )
-
805c8a13 ff7508 push dword ptr [ ebp + 8 ]
-
805c8a16 50 push eax
-
805c8a17 e828fcffff call nt!PspTerminateThreadByPointer (805c8644 )
-
805c8a1c 5d pop ebp
-
805c8a1d c20400 ret 4
得到了偏移,下面就是写代码了,驱动部分:
-
#include <ntifs. h >
-
#include <ntddk. h >
-
-
#define PS_CROSS_THREAD_FLAGS_SYSTEM 0x00000010UL //form wrk 1.2 base\ntos\inc\ps.h
-
#define IOCTL_THREAD_PROTECT CTL_CODE (FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS )
-
-
VOID DriverUnload (PDRIVER_OBJECT pDriverObject )
-
{
-
UNICODE_STRING usSymLink;
-
RtlInitUnicodeString ( &usSymLink, L "\\??\\ThreadProtect" );
-
IoDeleteSymbolicLink ( &usSymLink );
-
IoDeleteDevice (pDriverObject - >DeviceObject );
-
}
-
-
NTSTATUS DispatchCreateClose (PDEVICE_OBJECT pDeviceObject, PIRP pIrp )
-
{
-
pIrp - >IoStatus. Status = STATUS_SUCCESS;
-
pIrp - >IoStatus. Information = 0;
-
IoCompleteRequest (pIrp, IO_NO_INCREMENT );
-
-
return STATUS_SUCCESS;
-
}
-
-
NTSTATUS DispatchControl (PDEVICE_OBJECT pDeviceObject, PIRP pIrp )
-
{
-
NTSTATUS nRet = STATUS_UNSUCCESSFUL;
-
ULONG_PTR uInf = 0;
-
PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation (pIrp );
-
PVOID pSysBuff = pIrp - >AssociatedIrp. SystemBuffer;
-
-
switch (pIoStack - >Parameters. DeviceIoControl. IoControlCode )
-
{
-
case IOCTL_THREAD_PROTECT :
-
PETHREAD pEThread;
-
PsLookupThreadByThreadId (HANDLE ( * (PULONG )pSysBuff ), &pEThread );
-
UNICODE_STRING usName;
-
RtlInitUnicodeString ( &usName, L "PsTerminateSystemThread" );
-
PUSHORT pOffset = (PUSHORT )MmGetSystemRoutineAddress ( &usName );
-
-
//search "test byte ptr [eax+xxxxxxxx],10h",hex:f680xxxxxxxx10
-
while ( *pOffset ! = 0x80f6 )
-
pOffset = PUSHORT ( (PUCHAR )pOffset + 1 );
-
PULONG pFlags = PULONG ( (PUCHAR )pEThread + * (PULONG ) (pOffset + 1 ) );
-
DbgPrint ( "pOffset:%08x, CrossFlagOffset:%08x\r\n", pOffset, * (PULONG ) (pOffset + 1 ) );
-
*pFlags |= PS_CROSS_THREAD_FLAGS_SYSTEM; //set PS_CROSS_THREAD_FLAGS_SYSTEM bit
-
nRet = STATUS_SUCCESS;
-
uInf = 0;
-
break;
-
}
-
-
pIrp - >IoStatus. Status = nRet;
-
pIrp - >IoStatus. Information = uInf;
-
IoCompleteRequest (pIrp, IO_NO_INCREMENT );
-
return nRet;
-
}
-
-
extern "C" NTSTATUS DriverEntry (PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath )
-
{
-
pDriverObject - >DriverUnload = DriverUnload;
-
pDriverObject - >MajorFunction [IRP_MJ_CREATE ] = DispatchCreateClose;
-
pDriverObject - >MajorFunction [IRP_MJ_CLOSE ] = DispatchCreateClose;
-
pDriverObject - >MajorFunction [IRP_MJ_DEVICE_CONTROL ] = DispatchControl;
-
-
UNICODE_STRING usDeviceName;
-
RtlInitUnicodeString ( &usDeviceName, L "\\Device\\ThreadProtect" );
-
-
NTSTATUS nRet;
-
PDEVICE_OBJECT pDeviceObject;
-
nRet = IoCreateDevice (pDriverObject, 0, &usDeviceName, FILE_DEVICE_UNKNOWN,
-
FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject );
-
if ( !NT_SUCCESS (nRet ) )
-
return nRet;
-
-
UNICODE_STRING usSymLink;
-
RtlInitUnicodeString ( &usSymLink, L "\\??\\ThreadProtect" );
-
nRet = IoCreateSymbolicLink ( &usSymLink, &usDeviceName );
-
if ( !NT_SUCCESS (nRet ) )
-
{
-
IoDeleteDevice (pDeviceObject );
-
return nRet;
-
}
-
return STATUS_SUCCESS;
-
}
这段代码要解释的都在上面了。EXE部分的代码就不用帖了,只要将每个线程的ID通过DeviceIoControl传入驱动即可:
-
#define IOCTL_THREAD_PROTECT CTL_CODE (FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS )
-
-
DeviceIoControl (hDevice, IOCTL_THREAD_PROTECT, &nThreadId, sizeof (nThreadId ), 0, 0, &nByteRet, 0 );
点击这里下载文件: ThreadProtect.rar
运行后果自行负责,运行不了自行想办法到注册表里删除先前的ThreadProtect键值。
最后,怎么结束用这种方法保护的进程?方法大大的有,插入APC,然后PspExitThread就不会经过PspTerminateThreadByPointer了。