fjasik/C-shellcode
GitHub: fjasik/C-shellcode
一个演示如何利用 C 语言和 MSVC 编译器编写地址无关 shellcode 的工具链项目,包含汇编修补、链接和提取等完整的自定义编译流程。
Stars: 1 | Forks: 0
# C-Shellcode
使用 C 语言编写、通过 MSVC 编译的地址无关 shellcode,并配备了一个自定义工具链来修补生成的汇编代码、进行链接,以及将可执行的 `.text` 节区提取为原始 shellcode。
## 关于
本项目演示了完全使用 C 语言创建 shellcode —— 无需手写汇编。C 代码由 MSVC 编译为汇编代码,随后使用 Python 脚本修补并移除所有外部引用和 CRT 依赖。最终结果会被链接为一个最小化的可执行文件,而 `.text` 节区将被提取为一个独立的、地址无关的二进制块,可直接用于注入。
所有的 Win32 导入都是通过遍历 PEB 并匹配函数哈希在运行时解析的 —— 没有 IAT,没有 `LoadLibrary`,也没有 CRT。
## 解决方案结构
这是一个 Visual Studio 解决方案。其结构如下:
- `C-Shellcode`:这是编写 shellcode 的主要试验场。它大量使用了直接借鉴(无耻窃取)来的 `peb_lookup.h`,在不使用 LoadLibrary 的情况下导入 Win32 函数(因为在 shellcode 中,我们无法访问它,也无法访问 CRT)。目前包含以下 shellcode:
- `test_debug.c`:演示了 shellcode 的调试打印功能。通过名称获取必要的函数。
- `test_string.c`:演示了如何使用 shellcode 调试打印,利用基于栈的字符串获取句柄和函数指针,并正确调用 MessageBoxA。需要在已加载 `user32.dll` 的进程中运行。
- `test_hash.c`:类似于 `test_string.c`,但使用预先计算的哈希值来获取句柄和函数指针。
- `websocket.c`:被注入后,它会打开一个连接到远程 IP 地址的 socket,获取指定大小的数字,分配给定大小的内存,将给定大小的 payload 获取到内存中,最后直接执行它。请注意,它必须被注入到已加载 `Ws2_32.dll` 的进程中。
- `reflective_loader.c`:此 shellcode 在与 DLL 拼接后,会在内存中加载该 DLL 并调用其 DllMain。
- `spawn.c`:启动 `cmd.exe` 并将其 IO 重定向到自定义命名管道。
- `inject.c`:将拼接在其末尾的 shellcode 注入到另一个硬编码的进程中。
- `DummyDLL`:仅作为一个用于验证加载过程是否成功的虚拟测试 DLL。它会启动一个线程,向控制台打印消息并弹出一个消息框。
- `DummyWinsock2App`:一个虚拟的测试应用程序,它会加载 `Ws2_32.dll`,打开一个 socket 然后什么也不做。非常适合作为注入目标。
- `ShellcodeInjector`:一个经典的 shellcode 注入器应用程序,使用 `WriteProcessMemory` 和 `CreateRemoteThread` 将 shellcode 注入到远程进程中。
- `SelfInjector`:一个更简单的应用程序,用于将 shellcode 加载到自身进程中,方便调试。
此外还有一个 `Auxilary` 文件夹,其中包含几个重要的辅助脚本:
- `amend_asm_x86.py` 和 `amend_asm_x64.py`:用于修补 MSVC 编译器生成的汇编代码的 Python 脚本。它会移除所有外部链接,并确保完全链接后的可执行文件的可执行节区可以直接被提取和运行。x64 版本还会注入一个在 main 之前运行的对齐栈过程。
- `compile_c_shellcode.ps1`:一个用于将 `.c` 文件编译为可执行文件并从中提取 shellcode 的 PowerShell 脚本。你可以选择正确的架构、是否添加调试打印以及是否使用优化。请注意,你需要从 `Developer PowerShell for VS 2019` 中运行此脚本,并且架构必须匹配:你无法从 x64 的 PowerShell 中编译 x86 shellcode。
- `concat_binaries.py`:一个用于拼接 2 个二进制文件的小型 Python 脚本,在创建反射式 DLL 时非常有用,因为需要将反射式加载器与 DLL 拼接在一起。
- `extract_text_section.py`:一个用于解析可执行文件并提取其 text 节区,然后将其保存到文件的小型 Python 脚本。
- `hash_string.py`:一个用于为 dll 和函数名称生成哈希值的 Python 脚本,用于通过哈希而不是名称来导入 dll 和函数。请注意,dll 名称应使用小写形式的哈希。
- `inject_shellcode.ps1`:一个用于将 shellcode 注入到进程中的 PowerShell 脚本(可能会被 Defender 拦截)。
- `server.py`:一个非常简单的 Python 服务器,它会打开一个 socket,等待有程序绑定到它(比如 `websocket.c` 所做的操作),然后发送 2 条消息:第一条是 payload 的大小,随后是 payload 本身。然后退出。
## 编译
### 32 位
编译示例 shellcode:
- 打开 `x86 Native Tools Command Prompt for VS`,或等效的 PowerShell
- 导航到仓库的根目录
- 调用编译脚本
- `.\Auxilary\compile_c_shellcode.ps1 .\C-Shellcode\test_string.c -Architecture Win32`
- 使用 `-DebugPrint` 允许 shellcode 输出调试消息
- 使用 `-Optimize` 让编译器优化代码(可能无法生效,请谨慎使用)
- 享受成果
### 64 位
编译示例 shellcode,与 32 位示例非常相似:
- 打开 `Developer PowerShell for VS`,或等效的 PowerShell
- 导航到仓库的根目录
- 调用编译脚本
- `.\Auxilary\compile_c_shellcode.ps1 .\C-Shellcode\test_string.c -Architecture x64`
- 根据需要使用 `-DebugPrint` 和 `-Optimize`
- 享受成果
## 示例用法(32 位)
### 准备
准备恶意代码:
- 构建解决方案
- 在 Visual Studio 的 `Win32` 模式下右键点击 `Build Solution`
- 编译并构建 shellcode
- 打开 `x86 Native Tools Command Prompt for VS`,或等效的 PowerShell
- `.\Auxilary\compile_c_shellcode.ps1 .\C-Shellcode\websocket.c -Architecture Win32 -DebugPrint`
- `.\Auxilary\compile_c_shellcode.ps1 .\C-Shellcode\reflective_loader.c -Architecture Win32 -DebugPrint`
- 注意,在编译 `reflective_loader.c` 时,请确保检查生成的 shellcode 大小是否与代码中的 `kShellcodeLength` 常量匹配。
- 将 `reflective_loader` shellcode 与一个虚拟 DLL 拼接
- `python3 .\Auxilary\concat_binaries.py .\out\shellcode\bin\reflective_loader_dbg_x86.bin .\out\bin\Win32\Debug\DummyDLL.dll`
### 执行
运行它:
- 启动 websocket 服务器并使其提供与 DLL 拼接后的 `reflective_loader` shellcode
- `python3 .\Auxilary\server.py .\concat.bin`
- 启动虚拟 Winsock2 应用程序
- `.\out\bin\Win32\Debug\DummyWinsock2App.exe`
- 将 `websocket` shellcode 注入到虚拟 Winsock2 应用程序中
- `.\out\bin\Win32\Debug\ShellcodeInjector.exe .\out\shellcode\bin\websocket_dbg_x86.bin DummyWinsock2App.exe`
### 接下来会发生什么?
攻击链如下所示:
- `websocket` shellcode 在 `DummyWinsock2App.exe` 中执行
- 立即打开一个连接到 Python 服务器的 socket
- 下载 `concat.bin`,即由 `reflective_loader` shellcode 与 `DummyDLL.dll` 拼接而成
- 执行 `reflective_loader` shellcode,加载 `DummyDLL.dll`
- 调用 `DllMain` 并初始化主线程
- 从 DLL 中生成一个消息框
## 编译状态
### 表格
| Shellcode 状态 | **x86** | | | **x64** | | |
|-------------------|-----------|-------------|---------------|-----------|-------------|---------------|
| | **Debug** | **Vanilla** | **Optimized** | **Debug** | **Vanilla** | **Optimized** |
| test_debug | ok | ok | ok | ok | ok | ok |
| test_string | ok | ok | ok | ok | ok | ok |
| test_hash | ok | ok | ok | ok | ok | ok |
| websocket | ok | ok | interactv req | ok | ok | ok |
| reflective_loader | ok | ok | ok | ok | ok | ok |
| spawn | | | | | | |
| inject | | | | ok | ok | |
### 注意事项
- websocket x86 优化版 shellcode 需要使用 -Interactive 标志编译,且需手动编辑生成的汇编代码。MSVC 似乎添加了 2 个从未被引用的 `voltbl ` 代码段,并导致编译失败。需要将它们移除。
- inject:在进行任何更改后,必须根据编译后的汇编代码验证 `kShellcodeLength` 常量。检查 `out\shellcode\temp\inject\` 中的 `.asm` 文件,并在 shellcode 大小发生变化时重新测量。
## 示例用法(inject,x64)
### 准备
- 编译 inject shellcode 以及你想要注入的 shellcode(例如 `websocket.c`):
- `.\Auxilary\compile_c_shellcode.ps1 .\C-Shellcode\inject.c -Architecture x64 -DebugPrint`
- `.\Auxilary\compile_c_shellcode.ps1 .\C-Shellcode\websocket.c -Architecture x64`
- 将它们拼接起来,并在两者之间前置一个 DWORD 大小的 payload:
- `python .\Auxilary\concat_binaries.py .\out\shellcode\bin\inject_dbg_x64.bin .\out\shellcode\bin\websocket_x64.bin --length`
- 输出:`.\concat.bin` (inject shellcode | 4-byte 大小 | payload shellcode)
### 执行
- 将 `concat.bin` 注入到任何进程中(例如使用 `SelfInjector.exe` 进行调试,或使用 `ShellcodeInjector.exe` 针对另一个进程)
- inject shellcode 会按名称查找 `DummyWinsock2App.exe`,在其中分配 RX 内存,复制 payload,并生成一个远程线程
### 接下来会发生什么?
- `concat.bin` 被注入到宿主进程中
- inject shellcode 从位于 `kShellcodeLength - offset` 处的 4 字节头部读取 payload 大小
- 它通过 Toolhelp32 遍历进程列表来定位目标进程
- 在目标进程中分配 `PAGE_EXECUTE_READ` 内存,通过 `WriteProcessMemory` 写入 payload
- 生成一个指向 RX 内存的远程线程
## 待办事项
- 完成 spawn.c
- inject:首次编译后验证 `kShellcodeLength` 值,添加 VirtualFreeEx 清理逻辑
- inject:添加 x86 支持(编译后测量偏移量)
## 免责声明
本项目仅供教育和研究目的使用。它在受控环境中演示了底层的 Windows 内部机制和攻击性技术。所有 shellcode 均以包含在解决方案中的虚拟测试应用程序为目标。
## 鸣谢
- PEB 遍历技术改编自 [ired.team](https://www.ired.team/offensive-security/code-injection-process-injection/writing-and-compiling-shellcode-in-c)
- 汇编修补方法受到了 [hasherezade 的论文](https://vxug.fakedoma.in/papers/VXUG/Exclusive/FromaCprojectthroughassemblytoshellcodeHasherezade.pdf) 的启发
标签:AI合规, HTTP Archive, Linux, Shellcode编写, Windows底层, 免杀技术, 安全意识培训, 客户端加密, 暴力破解检测, 网络信息收集, 逆向工具