发现res区现在编程风行哈~ 眼看就要开学,偶再不鲜点血就说不过去了 :P
其实是比较老的东西了 不过个人感觉似乎还是有点意义的 :)
应该能过taskmgr,IceSword(IceSword的线程信息中一个一个线程的杀还是可以干掉这种的,之于如何防IceSword按线程杀以后再讲:)),DarkSpy 1.0.5.0(我没有办法拿到内部版 所以不知道内部版是什么样的情况:P),SnipeSword (截至偶发贴之前的所有版本),GMER 1.0.13.12551(我所能拿到的最新版本)
过不了Rootkit Unhooker的虚拟内存清零(RkU的以后再讲:P),也过不了Simple Taskmgr 1.0.303
事实上,在simple taskmgr 1.0.303(st)中,所有被提及的全能bypass掉(DarkSpy杀st的时候会蓝屏T_T),不过st用的是ring0 inline hook API,暂时不说。
IceSword杀进程是使用NtTerminateProcess(当然是先恢复掉hook咯 :P),DarkSpy似乎是自己实现了一个PspTerminateProcess(但是并没有实现PspTerminateThreadByPointer),SnipeSword也是使用NtTerminateProcess(调用前恢复hook)。
无论是NtTerminateProcess还是PspTerminateProcess,最终都是调用了PspTerminateThreadByPointer(可以通过windows 2k的源代码或者wrk来看到)
以下以wrk中的代码为例,windows 2k中PspTerminateThreadByPointer的参数是两个,wrk中为三个。不过这些我们不需要关心:P
NtTerminateProcess节选如下:
Quote:
NTSTATUS
NtTerminateProcess(
__in_opt HANDLE ProcessHandle,
__in NTSTATUS ExitStatus
)
{
//省略...
st = STATUS_NOTHING_TO_TERMINATE;
for (Thread = PsGetNextProcessThread (Process, NULL);
Thread != NULL;
Thread = PsGetNextProcessThread (Process, Thread)) {
st = STATUS_SUCCESS;
if (Thread != Self) {
PspTerminateThreadByPointer (Thread, ExitStatus, FALSE);
}
}
//省略...
return st;
}
PspTerminateProcess(因为PspTerminateProcess相对比较简单,就全复制过来了):
Quote:
NTSTATUS
PspTerminateProcess(
PEPROCESS Process,
NTSTATUS ExitStatus
)
{
PETHREAD Thread;
NTSTATUS st;
PAGED_CODE();
if (Process->Flags
& PS_PROCESS_FLAGS_BREAK_ON_TERMINATION) {
PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
Process,
Process->ImageFileName);
}
PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_PROCESS_DELETE);
st = STATUS_NOTHING_TO_TERMINATE;
for (Thread = PsGetNextProcessThread (Process, NULL);
Thread != NULL;
Thread = PsGetNextProcessThread (Process, Thread)) {
st = STATUS_SUCCESS;
PspTerminateThreadByPointer (Thread, ExitStatus, FALSE);
}
if (st == STATUS_NOTHING_TO_TERMINATE || Process->DebugPort != NULL) {
ObClearProcessHandleTable (Process);
st = STATUS_SUCCESS;
}
return st;
}
可以看到这两个最后都是使用PspTerminateThreadByPointer来按照线程来终止的。
再看看PspTerminateThreadByPointer的代码(节选):
Quote:
NTSTATUS
PspTerminateThreadByPointer(
IN PETHREAD Thread,
IN NTSTATUS ExitStatus,
IN BOOLEAN DirectTerminate
)
{
//省略...
if (DirectTerminate && Thread == PsGetCurrentThread()) {
ASSERT (KeGetCurrentIrql() < APC_LEVEL);
PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_TERMINATED);
PspExitThread (ExitStatus);
} else {
if (IS_SYSTEM_THREAD (Thread)) {
return STATUS_ACCESS_DENIED;
}
//省略...
}
return Status;
}
也就是说,只要是“他杀”(当前进程(PsGetCurrentThread())不等于参数Thread),那么就会判断IS_SYSTEM_THREAD这个宏 如果为true,就直接返回STATUS_ACCESS_DENIED(拒绝访问)
Quote:
#define IS_SYSTEM_THREAD(Thread) (((Thread)->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_SYSTEM) != 0)
从PspTerminateThreadByPointer的参数表上我们可以知道,Thread是一个PETHREAD类型的数据。
而PETHREAD被定义为*ETHREAD,也就是ETHREAD结构的指针。
ETHREAD结构(来自windbg,结构为xp sp2下的——这个结构在不同系统下不一定相同,CrossThreadFlags在ETHREAD结构中的偏移需要根据系统来判断):
Quote:
lkd> dt _ETHREAD
nt!_ETHREAD
+0x000 Tcb : _KTHREAD
+0x1c0 CreateTime : _LARGE_INTEGER
+0x1c0 NestedFaultCount : Pos 0, 2 Bits
+0x1c0 ApcNeeded : Pos 2, 1 Bit
+0x1c8 ExitTime : _LARGE_INTEGER
+0x1c8 LpcReplyChain : _LIST_ENTRY
+0x1c8 KeyedWaitChain : _LIST_ENTRY
+0x1d0 ExitStatus : Int4B
+0x1d0 OfsChain : Ptr32 Void
+0x1d4 PostBlockList : _LIST_ENTRY
+0x1dc TerminationPort : Ptr32 _TERMINATION_PORT
+0x1dc ReaperLink : Ptr32 _ETHREAD
+0x1dc KeyedWaitValue : Ptr32 Void
+0x1e0 ActiveTimerListLock : Uint4B
+0x1e4 ActiveTimerListHead : _LIST_ENTRY
+0x1ec Cid : _CLIENT_ID
+0x1f4 LpcReplySemaphore : _KSEMAPHORE
+0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
+0x208 LpcReplyMessage : Ptr32 Void
+0x208 LpcWaitingOnPort : Ptr32 Void
+0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION
+0x210 IrpList : _LIST_ENTRY
+0x218 TopLevelIrp : Uint4B
+0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT
+0x220 ThreadsProcess : Ptr32 _EPROCESS
+0x224 StartAddress : Ptr32 Void
+0x228 Win32StartAddress : Ptr32 Void
+0x228 LpcReceivedMessageId : Uint4B
+0x22c ThreadListEntry : _LIST_ENTRY
+0x234 RundownProtect : _EX_RUNDOWN_REF
+0x238 ThreadLock : _EX_PUSH_LOCK
+0x23c LpcReplyMessageId : Uint4B
+0x240 ReadClusterSize : Uint4B
+0x244 GrantedAccess : Uint4B
+0x248 CrossThreadFlags : Uint4B
+0x248 Terminated : Pos 0, 1 Bit
+0x248 DeadThread : Pos 1, 1 Bit
+0x248 HideFromDebugger : Pos 2, 1 Bit
+0x248 ActiveImpersonationInfo : Pos 3, 1 Bit
+0x248 SystemThread : Pos 4, 1 Bit
+0x248 HardErrorsAreDisabled : Pos 5, 1 Bit
+0x248 BreakOnTermination : Pos 6, 1 Bit
+0x248 SkipCreationMsg : Pos 7, 1 Bit
+0x248 SkipTerminationMsg : Pos 8, 1 Bit
+0x24c SameThreadPassiveFlags : Uint4B
+0x24c ActiveExWorker : Pos 0, 1 Bit
+0x24c ExWorkerCanWaitUser : Pos 1, 1 Bit
+0x24c MemoryMaker : Pos 2, 1 Bit
+0x250 SameThreadApcFlags : Uint4B
+0x250 LpcReceivedMsgIdValid : Pos 0, 1 Bit
+0x250 LpcExitThreadCalled : Pos 1, 1 Bit
+0x250 AddressSpaceOwner : Pos 2, 1 Bit
+0x254 ForwardClusterOnly : UChar
+0x255 DisablePageFaultClustering : UChar
理论上都都讲完了,我们来回顾下:
1、不论SnipeSword,IceSword,DarkSpy,又或是GMER(如果我没记错,GMER应该是使用NtTerminateProcess的方法来结束进程的),最终杀进程都要过PspTerminateThreadByPointer
2、PspTerminateThreadByPointer会检查线程的SystemThread标志(ETHREAD结构中CrossThreadFlags的第四位),如果被置为1,就返回拒绝访问(STATUS_ACCESS_DENIED)
3、ETHREAD结构在不同系统中不同,所以我们需要判断操作系统版本(这个我不会在演示代码中出现,交给大家了:P)。
但是我们仍然有一些问题没有解决:
1、进程的ETHREAD结构在内存中的地址是多少?
2、ETHREAD结构存在于系统高2G空间,如何修改?
至于判断系统版本,相信大家都会 :)
1、ETHREAD结构的地址
ntdll.dll导出了一个未文档化的函数——NtQuerySystemInformation,它可以用来查询SystemHandleInformation,查询SystemHandleInformation的返回的数据结构如下(懒得再弄vb的了,直接把C的弄过来,这个可能跟我的代码中的定义有些不同,但是实际上被用到的数据在结构中的偏移是相同的:P):
Quote:
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
USHORT UniqueProcessId;
USHORT CreatorBackTraceIndex;
UCHAR ObjectTypeIndex;
UCHAR HandleAttributes;
USHORT HandleValue;
PVOID Object;
ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG NumberOfHandles;
SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[ 1 ];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
NumberOfHandles表示返回的数组个数,SYSTEM_HANDLE_TABLE_ENTRY_INFO则是返回的数据。
SYSTEM_HANDLE_TABLE_ENTRY_INFO中的HandleValue是句柄的值,Object便是这个Handle对应的对象(Object,如果Handle类型为线程,那么这个对象就是ETHREAD结构)的地址。
嗯,我想我说的还是比较清楚的。
2、修改物理内存
ntdll.dll还导出了一个函数叫做NtSystemDebugControl,这个函数可以用来操作高2G的内存空间。
剩下的废话不多说了~ 大家看附件把 :)