frkngksl/Shoggoth
GitHub: frkngksl/Shoggoth
基于 AsmJit 的多态加密工具,可对 shellcode、PE 和 COFF 文件进行多层加密并生成可直接执行的位置无关代码,用于对抗静态和动态特征检测。
Stars: 782 | Forks: 99
# Shoggoth
**发表于**
- [BlackHat Europe 2022 Arsenal](https://www.blackhat.com/eu-22/arsenal/schedule/index.html#shoggoth-asmjit-based-polymorphic-encryptor-29588) - [ 演讲记录](https://www.youtube.com/watch?v=ECbQnbPxz5g)
# 简介
## 描述
Shoggoth 是一个基于 C++ 和 asmjit 库的开源项目,用于对给定的 shellcode、PE 和 COFF 文件进行多态加密。
Shoggoth 将生成一个输出文件,以混淆的形式存储 payload 及其相应的 loader。由于输出的内容是位置无关的,因此可以直接作为 shellcode 执行。在 payload 执行时,它会在运行时自行解密。除了加密例程外,Shoggoth 还会在例程之间添加不会改变任何状态的垃圾指令。
我开始开发这个项目是为了研究不同的动态指令生成方法、汇编实践以及特征检测。我计划定期使用我学到的新知识来更新这个代码库。
# 功能
当前的功能列表如下:
- 仅支持 x64 输入
- 能够将 PIC COFF Loader 与 COFF 或 BOF 输入文件合并
- 能够将 PIC PE Loader 与 PE 输入文件合并
- 使用 RC4 算法的流密码
- 使用随机生成运算的块密码
- 垃圾指令生成
## 执行流程
Shoggoth 针对输入文件的一般执行流程如下图所示。您可以观察到这是默认配置下的流程。
基本上,Shoggoth 首先根据所选的模式(COFF 或 PE 文件)将预编译的 loader shellcode 与输入文件合并。然后,它将生成的多条垃圾指令添加到此合并后的 payload 中。包含 loader、垃圾指令和 payload 的 stub 首先使用 RC4 加密,然后再通过将相应的解密器组合起来,使用随机生成的块加密进行加密。最后,它会向生成的代码块中添加一条垃圾指令。
## 机器码生成
当 Shoggoth 为垃圾 stub 或加密例程随机生成指令时,它使用了 [AsmJit](https://asmjit.com/) 库。
AsmJit 是一个用 C++ 语言编写的轻量级机器码生成库。它可以为 X86、X86_64 和 AArch64 架构生成机器码,并支持基准指令和所有最新的扩展指令集。AsmJit 允许指定操作码、寄存器、立即数、调用标签,并可以将任意值嵌入到代码内的任何偏移量位置。在使用 AsmJit 生成某些汇编指令时,只需使用 Assembler 类中汇编操作数的值,调用与所需汇编操作相对应的 API 函数即可。对于每次 API 调用,AsmJit 都会在其内部的 CodeHolder 结构中保存代码和重定位信息。在调用完所有要生成的汇编命令的 API 函数后,可以使用其 JitRuntime 类将代码从 CodeHolder 复制到具有可执行权限的内存中并进行重定位。
在寻找代码生成库时,我偶然发现了 AsmJit,并且看到它被许多流行的项目广泛使用。这就是为什么我决定使用它来满足我的需求。我不知道 Shoggoth 是否是第一个在红队背景下使用它的项目,但我相信它可以作为未来实现的参考。
## COFF 和 PE Loader
Shoggoth 可用于对给定的 PE 和 COFF 文件进行加密,得益于预编译的位置无关 loader,它们都可以作为 shellcode 执行。我只需使用 *C to Shellcode* 方法,就可以获得我为我以前的项目修改过的著名 PE 和 COFF loader 的 PIC 版本。在编译方面,我使用了 [HandleKatz](https://github.com/codewhitesec/HandleKatz) 项目中的 Makefile,这是一个 PIC 形式的 LSASS 转储工具。
基本上,为了通过 C to Shellcode 技术获取 shellcode,我移除了 loader 源代码中的所有全局变量,将所有字符串存入栈中,并通过在运行时加载和解析必要的 DLL 来获取 Windows API 函数的地址。随后,我通过链接脚本确定了入口点,并使用 MinGW 结合各种编译标志对代码进行了编译。我提取了生成的可执行文件的 .text 节并获得了 loader shellcode。由于按上述方式编辑代码后生成的可执行文件不包含 .text 节以外的任何节,因此该节中的代码可以作为位置无关代码使用。
这些的源代码可以在 [COFFLoader](https://github.com/frkngksl/Shoggoth/tree/main/COFFLoader) 和 [PELoader](https://github.com/frkngksl/Shoggoth/tree/main/PELoader) 目录中查看和编辑。此外,这些源代码编译后的版本可以在 [stub](https://github.com/frkngksl/Shoggoth/tree/main/stub) 目录中找到。目前,如果你想编辑或更改这些 loader,你必须遵循其函数签名并替换 stub 目录中的预编译二进制文件。
要将参数传递给 BOF,请使用 '--coff-arg' 选项。Shoggoth 期望接收一个包含打包参数的预格式化十六进制字符串,这可以使用 TrustedSec 的 beacon_generate.py 脚本来创建。该脚本的一个副本已作为 COFFArgGenerator/beacon_generate.py 包含在内。(非常感谢 @Octoberfest7)
## RC4 密码
Shoggoth 首先使用流密码之一的 RC4 算法来加密其获取的 payload。在随机生成此处使用的密钥后,它使用该密钥对 payload 进行加密。在运行期间解密 payload 的解密器 stub 是通过使用 AsmJit 动态创建和汇编的。stub 中使用的寄存器在每个样本中都是随机选择的。
对于我在 Shoggoth 中使用的 RC4 算法的实现,我参考了 Nayuki 的[代码](https://www.nayuki.io/page/rc4-cipher-in-x86-assembly)。
## 随机块密码
在执行第一次加密之后,Shoggoth 使用第二次加密,即随机生成的块密码。通过第二次加密,它同时加密 RC4 解密器,以及(可选的)包含 payload、垃圾指令和使用 RC4 加密的 loader 的 stub。它将要加密的数据块划分为 8 字节的块,并对每个块使用随机生成的指令。这些指令包括 ADD、SUB、XOR、NOT、NEG、INC、DEC、ROL 和 ROR。这些指令的操作数也是随机选择的。
## 垃圾指令生成
生成的垃圾指令逻辑深受 Ege Balci 出色的 [SGN](https://github.com/EgeBalci/sgn) 项目启发。Shoggoth 可以基于跳过随机字节、无副作用的指令、虚假函数调用以及有副作用但保留初始值的指令来选择垃圾指令。所有这些指令都是随机选择的,并通过调用 AsmJit 库的相应 API 函数来生成。此外,为了增加大小和不同的组合方式,这些生成函数是以递归方式调用的。
在 Shoggoth 的第一个版本中,有很多可以放置垃圾指令的地方。例如,我们可以在块密码指令或 RC4 密码指令之间插入垃圾指令。然而,出于演示目的,为了避免生成的 payload 出现额外的复杂性,我将它们留给了后续版本。
# 用法
## 环境要求
我没有编译主项目。这就是为什么你必须自己编译。或者,如果你想编辑 PE loader 或 COFF loader 的源代码,你的机器上应该装有 MinGW,以便使用提供的 Makefile 编译它们。
- Visual Studio 2019+
- (可选) MinGW 编译器
## 命令行参数
```
______ _ _
/ _____) | _ | |
( (____ | |__ ___ ____ ____ ___ _| |_| |__
\____ \| _ \ / _ \ / _ |/ _ |/ _ (_ _) _ \
_____) ) | | | |_| ( (_| ( (_| | |_| || |_| | | |
(______/|_| |_|\___/ \___ |\___ |\___/ \__)_| |_|
(_____(_____|
by @R0h1rr1m
"Tekeli-li! Tekeli-li!"
Usage of Shoggoth.exe:
-h | --help Show the help message.
-v | --verbose Enable more verbose output.
-i | --input Input path of payload to be encrypted. (Mandatory)
-o | --output
**发表于**
- [BlackHat Europe 2022 Arsenal](https://www.blackhat.com/eu-22/arsenal/schedule/index.html#shoggoth-asmjit-based-polymorphic-encryptor-29588) - [ 演讲记录](https://www.youtube.com/watch?v=ECbQnbPxz5g)
# 简介
## 描述
Shoggoth 是一个基于 C++ 和 asmjit 库的开源项目,用于对给定的 shellcode、PE 和 COFF 文件进行多态加密。
Shoggoth 将生成一个输出文件,以混淆的形式存储 payload 及其相应的 loader。由于输出的内容是位置无关的,因此可以直接作为 shellcode 执行。在 payload 执行时,它会在运行时自行解密。除了加密例程外,Shoggoth 还会在例程之间添加不会改变任何状态的垃圾指令。
我开始开发这个项目是为了研究不同的动态指令生成方法、汇编实践以及特征检测。我计划定期使用我学到的新知识来更新这个代码库。
# 功能
当前的功能列表如下:
- 仅支持 x64 输入
- 能够将 PIC COFF Loader 与 COFF 或 BOF 输入文件合并
- 能够将 PIC PE Loader 与 PE 输入文件合并
- 使用 RC4 算法的流密码
- 使用随机生成运算的块密码
- 垃圾指令生成
## 执行流程
Shoggoth 针对输入文件的一般执行流程如下图所示。您可以观察到这是默认配置下的流程。
基本上,Shoggoth 首先根据所选的模式(COFF 或 PE 文件)将预编译的 loader shellcode 与输入文件合并。然后,它将生成的多条垃圾指令添加到此合并后的 payload 中。包含 loader、垃圾指令和 payload 的 stub 首先使用 RC4 加密,然后再通过将相应的解密器组合起来,使用随机生成的块加密进行加密。最后,它会向生成的代码块中添加一条垃圾指令。
## 机器码生成
当 Shoggoth 为垃圾 stub 或加密例程随机生成指令时,它使用了 [AsmJit](https://asmjit.com/) 库。
AsmJit 是一个用 C++ 语言编写的轻量级机器码生成库。它可以为 X86、X86_64 和 AArch64 架构生成机器码,并支持基准指令和所有最新的扩展指令集。AsmJit 允许指定操作码、寄存器、立即数、调用标签,并可以将任意值嵌入到代码内的任何偏移量位置。在使用 AsmJit 生成某些汇编指令时,只需使用 Assembler 类中汇编操作数的值,调用与所需汇编操作相对应的 API 函数即可。对于每次 API 调用,AsmJit 都会在其内部的 CodeHolder 结构中保存代码和重定位信息。在调用完所有要生成的汇编命令的 API 函数后,可以使用其 JitRuntime 类将代码从 CodeHolder 复制到具有可执行权限的内存中并进行重定位。
在寻找代码生成库时,我偶然发现了 AsmJit,并且看到它被许多流行的项目广泛使用。这就是为什么我决定使用它来满足我的需求。我不知道 Shoggoth 是否是第一个在红队背景下使用它的项目,但我相信它可以作为未来实现的参考。
## COFF 和 PE Loader
Shoggoth 可用于对给定的 PE 和 COFF 文件进行加密,得益于预编译的位置无关 loader,它们都可以作为 shellcode 执行。我只需使用 *C to Shellcode* 方法,就可以获得我为我以前的项目修改过的著名 PE 和 COFF loader 的 PIC 版本。在编译方面,我使用了 [HandleKatz](https://github.com/codewhitesec/HandleKatz) 项目中的 Makefile,这是一个 PIC 形式的 LSASS 转储工具。
基本上,为了通过 C to Shellcode 技术获取 shellcode,我移除了 loader 源代码中的所有全局变量,将所有字符串存入栈中,并通过在运行时加载和解析必要的 DLL 来获取 Windows API 函数的地址。随后,我通过链接脚本确定了入口点,并使用 MinGW 结合各种编译标志对代码进行了编译。我提取了生成的可执行文件的 .text 节并获得了 loader shellcode。由于按上述方式编辑代码后生成的可执行文件不包含 .text 节以外的任何节,因此该节中的代码可以作为位置无关代码使用。
这些的源代码可以在 [COFFLoader](https://github.com/frkngksl/Shoggoth/tree/main/COFFLoader) 和 [PELoader](https://github.com/frkngksl/Shoggoth/tree/main/PELoader) 目录中查看和编辑。此外,这些源代码编译后的版本可以在 [stub](https://github.com/frkngksl/Shoggoth/tree/main/stub) 目录中找到。目前,如果你想编辑或更改这些 loader,你必须遵循其函数签名并替换 stub 目录中的预编译二进制文件。
要将参数传递给 BOF,请使用 '--coff-arg' 选项。Shoggoth 期望接收一个包含打包参数的预格式化十六进制字符串,这可以使用 TrustedSec 的 beacon_generate.py 脚本来创建。该脚本的一个副本已作为 COFFArgGenerator/beacon_generate.py 包含在内。(非常感谢 @Octoberfest7)
## RC4 密码
Shoggoth 首先使用流密码之一的 RC4 算法来加密其获取的 payload。在随机生成此处使用的密钥后,它使用该密钥对 payload 进行加密。在运行期间解密 payload 的解密器 stub 是通过使用 AsmJit 动态创建和汇编的。stub 中使用的寄存器在每个样本中都是随机选择的。
对于我在 Shoggoth 中使用的 RC4 算法的实现,我参考了 Nayuki 的[代码](https://www.nayuki.io/page/rc4-cipher-in-x86-assembly)。
## 随机块密码
在执行第一次加密之后,Shoggoth 使用第二次加密,即随机生成的块密码。通过第二次加密,它同时加密 RC4 解密器,以及(可选的)包含 payload、垃圾指令和使用 RC4 加密的 loader 的 stub。它将要加密的数据块划分为 8 字节的块,并对每个块使用随机生成的指令。这些指令包括 ADD、SUB、XOR、NOT、NEG、INC、DEC、ROL 和 ROR。这些指令的操作数也是随机选择的。
## 垃圾指令生成
生成的垃圾指令逻辑深受 Ege Balci 出色的 [SGN](https://github.com/EgeBalci/sgn) 项目启发。Shoggoth 可以基于跳过随机字节、无副作用的指令、虚假函数调用以及有副作用但保留初始值的指令来选择垃圾指令。所有这些指令都是随机选择的,并通过调用 AsmJit 库的相应 API 函数来生成。此外,为了增加大小和不同的组合方式,这些生成函数是以递归方式调用的。
在 Shoggoth 的第一个版本中,有很多可以放置垃圾指令的地方。例如,我们可以在块密码指令或 RC4 密码指令之间插入垃圾指令。然而,出于演示目的,为了避免生成的 payload 出现额外的复杂性,我将它们留给了后续版本。
# 用法
## 环境要求
我没有编译主项目。这就是为什么你必须自己编译。或者,如果你想编辑 PE loader 或 COFF loader 的源代码,你的机器上应该装有 MinGW,以便使用提供的 Makefile 编译它们。
- Visual Studio 2019+
- (可选) MinGW 编译器
## 命令行参数
```
______ _ _
/ _____) | _ | |
( (____ | |__ ___ ____ ____ ___ _| |_| |__
\____ \| _ \ / _ \ / _ |/ _ |/ _ (_ _) _ \
_____) ) | | | |_| ( (_| ( (_| | |_| || |_| | | |
(______/|_| |_|\___/ \___ |\___ |\___/ \__)_| |_|
(_____(_____|
by @R0h1rr1m
"Tekeli-li! Tekeli-li!"
Usage of Shoggoth.exe:
-h | --help Show the help message.
-v | --verbose Enable more verbose output.
-i | --input Input path of payload to be encrypted. (Mandatory)
-o | --output 标签:Asmjit, BlackHat Europe, BOF, C++, COFF文件加载, EDR绕过, Gophish, PE文件加载, PIC, RC4算法, shellcode加密, x64架构, 中高交互蜜罐, 代码混淆, 位置无关代码, 动态指令生成, 块密码, 垃圾指令, 多态加密, 恶意软件开发, 数据展示, 数据擦除, 欺骗防御, 汇编指令生成, 流密码, 签名规避, 红队, 红队武器化, 运行时解密, 高交互蜜罐, 黑帽大会