
Загрузчик шеллкода из разделяемой библиотеки Linux
Donut для Linux преобразует разделяемую объектную библиотеку Linux ELF (.so) в позиционно-независимый двоичный блок .bin, который может быть выполнен напрямую из памяти (например, путём копирования в область mmap и перехода к нему как к указателю на функцию).
Этот проект целенаправленно избегает memfd (memfd_create, execveat на memfd и т.д.).
amd64arm64386Требования:
go generate и для тестов)Сборка CLI:
make
Соберите .so "hello world", преобразуйте его в .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
# Сборка раннера (исполнителя PIC shellcode) с помощью zig cc
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