news 2026/9/25 7:59:12

Sliver 中的 Beignet:将 macOS dylib 转换为 ARM64/x86_64 PIC Shellcode 的完整技术指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Sliver 中的 Beignet:将 macOS dylib 转换为 ARM64/x86_64 PIC Shellcode 的完整技术指南
  • 网络安全

【免费下载链接】sliver

Adversary Emulation Framework

项目地址:https://gitcode.com/gh_mirrors/sl/sliver
点击查看免费下载

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 APIshellcode.go、arm64_bootstrap.go、amd64_bootstrap.go入口函数、Mach-O 校验、架构引导桩(bootstrap stub)生成
内存加载器internal/loader/beignet_loader.c基于 dyld 的免落盘 Mach-O 加载器 C 源码
压缩器internal/aplibaPLib(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 无需额外的解包代码参与。

从源码构建

仓库根目录执行:

make

Makefile 默认通过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.go
  • stager_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 字节
Compressfalse是否用 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):

  1. 架构引导桩(bootstrap stub):一段几十字节的位置无关汇编,负责设置寄存器参数并跳转到加载器;
  2. 对齐填充:加载器镜像要求起始于页边界(0x1000),以保持 ADRP 相对寻址有效,因此 bootstrap 之后会按页对齐补齐;
  3. 内嵌加载器镜像:从 C 源码抽取的(近似)位置无关 Mach-O 镜像;
  4. 载荷区:原始 dylib(或经 aPLib 压缩后的数据),按 16 字节对齐;
  5. 入口符号名:以 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)。
  • 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

项目地址:https://gitcode.com/gh_mirrors/sl/sliver
点击查看免费下载
上一篇:OpenTUI Zig 原生依赖离线打包与可复现构建指南:`zig-deps.tar.gz` 的生成、校验与更新流程
下一篇:emilianJR/chilloutmix_NiPrunedFp32Fix无服务器部署:云平台方案对比

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 7:52:37

豆瓣图书知识图谱实战:Neo4j图数据库推荐系统搭建

简介:本资源是一套面向高校计算机及相关专业(人工智能、自动化、物联网等)学生的毕业设计级实践项目,聚焦豆瓣图书推荐系统与知识图谱构建,深度融合Neo4j图数据库应用开发。项目完整覆盖数据采集、清洗、图模型设计、实…

作者头像 李华
网站建设 2026/9/25 7:52:18

新手避坑指南:AI博士周有贵教你,选GEO软件拒绝套路只讲干货

很多做网站获客、搜索运营的新手,刚接触 GEO 生成式搜索引擎优化的时候,很容易被各种宣传话术绕晕。市面上相关工具、服务商参差不齐,不少运营新人踩坑:工具功能虚标、关键词挖掘不准、收费暗藏套路,做出来的内容不匹配…

作者头像 李华
网站建设 2026/9/25 7:49:54

安徽部分地区用户力荐的净菜加工配送服务商挑选全攻略

很多安徽连锁餐饮品牌拓展长三角市场,或是跨城布局门店的时候,都在找能做食材溯源的配送公司,也会疑问长三角地区有哪些好的食材配送企业,也会咨询能做食材批量加工配送的公司有哪些靠谱选择。伴随着长三角餐饮连锁化发展不断提速…

作者头像 李华