Linux 版的 Donut,将 Linux ELF 共享对象(.so)转换为位置无关的 .bin 二进制块,可直接从内存中执行(例如,将其复制到 mmap 区域后,作为函数指针跳转执行)。
本项目有意避免使用 memfd(memfd_create、对 memfd 执行 execveat 等)。
amd64arm64386依赖:
go generate 及测试所需)构建 CLI:
make
构建一个 hello-world .so,将其转换为 .bin,并使用附带的运行器执行:
# 构建 payload .so
go build -buildmode=c-shared -o /tmp/hello.so ./testdata/hello
# 将 .so 转换为 .bin(调用导出的符号 "Hello")
./malasada --call-export Hello -o /tmp/hello.bin /tmp/hello.so
# 可选:压缩嵌入的 payload(stage0 会在加载前解压)
./malasada --compress --call-export Hello -o /tmp/hello.compressed.bin /tmp/hello.so
# 使用 zig cc 构建运行器(PIC shellcode 执行器)
zig cc -O2 -o /tmp/runner ./testdata/runner/runner.c
# 执行(stage0 将控制权交给 ld-linux;运行器不会返回)
/tmp/runner /tmp/hello.bin
预期输出包含:
hello from go
仓库嵌入了预构建的 stage0 二进制块:
internal/stage0/stage0_linux_amd64.bininternal/stage0/stage0_linux_arm64.bininternal/stage0/stage0_linux_386.bin如果你修改了 internal/stage0/stage0.c 或 internal/stage0/linker.ld,请重新生成:
go generate ./...
CLI 始终使用嵌入的 stage0 二进制块(运行时无需 Zig)。要修改 stage0,请编辑 internal/stage0/stage0.c 并重新运行:
go generate ./...
testdata/Dockerfile 构建 CLI、构建 hello .so、将其转换为 .bin、使用 Zig 构建运行器,并在 Linux 容器中运行端到端测试。
示例:
docker buildx build --platform linux/amd64 -f testdata/Dockerfile .
docker buildx build --platform linux/arm64 -f testdata/Dockerfile .
docker buildx build --platform linux/386 -f testdata/Dockerfile .
# 或通过 Makefile:
make docker-test-386