
리눅스 공유 라이브러리를 셸코드 로더로
Donut for Linux, Linux ELF 공유 오브젝트(.so)를 위치 독립적인 .bin 블롭으로 변환하여 메모리에서 직접 실행할 수 있게 합니다 (예: mmap'd 영역에 복사한 후 함수 포인터로 점프하는 방식).
이 프로젝트는 의도적으로 memfd (memfd_create, execveat on memfd 등)를 사용하지 않습니다.
amd64arm64386요구 사항:
go generate 및 테스트에 필요)CLI 빌드:
make
hello-world .so를 빌드하고 .bin으로 변환한 후 포함된 runner로 실행합니다:
# Build payload .so
go build -buildmode=c-shared -o /tmp/hello.so ./testdata/hello
# Convert .so -> .bin (call the exported symbol "Hello")
./malasada --call-export Hello -o /tmp/hello.bin /tmp/hello.so
# Optional: compress the embedded payload (stage0 will depack before loading)
./malasada --compress --call-export Hello -o /tmp/hello.compressed.bin /tmp/hello.so
# Build the runner (PIC shellcode executor) with zig cc
zig cc -O2 -o /tmp/runner ./testdata/runner/runner.c
# Run it (stage0 hands off to ld-linux; runner will not return)
/tmp/runner /tmp/hello.bin
예상 출력에는 다음이 포함됩니다:
hello from go
레포지토리는 사전 빌드된 stage0 블롭을 포함합니다:
internal/stage0/stage0_linux_amd64.bininternal/stage0/stage0_linux_arm64.bininternal/stage0/stage0_linux_386.bininternal/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로 runner를 빌드한 후 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 .
# Or via Makefile:
make docker-test-386