查看文章 |
进程防结束之PS_CROSS_THREAD_FLAGS_SYSTEM
2010-03-26 22:47
http://hi.baidu.com/cicitech/blog/item/dba014ee50bb041efcfa3c75.html 这种方法的关键 在于给线程的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 很 明显test byte ptr [eax+248h],10h中的248h就是CrossThreadFlags在ETHREAD里的偏移了,test byte ptr [eax+xxxxxxxx],10h的16进制是f680xxxxxxxx10,现在只要先获得PsTerminateSystemThread的地 址,然后向后搜索0x80f6,搜索到后再后面的4个字节就是CrossThreadFlags在ETHREAD里的偏移了。 得到了偏移,下面就是写代码了,驱动部分: #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键值。 最后,怎么结束用这种方法保护的进程?方法大大的有,插入APC,然后PspExitThread就不会经过PspTerminateThreadByPointer了。 |
最近读者:

