关于进程创建,
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;
}
}