- 网络安全
【免费下载链接】sliver
Adversary Emulation Framework
Beignet 是 Sliver Adversary Emulation Framework 在 macOS 平台上生成 shellcode 的核心转换库,其作用相当于 Windows 平台上的 Donut:把darwin/arm64与darwin/amd64架构的.dylib动态库转换为位置无关(PIC)的原始 shellcode 缓冲区,既可独立作为命令行工具使用,也可作为 Go 库被导入。读完本文,你将掌握 Beignet 的 CLI 用法、Go API 调用方式、aPLib 压缩选项、源码构建流程,以及它如何在 Sliver 的generate管线中被实际调用。
Beignet 是什么
Beignet(README.md)是 SliverArmory 组织为 macOS 准备的 Donut 等价物。它的核心能力是:
- 将
darwin/arm64(Apple Silicon)与darwin/amd64(Intel)的.dylib文件转换为 macOS PIC shellcode; - 生成的 shellcode 通过一个内嵌的内存加载器(embedded loader)在目标进程内直接加载 dylib,全程不落盘;
- 支持以 CLI 二进制形式使用,也可以作为 Go 库被其他项目(如 Sliver 的
server)导入。
从源码结构看,仓库由三大部分组成(见 vendor/github.com/sliverarmory/beignet 目录):
| 模块 | 路径 | 作用 |
|---|---|---|
| 顶层 Go API | shellcode.go、arm64_bootstrap.go、amd64_bootstrap.go | 入口函数、Mach-O 校验、架构引导桩(bootstrap stub)生成 |
| 内存加载器 | internal/loader/beignet_loader.c | 基于 dyld 的免落盘 Mach-O 加载器 C 源码 |
| 压缩器 | internal/aplib | aPLib(AP32)打包/解包实现 |
| 加载器镜像 | internal/stager | 编译好的 arm64/amd64 加载器二进制及go:generate再生成机制 |
CLI 用法:一行命令把 dylib 变成 shellcode
构建出beignet可执行文件后,最基本的转换命令是:
./beignet --out payload.bin ./payload.dylib./payload.dylib:输入的 macOS 动态库(thin 或 fat Mach-O 均可,支持darwin/arm64、darwin/amd64两种 slice);--out payload.bin:指定输出的原始 shellcode 文件。
可选地,用 aPLib 的 “AP32” safe-packed 格式压缩待加载的 dylib,以缩小最终 shellcode 体积:
./beignet --compress --out payload.bin ./payload.dylib从源码看,压缩开关对应 shellcode.go 中的逻辑:当Options.Compress为 true 时,dylib 字节流会先经aplib.PackSafe()压缩,再被拼进输出缓冲区;而内嵌加载器在运行时能识别 AP32 魔数('AP32',定义于 beignet_loader.c),自动解包后再交给 dyld 加载,因此压缩后的 shellcode 无需额外的解包代码参与。
从源码构建
仓库根目录执行:
makeMakefile 默认通过go build -o beignet ./cli构建 CLI 二进制。它还对构建环境做了缓存隔离:
GOCACHE指向$(CURDIR)/.go-cache;ZIG_GLOBAL_CACHE_DIR/ZIG_LOCAL_CACHE_DIR指向$(CURDIR)/.zig-cache。
另外,Makefile 中还有一个用于交叉编译测试运行器的目标(make runner),它使用 Zig 将 C 代码编译为aarch64-macos可执行文件,说明项目对 arm64 目标的验证依赖 Zig 工具链。
重新生成内嵌加载器(darwin/arm64 + darwin/amd64)
内嵌加载器镜像不是手工维护的二进制,而是由 C 源码生成并go:embed进包的。如果需要针对新版本 macOS 或 dyld 行为重新生成,执行:
go generate ./internal/stager这条命令触发 internal/stager/gen.go 中的指令:
//go:generate go run ../../internal/tools/genstager -src ../../internal/loader/beignet_loader.c -out .即由genstager工具读取 beignet_loader.c,编译并抽取相关 segment 后输出两个产物(见 internal/stager 目录):
stager_darwin_arm64.bin+stager_darwin_arm64_gen.gostager_darwin_amd64.bin+stager_darwin_amd64_gen.go
生成的 Go 文件(例如 stager_darwin_amd64_gen.go)通过//go:embed把二进制与入口偏移量(如 amd64 的0x4e0)编译进最终库中,运行时由 stager.go 的LoaderText(cpu)按目标架构返回对应镜像。
作为 Go 库使用:API 与调用流程
Beignet 暴露了两个核心转换函数(shellcode.go):
func DylibFileToShellcode(path string, opts Options) ([]byte, error) func DylibToShellcode(dylib []byte, opts Options) ([]byte, error)Options结构体支持两个字段:
| 字段 | 默认值 | 说明 |
|---|---|---|
EntrySymbol | _StartW | 在加载模块中解析的入口符号名;未加前导下划线时会被自动补上,且不允许包含 NUL 字节 |
Compress | false | 是否用 aPLib “AP32” safe-packed 格式压缩 dylib 缓冲区 |
DylibFileToShellcode内部通过macho.NewFatFile解析输入,支持 thin 与 fat 两种格式:若是 fat Mach-O,会优先按当前runtime.GOARCH选择 slice,并保持 arm64 优先于 amd64 的确定性回退顺序。若输入既不是MH_DYLIB也不是MH_BUNDLE,或架构不受支持,会分别返回ErrInvalidMachO与ErrUnsupportedArch(见 shellcode.go)。
输出缓冲区布局
DylibToShellcode生成的 shellcode 遵循严格的布局(shellcode.go):
- 架构引导桩(bootstrap stub):一段几十字节的位置无关汇编,负责设置寄存器参数并跳转到加载器;
- 对齐填充:加载器镜像要求起始于页边界(
0x1000),以保持 ADRP 相对寻址有效,因此 bootstrap 之后会按页对齐补齐; - 内嵌加载器镜像:从 C 源码抽取的(近似)位置无关 Mach-O 镜像;
- 载荷区:原始 dylib(或经 aPLib 压缩后的数据),按 16 字节对齐;
- 入口符号名:以 NUL 结尾的符号字符串,供加载器在镜像内查找入口。
引导桩的寄存器约定因架构而异:
- arm64(arm64_bootstrap.go):
x0= 载荷指针、x1= 载荷大小、x2= 符号指针,最后br跳转到加载器入口;固定长度为21 * 4字节。 - amd64(amd64_bootstrap.go):
rdi= 载荷指针、rsi= 载荷大小、rdx= 符号指针,通过call rax调用加载器并ret返回调用者(保持 System V ABI 的栈对齐);固定长度 59 字节。
两个引导桩都是运行时用 Keystone 引擎 现场汇编生成,并用固定长度断言保证输出稳定性。
内嵌加载器的实现原理(免落盘加载)
internal/loader/beignet_loader.c 是整个方案的灵魂,其设计要点从源码注释与实现中可以明确归纳:
- 源自 Metasploit 的 OSX Stager:文件头注明基于 Rapid7 的 OSX stager 源码,采用 BSD-3-clause 许可。
- freestanding 风格,不调用 libc:文件被编译成 Mach-O 后,相关 segment 被抽取为扁平的内存镜像当作 shellcode 执行,因此所有系统调用(
mmap、mprotect、shared_region_check_np)都以内联汇编 +svc/syscall指令直接发起。 - 主加载路径绝不写盘:不使用
open/write/unlink创建临时文件。 - 双路径策略:
- x86_64:走 libdyld 导出的传统
NS*API(NSCreateObjectFileImageFromMemory、NSLinkModule、NSLookupSymbolInModule、NSAddressOfSymbol),且先把MH_DYLIB归一化为MH_BUNDLE私有副本,避免触发基于磁盘的回退路径(见 beignet_loader.c); - arm64:解析
/usr/lib/dyld中 dyld4 的 C++ 符号(dyld4::JustInTimeLoader::make、analyzeSegmentsLayout、loadDependents、applyFixups、runInitializersBottomUpPlusUpwardLinks等),用JustInTimeLoader从内存加载 Mach-O 镜像,并配合lsl::MemoryManager的可写状态切换与ProtectedStack执行关键流程(见 beignet_loader.c)。
- x86_64:走 libdyld 导出的传统
- AP32 自动解包:若载荷开头是 aPLib safe 头(魔数
'AP32'),加载器会先用内嵌的aP_depack_safe安全解包器解压到匿名映射内存,再进入 dyld 加载流程,错误码统一以返回值形式返回(如 14/15 表示压缩数据损坏、16/17 表示 NS* 加载失败)。
在 Sliver 中的实际应用
Beignet 不是孤立存在的工具,它已被集成进 Sliver 的server/generate模块。在 server/generate/binaries.go 的注释中明确说明:Sliver 生成 shellcode 时按平台选择转换器——Windows 用 Donut,macOS 用 Beignet,Linux 用 malasada。
具体调用点在 server/generate/binaries.go:
shellcodeBin, err := beignet.DylibToShellcode(dylibData, beignet.Options{ EntrySymbol: config.Exports[0], Compress: compress, })其中compress由ShellcodeConfig.Compress == 2决定(binaries.go),对应 aPLib 压缩模式;EntrySymbol直接使用编译出的导出符号。也就是说:在 Sliver 中执行generate并选择 macOS 目标时,darwin/arm64(及darwin/amd64)dylib 会经此管线被转成.binshellcode 文件,供后续注入/加载使用。
适用前提与限制
- 平台限定:Beignet 只面向 macOS,且仅支持
darwin/arm64与darwin/amd64两种架构,其他平台/架构会返回ErrUnsupportedArch。 - 入口符号:dylib 需要暴露可解析的导出符号(默认
_StartW),Beignet 不做符号注入,符号不存在时加载器会返回对应错误码。 - 加载器版本敏感度:arm64 路径依赖 dyld4 的内部符号,不同 macOS 版本之间可能存在差异;这正是提供
go generate ./internal/stager重新生成机制的原因——当目标系统 dyld 变化时可重新构建内嵌加载器。 - 压缩权衡:
--compress会减小 shellcode 体积,但载荷区变为 AP32 压缩流,加载器运行时需额外解压,二者需按场景取舍。
总结
Beignet 是 Sliver 在 macOS 平台生成 PIC shellcode 的关键组件:CLI 与 Go API 双形态、aPLib 压缩、免落盘 dyld 内存加载、跨 arm64/amd64 架构支持,再加上go generate可再生的内嵌加载器,使其成为一条完整、可维护的 dylib→shellcode 流水线。无论是想独立把 dylib 转成可注入的 macOS shellcode,还是理解 Slivergenerate后端对 macOS 目标的处理细节,都可以从本仓库的 README.md、shellcode.go 与 beignet_loader.c 入手深入研读。
- 网络安全
【免费下载链接】sliver
Adversary Emulation Framework
相关推荐
将 Gatsby Starter 转换为 Gatsby Theme 的完整实战指南
将 Gatsby Starter 转换为 Gatsby Theme 的完整实战指南 Gatsby Theme 是可直接发布到 npm 的插件类型,它包含 gat
前端静态站点Web框架danmaku2ass:将弹幕转换为ASS字幕的完整指南
danmaku2ass:将弹幕转换为ASS字幕的完整指南 danmaku2ass 是一个功能强大的开源工具,专门用于将来自Niconico、Acfun、Bili
CLI音视频将现有软件转换为 Apify Actor:Agentic Awesome Skills 中 Actorization 技能的完整实战指南
将现有软件转换为 Apify Actor:Agentic Awesome Skills 中 Actorization 技能的完整实战指南 Actorizatio
AI 技能AI 插件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考