
Chargeur de shellcode depuis une bibliothèque partagée Linux
Donut pour Linux, convertit un objet partagé ELF Linux (.so) en un blob .bin indépendant de la position qui peut être exécuté directement depuis la mémoire (par exemple, en le copiant dans une région mmap'ée et en y sautant comme un pointeur de fonction).
Ce projet évite intentionnellement memfd (memfd_create, execveat sur memfd, etc).
amd64arm64386Prérequis :
go generate et pour les tests)Compiler la CLI :
make
Compilez un .so hello-world, convertissez-le en .bin et exécutez-le avec le runner inclus :
# 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
Le résultat attendu contient :
hello from go
Le dépôt intègre des blobs stage0 précompilés :
internal/stage0/stage0_linux_amd64.bininternal/stage0/stage0_linux_arm64.bininternal/stage0/stage0_linux_386.binSi vous modifiez internal/stage0/stage0.c ou internal/stage0/linker.ld, régénérez-les :
go generate ./...
La CLI utilise toujours les blobs stage0 intégrés (pas besoin de Zig à l'exécution). Pour changer stage0, modifiez internal/stage0/stage0.c et relancez :
go generate ./...
testdata/Dockerfile compile la CLI, compile le .so hello, le convertit en .bin, compile le runner avec Zig et exécute le test de bout en bout dans un conteneur Linux.
Exemples :
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 .
# Ou via le Makefile :
make docker-test-386