曾在以下场合展示
Shoggoth 是一个基于 C++ 和 asmjit 库的开源项目,用于对给定的 shellcode、PE 和 COFF 文件进行多态加密。
Shoggoth 会生成一个输出文件,该文件以混淆形式存储 payload 及其对应的加载器。由于输出内容与位置无关,因此可以直接作为 shellcode 执行。在执行 payload 时,它会在运行时自行解密。除了加密例程外,Shoggoth 还会在各例程之间插入不改变任何内容的垃圾指令。
我开始开发这个项目是为了研究不同的动态指令生成方法、汇编实践以及签名检测技术。我计划定期用新的学习成果更新此仓库。
当前功能如下:
Shoggoth 对于输入文件的一般执行流程如下图所示。您可以在默认配置下观察此流程。
基本上,Shoggoth 首先根据所选模式(COFF 或 PE 文件)将预编译的加载器 shellcode 与输入文件合并。然后,它向合并后的 payload 中添加多条自己生成的垃圾指令。包含加载器、垃圾指令和 payload 的存根先经过 RC4 加密,再通过结合相应解密器的随机生成块加密进行二次加密。最后,它向结果块中添加一条垃圾指令。
Shoggoth 在随机生成垃圾存根或加密例程的指令时,使用了 AsmJit 库。
AsmJit 是一个用 C++ 编写的轻量级机器码生成库。它可以生成 X86、X86_64 和 AArch64 架构的机器码,支持基础指令及所有最新扩展。AsmJit 允许指定操作码、寄存器、立即操作数、调用标签,以及向代码中的任意偏移处嵌入任意值。通过使用 AsmJit 生成一些汇编指令时,只需从 Assembler 类中调用与所需汇编操作对应的 API 函数,并传入汇编操作数即可。对于每次 API 调用,AsmJit 会将其内部的 CodeHolder 结构中的代码和重定位信息保存下来。在调用完所有要生成的汇编命令的 API 函数后,可以使用其 JitRuntime 类将代码从 CodeHolder 复制到具有可执行权限的内存中并进行重定位。
在我寻找代码生成库时,遇到了 AsmJit,并且看到它被许多流行的项目广泛使用。因此,我决定用它来满足我的需求。我不知道 Shoggoth 是否是第一个在红队场景中使用它的项目,但我相信它可以为未来的实现提供参考。
Shoggoth 可用于加密给定的 PE 和 COFF 文件,从而使两者都可以作为 shellcode 执行,这得益于预编译的与位置无关的加载器。我只是使用了 C 到 Shellcode 的方法,从我为了旧项目修改的知名 PE 和 COFF 加载器中获取了 PIC 版本。编译时,我使用了 HandleKatz 项目中的 Makefile,它是一个 PIC 形式的 LSASS 转储器。
基本上,为了通过 C 到 Shellcode 技术获得 shellcode,我删除了加载器源代码中的所有全局变量,将所有字符串存储在栈中,并通过在运行时加载和解析必要的 DLL 来解析 Windows API 函数的地址。之后,我通过链接器脚本确定了入口点,并使用 MinGW 配合各种编译标志编译了代码。我提取了生成可执行文件的 .text 部分,从而获得了加载器 shellcode。由于按上述方式编辑代码后得到的可执行文件不包含除 .text 部分以外的任何部分,因此该部分中的代码可以用作位置无关代码。
这些源代码可以在 COFFLoader 和 PELoader 目录中查看和编辑。这些源代码的编译版本可以在 stub 目录中找到。目前,如果您想编辑或更改这些加载器,您应遵守签名,并从 stub 目录替换预编译的二进制文件。
要向 BOF 传递参数,请使用 '--coff-arg' 选项。Shoggoth 期望一个包含打包参数的预格式化十六进制字符串,该字符串可以使用 TrustedSec 的 beacon_generate.py 脚本创建。此脚本的副本已作为 COFFArgGenerator/beacon_generate.py 包含在内。(非常感谢 @Octoberfest7)
Shoggoth 首先使用流密码之一的 RC4 算法来加密获得的 payload。在随机生成此处使用的密钥后,它用该密钥加密 payload。在运行时解密 payload 的解密器存根是通过使用 AsmJit 动态创建和汇编的。存根中使用的寄存器是为每个样本随机选择的。
我在 Shoggoth 中实现的 RC4 算法参考了 Nayuki 的 代码。
第一次加密后,Shoggoth 使用第二次加密,即随机生成的块密码。通过第二次加密,它同时加密了 RC4 解密器,以及可选地包含经 RC4 加密的 payload、垃圾指令和加载器的存根。它将要加密的块分成 8 字节的块,并为每个块使用随机生成的指令。这些指令包括 ADD、SUB、XOR、NOT、NEG、INC、DEC、ROL 和 ROR。这些指令的操作数也是随机选择的。
生成的垃圾指令逻辑深受 Ege Balci 出色的 SGN 项目的启发。Shoggoth 可以根据随机字节跳转、无副作用的指令、虚假函数调用以及具有副作用但保留初始值的指令来选择垃圾指令。所有这些指令都是随机选择的,并通过调用 AsmJit 库的相应 API 函数生成。此外,为了增加大小和不同的组合,这些生成函数会被递归调用。
在第一个版本的 Shoggoth 中,有很多地方可以放置垃圾指令。例如,我们可以在块加密指令或 RC4 加密指令之间放置垃圾指令。然而,出于演示目的,我将其留给了后续版本,以避免增加生成 payload 的额外复杂性。
我没有编译主项目。因此,您必须自行编译。如果您想编辑 PE 加载器或 COFF 加载器的源代码,则需在机器上安装 MinGW,以便使用给定的 Makefile 进行编译。
______ _ _
/ _____) | _ | |
( (____ | |__ ___ ____ ____ ___ _| |_| |__
\____ \| _ \ / _ \ / _ |/ _ |/ _ (_ _) _ \
_____) ) | | | |_| ( (_| ( (_| | |_| || |_| | | |
(______/|_| |_|\___/ \___ |\___ |\___/ \__)_| |_|
(_____(_____|
by @R0h1rr1m
"Tekeli-li! Tekeli-li!"
Shoggoth.exe 的使用方法:
-h | --help 显示帮助信息。
-v | --verbose 启用更详细的输出。
-i | --input <输入路径> 待加密 payload 的输入路径。(必填)
-o | --output <输出路径> 加密后输出的路径。(必填)
-s | --seed <数值> 设置随机化的种子值。
-m | --mode <模式值> 设置 payload 加密模式。可用模式有:(必填)
[*] raw - Shoggoth 不附加加载器存根。(默认模式)
[*] pe - Shoggoth 附加 PE 加载器存根。输入必须是有效的 x64 PE。
[*] coff - Shoggoth 附加 COFF 加载器存根。输入必须是有效的 x64 COFF。
--coff-arg <参数> 为 COFF 加载器设置参数。使用 COFFArgGenerator/beacon_generate.py 生成此字符串。
示例:--coff-arg 0a0000000600000068656c6c6f00
仅在 COFF 加载器模式下使用。(感谢 @Octoberfest7)
-k | --key <加密密钥> 设置第一重加密密钥,而非随机密钥。
--dont-do-first-encryption 不执行第一重加密(流加密)。
--dont-do-second-encryption 不执行第二重加密(块加密)。
--encrypt-only-decryptor 在第二重加密中仅加密解密器存根。
“那是一个可怕、难以形容的东西,比任何地铁列车都庞大——一团无定形的原生质气泡集合体,微微自发光,无数临时性的眼睛像绿色光的脓疱,在填满隧道的正面形成和消散,向我们压迫而来,碾碎惊慌的企鹅,滑过那闪亮的地板——它和它的同类已经邪恶地将一切垃圾扫除干净。” ~ H. P. Lovecraft,《疯狂山脉》
Shoggoth 是克苏鲁神话中的虚构怪物。该生物在 H. P. Lovecraft 的十四行诗组《犹格斯的真菌》(1929–30)中被简要提及,后来在他的中篇小说《疯狂山脉》(1931)中被详细描述。它们能够形成当前任务所需的任何器官或附肢,尽管它们通常的状态是一团扭动的眼睛、嘴巴和蠕动的触手。
由于这些生物像一坨有感知、会自我塑形的凝胶状血肉,在 Lovecraft 的描述中没有固定形状,因此我想将一个多态加密工具命名为这个名字。🙂
仅限于授权的安全测试。未经明确许可,将此工具用于系统上属于非法行为。