hook方式进程创建监控,进程保护

博客围绕进程创建监控和进程保护展开。进程创建监控方面,介绍了不同系统下进程创建调用流程,提及Hook NtCreateSection及过滤情况,还给出获取子进程路径等方法。进程保护方面,阐述应用层和内核层杀死进程函数,介绍通过hook和回调保护进程,以及结束任务保护的解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于进程创建,

xp系统:CreatProcessW->CreateProcessInternalW->NtCreateProcessEx->NtCreatSection

Vista以上:CCreatProcessW->CreateProcessInternalW->NtCreateUserProcess->NtCreateSection

所以我们要HookNtCreateSection

而系统调用NtCreateSecton时有多种情况,不只是创建进程时,我们要过滤排除掉其他情况。

发现只有

(Protect (PAGE_EXECUTE/*|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY*/)&&(Attributes == SEC_IMAGE) && FileHandle)

发现这些可以在创建进程时windbg在此下断,观察参数,或者去看wrk,reactos代码。

还要去得到子进程路径。

另外其实使用文件过滤监控IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION更好,这个函数会走这个IRP。因为通过过滤支持x64,ssdthook只支持x86.或者使用回调PsSetCreateProcessNotifyRoutineEx。注册回调,这样在进程创建时候回调用他。

监控代码片段

NTSTATUS NTAPI HOOK_NtCreateSection(PHANDLE SectionHandle,
				  ACCESS_MASK DesiredAccess,
				  POBJECT_ATTRIBUTES ObjectAttributes,
				  PLARGE_INTEGER SectionSize,
				  ULONG Protect,
				  ULONG Attributes,
				  HANDLE FileHandle)//代理函数 
{
	PFILE_OBJECT    			FileObject = NULL; 
	POBJECT_NAME_INFORMATION 	wcFilePath = NULL;
	ANSI_STRING 				dst = {0};
	UNICODE_STRING				ustrProcessPath = {0};
	WCHAR						wszProcessPath[MAX_PATH] = {0};
	NTSTATUS					ntStatus = 0;

	__try
	{
		if (Protect & (PAGE_EXECUTE/*|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY*/)&&
			(Attributes == SEC_IMAGE) && 
		    FileHandle)
		{
			if (NT_SUCCESS(ObReferenceObjectByHandle(FileHandle,0,NULL,KernelMode,&FileObject,NULL)))//获取文件对象,这里类型最好不要传NULL,不然会有问题
			{
				//获取FileObject对应的文件全路径
				if (IoQueryFileDosDeviceName(FileObject, &wcFilePath)==STATUS_SUCCESS)//获取文件对象所对应的文件Dos设备名称,即是全路径
				{
					if (RtlCompareMemory(wcFilePath->Name.Buffer+wcFilePath->Name.Length/2-wcslen(L"Winobj.exe"),L"Winobj.exe",wcslen(L"Winobj.exe")*sizeof(WCHAR))==wcslen(L"Winobj.exe")*sizeof(WCHAR)
						&& RtlCompareMemory(wcFilePath->Name.Buffer+wcFilePath->Name.Length/2-wcslen(L"PopupClient.exe"),
						L"PopupClient.exe",wcslen(L"PopupClient.exe")*sizeof(WCHAR))!=wcslen(L"PopupClient.exe")*sizeof(WCHAR))//这里是例子只监控Winobj.exe
					{
						DbgPrint("Target:%wZ\n",&wcFilePath->Name);//子进程
						//PPID = HandleToUlong(PsGetCurrentProcessId());
						ustrProcessPath.Buffer = wszProcessPath;
						ustrProcessPath.Length = 0;
						ustrProcessPath.MaximumLength = sizeof(wszProcessPath);
						ntStatus = ntGetProcessFullNameByPid(PsGetCurrentProcessId(), &ustrProcessPath);//父进程路径,就是当前路径
						DbgPrint("Parent:%wZ\n", &ustrProcessPath);
						if (NT_SUCCESS(ntStatus))
						{
							if (GetResultFromUser()==R3Result_Pass)
							{
								ntStatus = OldZwCreateSection(
												SectionHandle,
												DesiredAccess,
												ObjectAttributes,
												SectionSize,
												Protect,
												Attributes,
												FileHandle);
								ObDereferenceObject(FileObject);//放弃对FileObject的引用
								ExFreePool(wcFilePath);
								return ntStatus;	
							}
							ObDereferenceObject(FileObject);//放弃对FileObject的引用
							ExFreePool(wcFilePath);
							return STATUS_SUCCESS;
						}
					}
					ExFreePool(wcFilePath);//IoQueryFileDosDeviceName获取的OBJECT_NAME_INFORMATION 需要手动释放
				}
				ObDereferenceObject(FileObject);//放弃对FileObject的引用
			}        
		}
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{

	}
	return OldZwCreateSection(SectionHandle,DesiredAccess,ObjectAttributes,SectionSize,Protect,Attributes,FileHandle);
}

 

注意点

if (NT_SUCCESS(ObReferenceObjectByHandle(FileHandle,0,NULL,KernelMode,&FileObject,NULL)))//获取文件对象,这里类型最好不要传NULL,不然会有问题

进程保护

在应用层杀死进程使用的是TerminateProcess,这个函数在0环使用的是ZwTerminateProcess,所以我们可以hookZwTerminateProcess

可以在用户层获得我们要保护的进程的PID,发到我们的内核里来,然后保存在一个数组里面,存着我们要保护进程的PID。然后每次hookZwTerminateProcess比对PID,但是ZwTerminateProcess只有handle,ObReferenceObjectByHandle拿到EPROCESS,调用PsGetProcessId拿到进程PID。然后去数组比对。

代码片段

NTSTATUS Hook_ZwTerminateProcess(
	__in_opt HANDLE ProcessHandle,
	__in NTSTATUS ExitStatus
	)
{
	ULONG 			uPID = 0;
	NTSTATUS 		ntStatus = 0;
	PEPROCESS 		pEProcess = NULL;

	ntStatus = ObReferenceObjectByHandle(ProcessHandle, FILE_READ_DATA, NULL, KernelMode, &pEProcess, NULL);
	if(!NT_SUCCESS(ntStatus))
	{
		return ntStatus;
	}


	uPID = (ULONG)PsGetProcessId(pEProcess);

	if(ValidateProcessNeedProtect(uPID) != -1)//不是当前进程PID,为了客户端自己关自己
	{
		if(uPID != (ULONG)PsGetProcessId(PsGetCurrentProcess()))
		{
			return STATUS_ACCESS_DENIED;
		}
	}
	ntStatus = OldZwTerminateProcess(ProcessHandle, ExitStatus);

	return ntStatus;
}

或者通过回调保护进程,通过obRegisterCallbacks注册回调,https://bbs.pediy.com/thread-168023.htm

结束任务的保护:

窗口标题不为空的程序,都会在任务列表中显示。

结束任务:使用SendMessageTimeoutW发送WM_CLOSE消息,并这顶超时时间500ms,超过走EndTask。

解决方法:我们就可以将标题SetWindowText(_T(""))为空,驱动里面hook NtOpenProcess,NtTerminateProcess

过滤WM_CLOSE消息,在虚函数Pre TranslateMessage里

BOOL CXXXDlg::PreTranslateMessage(MSG* pMSG)
{
    if(pMsg->message==WM_CLOSE)//过滤掉WM_CLOSE
    {
        return TRUE;
    }
    
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值