Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
ShellcodeFluctuation — 一种高级内存规避技术,在 RW/NoAccess 与 RX 之间波动切换 shellcode 的内存保护,并对其内容进行加密/解密。 | Kitploit
工具/GitHubGitHub/mgeeky/shellcodefluctuation
Payload生成Shellcode后渗透利用红队Shellcode 生成Payload 开发对抗性攻击Payload 开发 分类第 16 名Payload生成 分类第 16 名Shellcode 分类第 14 名
1.1k163474年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
Shellcode 生成 分类第 16 名
GitHubmgeeky/shellcodefluctuation

ShellcodeFluctuation

一种高级内存规避技术,在 RW/NoAccess 与 RX 之间波动切换 shellcode 的内存保护,并对其内容进行加密/解密。

查看仓库

Shellcode Fluctuation PoC

A PoC implementation for an another in-memory evasion technique that cyclically encrypts and decrypts shellcode's contents to then make it fluctuate between RW (or NoAccess) and RX memory protection. When our shellcode resides in RW or NoAccess memory pages, scanners such as Moneta or pe-sieve will be unable to track it down and dump it for further analysis.

简介

在发布 ThreadStackSpoofer 之后,我收到了一些关于以下 README 要点的提问:

在 Beacon 睡眠前,将其内存页保护从 RX/RWX 改为 RW,并加密其内容(这样可以规避诸如 Moneta 或 pe-sieve 之类的扫描器)

在此之前,我曾相当确信社区已经知道如何加密/解密其载荷并翻转内存保护,以简单规避那些寻找异常可执行区域的内存扫描器。 事实证明并非如此,因此我决定发布这个未武器化的 PoC,以记录又一种规避策略,并为社区提供可用的示例实现。

这个 PoC 演示了一种相当简单的技术,红队社区早已熟知(所以我其实并没有带来什么新东西),希望借此揭开某些商业框架在演示针对上述两款内存扫描器的规避能力时所展现的“魔法”背后的秘密。

以下是对波动到 RW 时的对比(另一种选择是波动到 PAGE_NOACCESS——见下文描述):

  1. Beacon 未加密
  2. Beacon 已加密(波动中)

对比

该实现连同我的 ThreadStackSpoofer,为攻防安全社区带来了可与商业 C2 产品功能比肩的示例实现,使我们在红队工具上也能不落下风。💪


工作原理?

该程序执行自注入 shellcode(大致通过经典的 VirtualAlloc + memcpy + CreateThread)。 当 shellcode 运行(此实现专门针对 Cobalt Strike Beacon 植入体)时,将会挂钩一个 Windows 函数,以拦截 Beacon 进入睡眠的时机 kernel32!Sleep。 每当被挂钩的 MySleep 函数被调用时,它会定位其内存分配边界,将保护属性翻转为 RW,并对其中存储的所有字节进行 xor32 加密。 在等待了预期的时间后,当 shellcode 返回到我们的 MySleep 处理程序时,我们会解密 shellcode 的数据,并将保护属性翻转回 RX。

波动到 PAGE_READWRITE 的工作方式如下

  1. 从文件中读取 shellcode 的内容。
  2. 挂钩 kernel32!Sleep,使其指向我们的回调函数。
  3. 通过 VirtualAlloc + memcpy + CreateThread 注入并启动 shellcode。与我们在 ThreadStackSpoofer 中所做的相反,这里我们不在 ntdll 中挂钩任何东西来启动 shellcode,而是从我们自己的函数跳转到它。这样做的目的是避免在内存中留下指向被修改的 ntdll 内存的简单 IOC。
  4. 一旦 Beacon 尝试睡眠,我们的 MySleep 回调就会被调用。
  5. Beacon 的内存分配被加密,保护属性翻转为 RW
  6. 然后我们取消挂钩原始 kernel32!Sleep,以避免在内存中留下表明 Sleep 已被 trampoline(内联挂钩)的简单 IOC。
  7. 调用原始 ::Sleep,让 Beacon 在等待后续通信时保持睡眠。
  8. 睡眠结束后,我们解密 shellcode 的数据,将内存保护翻转回 RX,然后重新挂钩 kernel32!Sleep,以确保拦截后续的睡眠。

波动到 PAGE_NOACCESS 的工作方式如下

  1. 从文件中读取 shellcode 的内容。
  2. 挂钩 kernel32!Sleep,使其指向我们的回调函数。
  3. 通过 VirtualAlloc + memcpy + CreateThread 注入并启动 shellcode ...
  4. 初始化向量化异常处理程序(VEH),以设置我们自己的处理程序来捕获 访问冲突 异常。
  5. 一旦 Beacon 尝试睡眠,我们的 MySleep 回调就会被调用。
  6. Beacon 的内存分配被加密,保护属性翻转为 PAGE_NOACCESS
  7. 然后我们取消挂钩原始 kernel32!Sleep,以避免在内存中留下表明 Sleep 已被 trampoline(内联挂钩)的简单 IOC。
  8. 调用原始 ::Sleep,让 Beacon 在等待后续通信时保持睡眠。
  9. 睡眠结束后,我们重新挂钩 kernel32!Sleep,以确保拦截后续的睡眠。
  10. 随后 shellcode 尝试恢复执行,这会因它的页面被标记为 NoAccess 而引发访问冲突。
  11. 我们的 VEH 处理程序捕获该异常,解密并将内存保护翻转回 RX,shellcode 随即恢复执行。

这并非一项新技术

这项技术并不是全新的,也不是我自己发明的。它仅仅是一个展示概念及其实际应用的实现,旨在让我们攻防安全社区赶上商业 C2 框架所提供的功能。

实际上,几年前我通过 Josh Lospinoso 在他出色的 Gargoyle 中的工作,第一次接触到了翻转 shellcode 内存保护这一想法。

更多背景资料:

  • gargoyle——一种内存扫描规避技术
  • 使用 Cobalt Strike 和 Gargoyle 绕过内存扫描器

Gargoyle 通过利用调用 VirtualProtect 的 ROP 序列,将自感知、自波动 shellcode 的概念又向前推进了一步。 不过,尽管这项技术令人印象深刻,但要将其与 Cobalt Strike 的 Beacon 结合使用同样困难,因为你必须杀死其线程,并在内存中不断重新初始化 Beacon。

这远非完美,但既然我们已经立足于自己的自注入加载器进程,就可以对 shellcode 运行的环境为所欲为,想怎么隐藏它就怎么隐藏它。这项技术(以及之前的 ThreadStackSpoofer)展示了以这种方式运行 shellcode 的优势。

波动到 PAGE_NOACCESS 的实现灵感来自于 ORCA666 在他的 https://github.com/ORCA666/0x41 注入器中展示的工作。 他证明了:

  1. 我们可以初始化一个向量化异常处理程序(VEH),
  2. 将 shellcode 的页面翻转为无访问权限(no-access)
  3. 然后捕获 Access Violation 异常——这些异常会在 shellcode 想要恢复执行时立即发生,此时再解密并将其内存页面翻转回读取+执行(Read+Execute)。

该实现包含了这一想法,可通过 <fluctuate> 中的选项 2 启用。 也请务必查看他的其他项目。


演示

工具 ShellcodeFluctuation 接受三个参数:第一个是 shellcode 的路径,第二个是我们功能的修饰符。``` Usage: ShellcodeFluctuation.exe : -1 - Read shellcode but dont inject it. Run in an infinite loop. 0 - Inject the shellcode but don't hook kernel32!Sleep and don't encrypt anything 1 - Inject shellcode and start fluctuating its memory with standard PAGE_READWRITE. 2 - Inject shellcode and start fluctuating its memory with ORCA666's PAGE_NOACCESS.

### Moneta(看似)误报```
C:\> ShellcodeFluctuation.exe beacon64.bin -1

So firstly we'll see what Moneta64 scanner thinks about process that does nothing dodgy and simply resorts to run an infinite loop:

moneta 误报

As we can see there's some 误报 (at least how I consider it) allegedly detecting Mismatching PEB module / Phantom image. The memory boundaries point at the ShellcodeFluctuate.exe module itself and could indicate that this module however being of MEM_IMAGE type, is not linked in process' PEB - which is unusual and sounds rather odd. The reason for this IOC is not known to me and I didn't attempt to understand it better, yet it isn't something we should be concerned about really.

If anyone knows what's the reason for this detection, I'd be very curious to hear! Please do reach out.

未加密的 Beacon```

C:> ShellcodeFluctuation.exe beacon64.bin 0

第二个用例展示了在我们进程中运行的 Beacon 的内存 IOC,该 Beacon 不使用任何定制的 `Artifact Kits`、`User-Defined Reflective Loaders`(例如我的 [`ElusiveMice`](https://github.com/mgeeky/ElusiveMice)),也不执行任何会破坏我们结果的初始操作。

![moneta not encrypted](https://assets.kitploit.com/production/public/readmes/50718/6a4e3a230a362c25da6f4aa6955b822d2a83215848c1bc09566a27ea9db653c9/dd2e0560a688886c0fe06debe92f153e129daa6654cb17c2976edee8661e3bd3-display-v1.webp)

我们可以看到 `Moneta64` 正确识别出指向我们 shellcode 所在位置的 `Abnormal private executable memory`。
这是一个非常强的内存 IOC,会暴露我们的 shellcode,使其可能被自动化扫描器转储和分析。这可不太好。

### 使用 RW 保护的加密 Beacon```
C:\> ShellcodeFluctuation.exe beacon64.bin 1

现在来看第三个用例,从本实现的角度来看最有趣,即 波动 Beacon。

moneta encrypted

除了第一个 IOC(在某种程度上被认为是 误报)之外,我们还看到了一个新的 IOC,表明 kernel32.dll 内存被修改了。 然而,这次没有 Abnormal private executable memory IOC。我们的波动(反复加密/解密以及内存保护切换是激活的)。

另外需要说明的是,pe-sieve 在使用 /data 3 选项时也会检测到植入的 PE(除非指定该选项,否则不会进行检测):

pe-sieve

我目前的假设是,PE-Sieve 检测到的特征与 Moneta 相同(在下面的 kernel32.dll 中的修改代码 中描述)——即 PE 映射的模块具有非空的工作集,这显然是某种代码注入的明显事实。 这被标记为 Implanted PE / Implanted。如果是这样,结论与 Moneta 的观察类似。我认为从检测的角度来看,我们不必太在意这个 IOC。

目前,除了挂钩 kernel32!Sleep 之外,我想不到更好的办法来中途拦截 shellcode 的执行(这里说的是 Cobalt Strike)。因此,我们必然会留下这类 IOC。

但是嘿,与文件系统上(C:\Windows\System32\kernel32.dll)的文件相比,仍然没有一个字节不同,也没有任何函数被挂钩,这是怎么回事?😉

具有 PAGE_NOACCESS 保护的加密 Beacon```

C:> ShellcodeFluctuation.exe beacon64.bin 2

![no-access](https://assets.kitploit.com/production/public/readmes/50718/03f80df765f37efb3242dce12c613091ab79896e584fbfc2a309a1295c4544c6/327fe5cc3e3ebe6db8277bd091361f7ae42ee4925e21aa87cfa9287b404a1ab5-display-v1.webp)

这实际上会导致 shellcode 在 `RX` 和 `NA` 页面之间波动。

目前我不确定切换到 `PAGE_NOACCESS` 而不是 `PAGE_READWRITE` 有什么好处。


### kernel32.dll 中被修改的代码

那么,那个被修改的 `kernel32` IOC 又是怎么回事呢?

现在,让我们试着追查这个 IOC 的根源,看看这里到底是怎么回事。

首先,我们会转储所提到的内存区域——即 `kernel32.dll` 的 `.text`(代码)节。为此,我们使用 `ProcessHacker`,以利用公开已知且稳定的工具:
下载工具