0环进程断链

使用PsLookupProcessByProcessId操作Windows进程及其隐藏/显示的PEPROCESS函数
文章介绍了如何通过PsLookupProcessByProcessId查询PID为4的进程并获取PEPROCESS结构,以及如何隐藏和显示进程链表中的节点。作者展示了HideProcess函数用于从链表中移除进程,而UnHideProcess函数则用于恢复进程在链表中的位置。

通过PsLookupProcessByProcessId查询PID=4的进程获得eprocess,再通过偏移量遍历链表对比断链。

PEPROCESS HideProcess(PCHAR sourceName) {
	PEPROCESS processNode = 0;
	NTSTATUS status = PsLookupProcessByProcessId((HANDLE)4, &processNode);
	if (!NT_SUCCESS(status)) {
		DbgPrint("PsLookupProcessByProcessId\n");
		return STATUS_UNSUCCESSFUL;
	}

	PLIST_ENTRY pCur = processNode;
	PLIST_ENTRY pNext = processNode;
	STRING sourceStr = { 0 };
	RtlInitString(&sourceStr, sourceName);
	STRING targetStr = { 0 };
	do {
		pNext = (ULONG)((PLIST_ENTRY)((ULONG)pNext + 0xb8))->Flink - 0xb8;
		RtlInitString(&targetStr, (PCHAR)pNext + 0x16c);
		if (!RtlCompareString(&sourceStr, &targetStr, TRUE)) {
			DbgPrint("PROCESS:%p %s\n", pNext, (PCHAR)pNext + 0x16c);
			RemoveEntryList((ULONG)pNext + 0xb8);
			ObDereferenceObject(processNode);
			return pNext;
		}
	} while (pNext - pCur);
	ObDereferenceObject(processNode);
	return 0;
}

复原

VOID UnHideProcess(PEPROCESS processNode) {
	PLIST_ENTRY Node = (PUCHAR)processNode + 0xb8;
	PLIST_ENTRY LastNode = Node->Blink;
	PLIST_ENTRY NextNode = Node->Flink;
	LastNode->Flink = Node;
	NextNode->Blink = Node;
}
实现: 在内核中很多数据使用_LIST_ENTRY,双向循表作为数据结构 typedef struct _LIST_ENTRY { struct _LIST_ENTRY *Flink; struct _LIST_ENTRY *Blink; } LIST_ENTRY, *PLIST_ENTRY; 首先要先了解EPROCESS,和KPROCESS两个重要的结构体; 每个windows进程0都有这样一个对应的结构体: nt!_EPROCESS +0x000 Pcb : _KPROCESS +0x098 ProcessLock : _EX_PUSH_LOCK 进程锁 +0x0a0 CreateTime : _LARGE_INTEGER 进程创建时间 +0x0a8 ExitTime : _LARGE_INTEGER 进程结束时间 +0x0b0 RundownProtect : _EX_RUNDOWN_REF +0x0b4 UniqueProcessId : Ptr32 Void PID进程id +0x0b8 ActiveProcessLinks : _LIST_ENTRY 活跃进程表 双向循表 可 +0x0c0 ProcessQuotaUsage : [2] Uint4B 物理页相关统计 +0x0c8 ProcessQuotaPeak : [2] Uint4B +0x0d0 CommitCharge : Uint4B cpu占用信息 +0x0d4 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK +0x0d8 CpuQuotaBlock : Ptr32 _PS_CPU_QUOTA_BLOCK cpu占用信息 +0x0dc PeakVirtualSize : Uint4B 虚拟内存相关统计 +0x0e0 VirtualSize : Uint4B +0x0e4 SessionProcessLinks : _LIST_ENTRY +0x0ec DebugPort : Ptr32 Void 调试相关≠0则被调试 +0x0f0 ExceptionPortData : Ptr32 Void +0x0f0 ExceptionPortValue : Uint4B +0x0f0 ExceptionPortState : Pos 0, 3 Bits +0x0f4 ObjectTable : Ptr32 _HANDLE_TABLE 句柄表 内核对象 +0x0f8 Token : _EX_FAST_REF +0x0fc WorkingSetPage : Uint4B +0x100 AddressCreationLock : _EX_PUSH_LOCK +0x104 RotateInProgress : Ptr32 _ETHREAD +0x108 ForkInProgress : Ptr32 _ETHREAD +0x10c HardwareTrigger : Uint4B +0x110 PhysicalVadRoot : Ptr32 _MM_AVL_TABLE +0x114 CloneRoot : Ptr32 Void +0x118 NumberOfPrivatePages : Uint4B +0x11c NumberOfLockedPages : Uint4B +0x120 Win32Process : Ptr32 Void +0x124 Job : Ptr32 _EJOB +0x128 SectionObject : Ptr32 Void +0x12c SectionBaseAddress : Ptr32 Void +0x130 Cookie : Uint4B +0x134 Spare8 : Uint4B +0x138 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY +0x13c Win32WindowStation : Ptr32 Void +0x140 InheritedFromUniqueProcessId : Ptr32 Void 父进程id +0x144 LdtInformation : Ptr32 Void +0x148 VdmObjects : Ptr32 Void +0x14c ConsoleHostProcess : Uint4B +0x150 DeviceMap : Ptr32 Void +0x154 EtwDataSource : Ptr32 Void +0x158 FreeTebHint : Ptr32 Void +0x160 PageDirectoryPte : Uint8B +0x168 Session : Ptr32 Void +0x16c ImageFileName : [15] UChar 进程名最多存16个字符,截 +0x17b PriorityClass : UChar +0x17c JobLinks : _LIST_ENTRY +0x184 LockedPagesList : Ptr32 Void +0x188 ThreadListHead : _LIST_ENTRY 双向循表 +0x190 SecurityPort : Ptr32 Void +0x194 PaeTop : Ptr32 Void +0x198 ActiveThreads : Uint4B 活跃线程数量 +0x19c ImagePathHash : Uint4B +0x1a0 DefaultHardErrorProcessing : Uint4B +0x1a4 LastThreadExitStatus : Int4B +0x1a8 Peb : Ptr32 _PEB PEB(process ENVIRONMENT BLOCK 进程境块) +0x1ac PrefetchTrace : _EX_FAST_REF +0x1b0 ReadOperationCount : _LARGE_INTEGER +0x1b8 WriteOperationCount : _LARGE_INTEGER +0x1c0 OtherOperationCount : _LARGE_INTEGER +0x1c8 ReadTransferCount : _LARGE_INTEGER +0x1d0 WriteTransferCount : _LARGE_INTEGER +0x1d8 OtherTransferCount : _LARGE_INTEGER +0x1e0 CommitChargeLimit : Uint4B +0x1e4 CommitChargePeak : Uint4B +0x1e8 AweInfo : Ptr32 Void +0x1ec SeAuditProcessCreationInfo : 进程路径_SE_AUDIT_PROCESS_CREATION_INFO +0x1f0 Vm : _MMSUPPORT +0x25c MmProcessLinks : _LIST_ENTRY +0x264 HighestUserAddress : Ptr32 Void +0x268 ModifiedPageCount : Uint4B +0x26c Flags2 : Uint4B +0x26c JobNotReallyActive : Pos 0, 1 Bit +0x26c AccountingFolded : Pos 1, 1 Bit +0x26c NewProcessReported : Pos 2, 1 Bit +0x26c ExitProcessReported : Pos 3, 1 Bit +0x26c ReportCommitChanges : Pos 4, 1 Bit +0x26c LastReportMemory : Pos 5, 1 Bit +0x26c ReportPhysicalPageChanges : Pos 6, 1 Bit +0x26c HandleTableRundown : Pos 7, 1 Bit +0x26c NeedsHandleRundown : Pos 8, 1 Bit +0x26c RefTraceEnabled : Pos 9, 1 Bit +0x26c NumaAware : Pos 10, 1 Bit +0x26c ProtectedProcess : Pos 11, 1 Bit 保护进程 +0x26c DefaultPagePriority : Pos 12, 3 Bits +0x26c PrimaryTokenFrozen : Pos 15, 1 Bit +0x26c ProcessVerifierTarget : Pos 16, 1 Bit +0x26c StackRandomizationDisabled : Pos 17, 1 Bit +0x26c AffinityPermanent : Pos 18, 1 Bit +0x26c AffinityUpdateEnable : Pos 19, 1 Bit +0x26c PropagateNode : Pos 20, 1 Bit +0x26c ExplicitAffinity : Pos 21, 1 Bit +0x26c Spare1 : Pos 22, 1 Bit +0x26c ForceRelocateImages : Pos 23, 1 Bit +0x26c DisallowStrippedImages : Pos 24, 1 Bit +0x26c LowVaAccessible : Pos 25, 1 Bit +0x26c RestrictIndirectBranchPrediction : Pos 26, 1 Bit +0x26c AddressPolicyFrozen : Pos 27, 1 Bit +0x26c SpeculativeStoreBypassDisable : Pos 28, 1 Bit +0x270 Flags : Uint4B +0x270 CreateReported : Pos 0, 1 Bit +0x270 NoDebugInherit : Pos 1, 1 Bit +0x270 ProcessExiting : Pos 2, 1 Bit +0x270 ProcessDelete : Pos 3, 1 Bit +0x270 Wow64SplitPages : Pos 4, 1 Bit +0x270 VmDeleted : Pos 5, 1 Bit +0x270 OutswapEnabled : Pos 6, 1 Bit +0x270 Outswapped : Pos 7, 1 Bit +0x270 ForkFailed : Pos 8, 1 Bit +0x270 Wow64VaSpace4Gb : Pos 9, 1 Bit +0x270 AddressSpaceInitialized : Pos 10, 2 Bits +0x270 SetTimerResolution : Pos 12, 1 Bit +0x270 BreakOnTermination : Pos 13, 1 Bit +0x270 DeprioritizeViews : Pos 14, 1 Bit +0x270 WriteWatch : Pos 15, 1 Bit +0x270 ProcessInSession : Pos 16, 1 Bit +0x270 OverrideAddressSpace : Pos 17, 1 Bit +0x270 HasAddressSpace : Pos 18, 1 Bit +0x270 LaunchPrefetched : Pos 19, 1 Bit +0x270 InjectInpageErrors : Pos 20, 1 Bit +0x270 VmTopDown : Pos 21, 1 Bit +0x270 ImageNotifyDone : Pos 22, 1 Bit +0x270 PdeUpdateNeeded : Pos 23, 1 Bit +0x270 VdmAllowed : Pos 24, 1 Bit +0x270 CrossSessionCreate : Pos 25, 1 Bit +0x270 ProcessInserted : Pos 26, 1 Bit +0x270 DefaultIoPriority : Pos 27, 3 Bits +0x270 ProcessSelfDelete : Pos 30, 1 Bit +0x270 SetTimerResolutionLink : Pos 31, 1 Bit +0x274 ExitStatus : Int4B +0x278 VadRoot : _MM_AVL_TABLE +0x298 AlpcContext : _ALPC_PROCESS_CONTEXT +0x2a8 TimerResolutionLink : _LIST_ENTRY +0x2b0 RequestedTimerResolution : Uint4B +0x2b4 ActiveThreadsHighWatermark : Uint4B +0x2b8 SmallestTimerResolution : Uint4B +0x2bc TimerResolutionStackRecord : Ptr32 _PO_DIAG_STACK_RECORD +0x2c0 SequenceNumber : Uint8B +0x2c8 CreateInterruptTime : Uint8B +0x2d0 CreateUnbiasedInterruptTime : Uint8B +0x2d8 SecurityDomain : Uint8B _EPROCESS的第一个成员是KPROCESS nt!_KPROCESS +0x000 Header : _DISPATCHER_HEADER 可等待内核对象 +0x010 ProfileListHead : _LIST_ENTRY +0x018 DirectoryTableBase : Uint4B CR3 通过线性地址以及分页模式定位物理基地址 +0x01c LdtDescriptor : _KGDTENTRY +0x024 Int21Descriptor : _KIDTENTRY 历史遗留 +0x02c ThreadListHead : _LIST_ENTRY 双向循表 +0x034 ProcessLock : Uint4B 内核进程锁 +0x038 Affinity : _KAFFINITY_EX cpu亲核性 +0x044 ReadyListHead : _LIST_ENTRY 进程就绪列表 +0x04c SwapListEntry : _SINGLE_LIST_ENTRY交互磁盘 +0x050 ActiveProcessors : _KAFFINITY_EX 活跃核心 +0x05c AutoAlignment : Pos 0, 1 Bit 对齐 +0x05c DisableBoost : Pos 1, 1 Bit +0x05c DisableQuantum : Pos 2, 1 Bit 关闭时间碎片 +0x05c ActiveGroupsMask : Pos 3, 1 Bit +0x05c ReservedFlags : Pos 4, 28 Bits +0x05c ProcessFlags : Int4B +0x060 BasePriority : Char 基础优先级8,进程下所有线程最低的优先级 +0x061 QuantumReset : Char时间碎片 +0x062 Visited : UChar +0x063 Unused3 : UChar +0x064 ThreadSeed : [1] Uint4B +0x068 IdealNode : [1] Uint2B +0x06a IdealGlobalNode : Uint2B +0x06c Flags : _KEXECUTE_OPTIONS +0x06d AddressPolicy : UChar +0x06e IopmOffset : Uint2B +0x070 Unused4 : Uint4B +0x074 StackCount : _KSTACK_COUNT +0x078 ProcessListEntry : _LIST_ENTRY +0x080 CycleTime : Uint8B +0x088 KernelTime : Uint4B +0x08c UserTime : Uint4B +0x090 VdmTrapcHandler : Ptr32 Void //虚拟8086模式下使用 其中在_EPROCESS我们需要关注的是 ActiveProcessLinks 进程活跃表 SessionProcessLinks 会话表 ObjectTable 私有句柄表 其中在_KPROCESS我们需要关注的是 ProcessListEntry 进程表 想要隐藏进程把所在数据的进程即可 //关键代码 FORCEINLINE BOOLEAN MyRemoveEntryList( _In_ PLIST_ENTRY Entry ) { PLIST_ENTRY PrevEntry; PLIST_ENTRY NextEntry; NextEntry = Entry->Flink; PrevEntry = Entry->Blink; if ((NextEntry->Blink != Entry) || (PrevEntry->Flink != Entry)) { return FALSE; } PrevEntry->Flink = NextEntry; NextEntry->Blink = PrevEntry; return (BOOLEAN)(PrevEntry == NextEntry); } // // ProcessListEntry PLIST_ENTRY ProfileListHead = (PLIST_ENTRY)((PUCHAR)mypEProcess + 0x18); MyRemoveEntryList(ProfileListHead); // struct _LIST_ENTRY ThreadListHead; //0x30 PLIST_ENTRY ThreadListHead = (PLIST_ENTRY)((PUCHAR)mypEProcess + 0x30); MyRemoveEntryList(ProfileListHead); //struct_LIST_ENTRYSessionProcessLinks PLIST_ENTRY essionProcessLinks = (PLIST_ENTRY)((PUCHAR)mypEProcess + get_eprocess_session_offset()); MyRemoveEntryList(essionProcessLinks); // private ObjectTable _HANDLE_TABLE* table= (_HANDLE_TABLE*)((PUCHAR)mypEProcess + get_eprocess_objecttable_offset()); MyRemoveEntryList(table->HandleTableList); 当然仅仅是不够的,因为操作系统还有一张全局句柄表PspCidTable,其中存储了线程和进程,我们还需要把我们的进程从全局句柄表中抹除,可以使用ExDestroyHandle _int64 __fastcall ExDestroyHandle(__int64 a1, __int64 a2, __int64 a3) { unsigned int v6; // ebx if ( *(_QWORD *)(a1 + 96) ) ExpUpdateDebugInfo(a1, KeGetCurrentThread(), a2, 2i64); v6 = ExSweepSingleHandle(a1, a3); ExpFreeHandleTableEntry(a1, a2, a3); return v6; } if (instance->fn_get_os_build_number() == 7600 || instance->fn_get_os_build_number() == 7601) table_code = ((PHANDLE_TABLE_W7)table)->TableCode; else table_code = table->TableCode; auto level = table_code & 3; if (level == 1) { return (PHANDLE_TABLE_ENTRY)(*(uint64_t*)(table_code - 1 + 8 * (u_handle >> 10)) + 4 * (u_handle & 0X3FF)); } else if (level == 2) { return (PHANDLE_TABLE_ENTRY)(*(uint64_t*)(*(uint64_t*)(table_code - 2 + 8 * (u_handle >> 19)) + 8 * (u_handle >> 10 & 0X1FF)) + 4 * (u_handle & 0x3ff)); } else { return (PHANDLE_TABLE_ENTRY)(table_code + 4 * (u_handle & 0x3ff)); } 注:高版本对全局句柄表有加密 实验: 隐藏前DebugView 8404 隐藏后 需要注意,关闭进程前需要还原全局句柄表,不然会蓝屏; 其次在高版本系统上PG增加了对隐藏进程的检测,有概率触发蓝屏,不过没那么快,运气好能挺好几个小时; 具体的隐藏进程完整代码可以参考一份开源的:https://github.com/Oxygen1a1/HideProcess 那么问题来了,如果恶意软件隐藏自己的进程我们如何查询呢? 思考:进程是给用户看的,CPU不认识进程,代码也是跑在线程上面的 ,最重要的是cpu线程的调度是基于某些表进行调度的,如果把cpu调度表也了,进程也就跑不起来了,可谓是真正实现了无痕进程隐藏;其次内核中有很多表都能回溯到进程信息。 本人采用的方法是通过遍历枚举线程去回溯到进程,在 _ETHREAD中_CLIENT_ID储存了当前线程所属的进程id //0x10 bytes (sizeof) struct _CLIENT_ID { VOID* UniqueProcess; //0x0 VOID* UniqueThread; //0x8 }; 查询恶意隐藏进程思路:正常调用API遍历进程并存储表A,暴力枚举线程回溯进程并存储表B,如果B中的进程在A中找不到基本可以判进程进行了隐藏。 完善隐藏进程代码,方便学习
11-28
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值