_ETHREAD断链 —— 实现线程隐藏

简介

线程所属的父进程 _EPROCESS 结构体中的 ThreadListHead 成员是当前进程中所有线程的双向链表头,该成员有两个,分别在 0x500x190 处。我们可以通过该线程链表头进行线程遍历,也可以通过直接遍历 _ETHREAD 结构体中的 ThreadListEntry 成员实现遍历进程中的所有线程,ThreadListEntry 分别位于 0x1b00x22c 处。

我们可以通过 _ETHREADThreadListEntry 断链实现线程隐藏。需要注意的是,ThreadListEntry 中的地址不能直接置为0,而是因指向自己,否则会触发蓝屏。

关于 _EPRICESS 的结构体,可参考
_EPROCESS断链 —— 实现进程内核隐藏


_ETHREAD

_ETHREAD 的结构如下:

kd> dt _ETHREAD
nt!_ETHREAD
   +0x000 Tcb              : _KTHREAD	//“可等待”对象,比如Mutex互斥体、Event事件等(WaitForSingleObject)
   /*
   	kd> dt _KTHREAD
    nt!_KTHREAD
       +0x000 Header           : _DISPATCHER_HEADER
       +0x010 MutantListHead   : _LIST_ENTRY
       +0x018 InitialStack     : Ptr32 Void		// 记录R0栈顶初始地址, 用于线程切换
       +0x01c StackLimit       : Ptr32 Void		// 记录R0栈界限
       +0x020 Teb              : Ptr32 Void		// R3 _TEB, Thread Environment Block, 线程环境块
       											// fs[0]: R3 表示_TEB; R0表示 KPCR
       +0x024 TlsArray         : Ptr32 Void
       +0x028 KernelStack      : Ptr32 Void		// 记录R0栈顶, 用于线程切换时, 填充TSS的ESP0
       +0x02c DebugActive      : UChar	// 当前线程是否处于调试状态
       									// 如果值为-1 不能使用调试寄存器:Dr0 - Dr7
       +0x02d State            : UChar	// 当前线程的状态, 就绪、阻塞
       +0x02e Alerted          : [2] UChar
       +0x030 Iopl             : UChar
       +0x031 NpxState         : UChar
       +0x032 Saturation       : Char
       +0x033 Priority         : Char
       +0x034 ApcState         : _KAPC_STATE		// APC 相关	
       +0x04c ContextSwitches  : Uint4B
       +0x050 IdleSwapBlock    : UChar
       +0x051 Spare0           : [3] UChar
       +0x054 WaitStatus       : Int4B
       +0x058 WaitIrql         : UChar
       +0x059 WaitMode         : Char
       +0x05a WaitNext         : UChar
       +0x05b WaitReason       : UChar
       +0x05c WaitBlockList    : Ptr32 _KWAIT_BLOCK
       +0x060 WaitListEntry    : _LIST_ENTRY	// 等待链表
       +0x060 SwapListEntry    : _SINGLE_LIST_ENTRY	// 就绪链表
       +0x068 WaitTime         : Uint4B
       +0x06c BasePriority     : Char	// 其初始值是所属进程的BasePriority值, 
       									// 以后可以通过KeSetBasePriorityThread()函数重新设定
       +0x06d DecrementCount   : UChar
       +0x06e PriorityDecrement : Char
       +0x06f Quantum          : Char
       +0x070 WaitBlock        : [4] _KWAIT_BLOCK	// 等待哪个对象(WaitForSingleObject)
       +0x0d0 LegoData         : Ptr32 Void
       +0x0d4 KernelApcDisable : Uint4B
       +0x0d8 UserAffinity     : Uint4B
       +0x0dc SystemAffinityActive : UChar
       +0x0dd PowerState       : UChar
       +0x0de NpxIrql          : UChar
       +0x0df InitialNode      : UChar
       +0x0e0 ServiceTable     : Ptr32 Void		//系统服务表
       +0x0e4 Queue            : Ptr32 _KQUEUE
       +0x0e8 ApcQueueLock     : Uint4B			// APC相关
       +0x0f0 Timer            : _KTIMER
       +0x118 QueueListEntry   : _LIST_ENTRY
       +0x120 SoftAffinity     : Uint4B
       +0x124 Affinity         : Uint4B
       +0x128 Preempted        : UChar
       +0x129 ProcessReadyQueue : UChar
       +0x12a KernelStackResident : UChar
       +0x12b NextProcessor    : UChar
       +0x12c CallbackStack    : Ptr32 Void
       +0x130 Win32Thread      : Ptr32 Void
       +0x134 TrapFrame        : Ptr32 _KTRAP_FRAME		// 进0环时保存环境
       +0x138 ApcStatePointer  : [2] Ptr32 _KAPC_STATE		// APC 相关
       +0x140 PreviousMode     : Char	//先前模式,记录先前是0环,还是3环
       +0x141 EnableStackSwap  : UChar
       +0x142 LargeStack       : UChar
       +0x143 ResourceIndex    : UChar
       +0x144 KernelTime       : Uint4B
       +0x148 UserTime         : Uint4B
       +0x14c SavedApcState    : _KAPC_STATE			// APC 相关
       +0x164 Alertable        : UChar
       +0x165 ApcStateIndex    : UChar
       +0x166 ApcQueueable     : UChar
       +0x167 AutoAlignment    : UChar
       +0x168 StackBase        : Ptr32 Void
       +0x16c SuspendApc       : _KAPC
       +0x19c SuspendSemaphore : _KSEMAPHORE
       +0x1b0 ThreadListEntry  : _LIST_ENTRY	// 双向链表, 记录进程中的所有模块
       +0x1b8 FreezeCount      : Char
       +0x1b9 SuspendCount     : Char
       +0x1ba IdealProcessor   : UChar
       +0x1bb DisableBoost     : UChar
   */
   +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		
   /*
   	kd> dt _CLIENT_ID
    nt!_CLIENT_ID
       +0x000 UniqueProcess    : Ptr32 Void		// PID
       +0x004 UniqueThread     : Ptr32 Void		// ThreadID
   */
   +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	// 指向父进程的 _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

Code

NTSTATUS _NtThreadHide(ULONG uPid)
{
	PEPROCESS pEPROCESS;
	LPSTR lpImageFileName;

	__asm
	{
		mov eax, fs: [0x124] 
		mov eax, [eax + 0x220]
		mov pEPROCESS, eax
	}
	PLIST_ENTRY pHeader = (PCHAR)pEPROCESS + 0x88;
	PLIST_ENTRY pCur = pHeader;

	do
	{
		if (*(PLONG)((ULONG)pCur - 4) == uPid)
		{
			PLIST_ENTRY pEThreadHeader1, pEThreadHeader2, pEThreadCur, pEThreadNext;
			ULONG uSizeOfLIST_ENTRY = sizeof(LIST_ENTRY);
			lpImageFileName = (PCHAR)pCur + 0xec;
			DbgPrint("该进程名称: %s\n", lpImageFileName);
			pEThreadHeader1 = (PCHAR)pCur - 0x88 + 0x50; // 模块链表头
			pEThreadHeader2 = (PCHAR)pCur - 0x88 + 0x190;	// 模块链表头

			pEThreadCur = pEThreadHeader1;
			do 
			{
				pEThreadNext = pEThreadCur->Blink;
				pEThreadCur->Flink = pEThreadCur;
				pEThreadCur->Blink = pEThreadCur;
				pEThreadCur = pEThreadNext;
				
			} while (pEThreadHeader1 == pEThreadCur);

			pEThreadCur = pEThreadHeader2;
			do
			{
				pEThreadNext = pEThreadCur->Blink;
				pEThreadCur->Flink = pEThreadCur;	// 指向自己, 不能直接置为0, 否则会触发蓝屏
				pEThreadCur->Blink = pEThreadCur;
				pEThreadCur = pEThreadNext;

			} while (pEThreadHeader1 == pEThreadCur);

			DbgPrint("线程隐藏成功!\n");
			return STATUS_SUCCESS;
		}
		pCur = pCur->Blink;
	} while (pCur != pHeader);
	return STATUS_ABANDONED;
}

测试进程的 PID 为 980,有一个线程。
在这里插入图片描述

当执行 _EtHReAD 断链后,线程数变为了0,说明成功实现了对线程的隐藏。
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值