玄 - 利用blockdlls和ACG保护恶意进程

blockdlls

Cobalt Strike 3.14版本以后添加了blockdlls功能,它将创建一个子进程并限定该子进程只能加载带有Microsoft签名的DLL。

这个功能可以阻止第三方安全软件向子进程注入DLL,也就无法对子进程进行hook,最终起到保护子进程的效果。

XPN在博客中分享了实现同样功能的c代码

#include <Windows.h>

int main()
{
	STARTUPINFOEXA si;
	PROCESS_INFORMATION pi;
	SIZE_T size = 0;
	BOOL ret;

	// 请求一个 STARTUPINFOEXA 结构体
	ZeroMemory(&si, sizeof(si));
	si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
	si.StartupInfo.dwFlags = EXTENDED_STARTUPINFO_PRESENT;

	//获取要分配的 PROC_THREAD_ATTRIBUTE_LIST 大小
	InitializeProcThreadAttributeList(NULL, 1, 0, &size);

	//为 PROC_THREAD_ATTRIBUTE_LIST 分配内存
	si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
		GetProcessHeap(),
		0,
		size
	);

	// 初始化我们的列表 
	InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);

	// 启用阻止未经Microsoft签名的DLL功能
	DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;

	// Assign our attribute
	UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(policy), NULL, NULL);

	// 创建进程
	ret = CreateProcessA(
		NULL,
		(LPSTR)"C:\\Windows\\System32\\cmd.exe",
		NULL,
		NULL,
		true,
		EXTENDED_STARTUPINFO_PRESENT,
		NULL,
		NULL,
		reinterpret_cast<LPSTARTUPINFOA>(&si),
		&pi
	);
}

通过STARTUPINFOEX结构体指定了要创建子进程的安全策略(开启PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON),这个安全策略起到了阻止加载非Microsoft签名dll的作用。

生成子进程后,使用ProcessHacker能够看到开启blockdlls功能的提示,如下图:

开启blockdlls功能后,尝试对这个进程进行dll注入,注入的代码可参考三好学生
注入时报错,提示如图:

接下来,需要了解此功能相关细节。在微软官方文档中,找到了相关API GetProcessMitigationPolicy(),可读取进程的安全策略。

而签名策略对应的结构体为PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY,资料显示该API支持的最低系统为Win8,这里猜测API GetProcessMitigationPolicy()同blockdlls支持的操作系统版本应该相同。

经过测试,发现Cobalt Strike中blockdlls支持的系统最低为Win8。

分析blockdlls在CS中的实现

如果我们搜索CS beacon二进制文件,我们会看到对UpdateProctThreadAttribute的引用:

0x20007的属性参数实际上定义为PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,并且0x10000000000的值解析为PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON。所以Cobalt Strike在这里所做的是使用CreateProcess API调用以及包含一个缓解策略的结构体STARTUPINFOEX,而该策略正是用于阻止非微软签名DLL的加载。

任意代码保护

ACG是Windows系统的另一个安全策略,用于阻止外部代码分配和/或修改内存,这里不多赘述

要了解此缓解策略的实际效果,我们创建一个小程序并尝试使用 SetMitigationPolicy 添加开启 ACG :

#include <iostream>
#include <Windows.h>
#include <processthreadsapi.h>

int main()
{
	STARTUPINFOEX si;
	DWORD oldProtection;
	
	PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy;
	ZeroMemory(&policy, sizeof(policy));
	policy.ProhibitDynamicCode = 1;

	void* mem = VirtualAlloc(0, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (mem == NULL) {
		printf("[!] Error allocating RWX memory\n");
	}
	else {
		printf("[*] RWX memory allocated: %p\n", mem);
	}

	printf("[*] Now running SetProcessMitigationPolicy to apply PROCESS_MITIGATION_DYNAMIC_CODE_POLICY\n");
	
	// Set our mitigation policy
	if (SetProcessMitigationPolicy(ProcessDynamicCodePolicy, &policy, sizeof(policy)) == false) {
		printf("[!] SetProcessMitigationPolicy failed\n");
		return 0;
	}

	// Attempt to allocate RWX protected memory (this will fail)
	mem = VirtualAlloc(0, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (mem == NULL) {
		printf("[!] Error allocating RWX memory\n");
	}
	else {
		printf("[*] RWX memory allocated: %p\n", mem);
	}

	void* ntAllocateVirtualMemory = GetProcAddress(LoadLibraryA("ntdll.dll"), "NtAllocateVirtualMemory");

	// Let's also try a VirtualProtect to see if we can update an existing page to RWX
	if (!VirtualProtect(ntAllocateVirtualMemory, 4096, PAGE_EXECUTE_READWRITE, &oldProtection)) {
		printf("[!] Error updating NtAllocateVirtualMemory [%p] memory to RWX\n", ntAllocateVirtualMemory);
	}
	else {
		printf("[*] NtAllocateVirtualMemory [%p] memory updated to RWX\n", ntAllocateVirtualMemory);
	}
}

编译并执行这段代码,我们将看到如下内容:

我们可以看到在 SetProcessMitigationPolicy 失败后尝试分配 RWX 的内存页,以及使用诸如 VirtualProtect 之类的调用来分配或修改内存保护,结果都是失败的。

那为什么要提这个呢? 因为我们确实看到了由微软签名的 EDR 注入DLL的例子,@Sektor7Net 展示了 Crowdstrike Falcon 可以不受 PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON 的影响

但许多EDR产品常见的操作是将他们的DLL注入到其想监测的进程中,围绕特定的API函数实现用户态hook技术(参考文章)。由于hook技术通常需要修改现有的可执行内存页以添加hook,因此EDR通常需要调用VirtualProtect来更新内存保护。如果我们在恶意软件设计上启用ProcessDynamicCodePolicy可能有助于保护其免受EDR hook监测的影响,就可能会强制阻止一个带微软签名的DLL加载。

总结

现在,我们要将这些策略进行整合,在生成恶意进程时,可以用PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON以及SetMitigationPolicyAPI调用进行保护。当然,还有其他方法可以对进程进行保护,例如通过简单的CreateProcessA生成任意进程。
这里,我仅根据以上展开的思路编写了新款免杀马(开源是不可能开源的,只提供思路大家自行创作),通杀国内外一流杀软,命名“冢虎”,在座的各位师傅有谁赞同,有谁反对?

参考:
https://blog.cobaltstrike.com/2019/05/02/cobalt-strike-3-14-post-ex-omakase-shimasu/
https://www.ired.team/offensive-security/defense-evasion/acg-arbitrary-code-guard-processdynamiccodepolicy#enabling-acg
https://blog.xpnsec.com/protecting-your-malware/
https://www.4hou.com/posts/0Xov

posted @ 2021-10-11 11:52  zha0gongz1  阅读(1118)  评论(0编辑  收藏  举报