commit 292edc9fe330e4c17298763c3efd8451c2adc486
parent d5ebfbdac2fd0471b76ce67e5651e998f53c4e15
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date: Sat, 4 Jul 2026 01:27:59 +0200
Code cleanup
Diffstat:
| M | .gitignore | | | 1 | - |
| M | Makefile | | | 8 | ++------ |
| A | elf_payload.h | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
| A | magic.h | | | 34 | ++++++++++++++++++++++++++++++++++ |
| M | main.c | | | 128 | ++++++++++++++++++++++++------------------------------------------------------- |
| A | utils.h | | | 83 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
6 files changed, 199 insertions(+), 97 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -4,4 +4,3 @@ test/
*.inc.h
*.inc.s
stabbish
-bbox/features.h
diff --git a/Makefile b/Makefile
@@ -19,14 +19,10 @@ stabbish: main.o bbox/busybox.inc.o | $(MUSL_CC)
$(info $() LD $@)
@$(CC) $(CFLAGS) $^ -o $@
-main.o: main.c bbox/busybox.inc.h bbox/features.h | $(MUSL_CC)
+main.o: main.c bbox/busybox.inc.h magic.h elf_payload.h utils.h | $(MUSL_CC)
$(info $() CC $@)
@$(CC) $(CFLAGS) -c $< -o $@
-bbox/features.h: $(BBOX)
- $(info $() GEN $@)
- @$^ --list | sed 's/[-\[\.]/_/g' | awk '{printf "#define BB_HAVE_%s \n", $$1}' >$@
-
%.inc.h: tmplt/inc.h
$(info $() GEN $@)
@sed 's@NAME@$(patsubst %.inc.h,%,$(@F))@g' $< > $@
@@ -85,7 +81,7 @@ test: test/stabbish_plain test/stabbish_bzip2 test/stabbish_gzip test/stabbish_x
clean_bbox:
$(info $() CLEAN bbox)
- @rm -r bbox/*.inc.* bbox/features.h
+ @rm -r bbox/*.inc.*
clean_test:
$(info $() CLEAN test)
diff --git a/elf_payload.h b/elf_payload.h
@@ -0,0 +1,42 @@
+#pragma once
+#include <elf.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/sendfile.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+#if defined(__LP64__)
+#define ElfW(type) Elf64_##type
+#else
+#define ElfW(type) Elf32_##type
+#endif
+
+#define ENOPAYLOAD -2
+
+static fd elf_payload(const char *path) {
+ static fd try_return = -1;
+
+ fd trys(in, open(path, O_RDONLY));
+
+ ElfW(Ehdr) header;
+ try(read(in, &header, sizeof(header)));
+
+ size_t trys(size, lseek(in, 0, SEEK_END));
+ off_t offset = header.e_shoff + (header.e_shentsize * header.e_shnum);
+ size_t payload_size = size - offset;
+
+ if (payload_size == 0) {
+ close(in);
+ return ENOPAYLOAD;
+ }
+
+ int trys(payload, memfd_create("payload", 0));
+ try(sendfile(payload, in, &offset, payload_size));
+ try(lseek(payload, SEEK_SET, 0));
+
+ close(in);
+
+ return payload;
+}
diff --git a/magic.h b/magic.h
@@ -0,0 +1,34 @@
+#pragma once
+#include <stdlib.h>
+
+#include "utils.h"
+#include <unistd.h>
+
+struct magic {
+ const char *tool;
+ size_t length;
+ unsigned char byte[16];
+};
+
+const struct magic MAGICS[] = {
+ {"xzcat", 6, {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}},
+ {"zcat", 2, {0x1F, 0x8B}},
+ {"bzcat", 3, {0x42, 0x5A, 0x68}},
+};
+
+static struct magic magic_detect(fd file) {
+ static struct magic try_return = {NULL, 0, {0x00}};
+
+ unsigned char header[10];
+
+ size_t trys(header_len, read(file, &header, 10));
+
+ for (int i = 0; i < tsizeof(MAGICS); i++) {
+ if (header_len > MAGICS[i].length &&
+ memcmp(header, MAGICS[i].byte, MAGICS[i].length) == 0) {
+ return MAGICS[i];
+ }
+ }
+
+ return try_return;
+}
diff --git a/main.c b/main.c
@@ -1,9 +1,8 @@
#define _GNU_SOURCE 1
#include <elf.h>
-#include <errno.h>
-#include <fcntl.h>
#include <malloc.h>
#include <sched.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -11,107 +10,56 @@
#include <unistd.h>
#include "bbox/busybox.inc.h"
-#include "bbox/features.h"
-
-#if defined(__LP64__)
-#define ElfW(type) Elf64_##type
-#else
-#define ElfW(type) Elf32_##type
-#endif
-
-struct magic {
- size_t length;
- unsigned char byte[16];
- const char *tool;
-};
-
-const struct magic MAGICS[] = {
-#ifdef BB_HAVE_xzcat
- {.length = 6,
- .byte = {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00},
- .tool = "xzcat"},
-#endif
-#ifdef BB_HAVE_zcat
- {.length = 2, .byte = {0x1F, 0x8B}, .tool = "zcat"},
-#endif
-#ifdef BB_HAVE_bzcat
- {.length = 3, .byte = {0x42, 0x5A, 0x68}, .tool = "bzcat"},
-#endif
-#ifdef BB_HAVE_zstdcat
- {.length = 4, .byte = {0x28, 0xB5, 0x2F, 0xFD}, .tool = "zstdcat"},
-#endif
-};
-const size_t MAGICS_size = sizeof(MAGICS) / sizeof(MAGICS[0]);
-
-#define checkerr(cmd, chk) \
- if (!((cmd)chk)) { \
- fprintf(stderr, "%s:%i: %s: %s\n", __FILE__, __LINE__, #cmd, \
- strerror(errno)); \
- return errno; \
- }
+#include "elf_payload.h"
+#include "magic.h"
+#include "utils.h"
int main(int argc, char **argv) {
- int bbox, script, self, envfile;
- size_t self_size;
- unsigned char *self_map;
-
- checkerr(bbox = memfd_create("busybox", 0), != -1);
- checkerr(envfile = memfd_create("envfile", 0), != -1);
- dprintf(envfile, "export ENV; echo No payload present, starting shell.");
+ static int try_return = -1;
- char *envstr;
- checkerr(asprintf(&envstr, "/dev/fd/%i", envfile), != -1);
- setenv("ENV", envstr, 1);
+ bool start_shell = argc > 1 && strcmp(argv[1], "--stabbish-shell") == 0;
+ if (start_shell)
+ shift(1);
- checkerr(asprintf(&envstr, "/dev/fd/%i", bbox), != -1);
- setenv("BUSYBOX", envstr, 1);
+ fd trys(busybox, memfd_create("busybox", 0));
+ fd trys(rcfile, memfd_create("rcfile", 0));
+ fd trys(payload, elf_payload("/proc/self/exe"));
- checkerr(write(bbox, _inc_busybox, _inc_busybox_size), != -1);
+ try(write(busybox, _inc_busybox, _inc_busybox_size));
- checkerr(self = open("/proc/self/exe", O_RDONLY), != -1);
- self_size = lseek(self, 0, SEEK_END);
+ setenv("ENV", pasprintf("/dev/fd/%i", rcfile), 1);
+ setenv("BUSYBOX", pasprintf("/dev/fd/%i", busybox), 1);
- checkerr(self_map = mmap(NULL, self_size, PROT_READ, MAP_PRIVATE, self, 0),
- != (void *)-1);
- close(self);
-
- const ElfW(Ehdr) *header = (const ElfW(Ehdr) *)self_map;
-
- int payload_i = header->e_shoff + (header->e_shentsize * header->e_shnum);
- int payload_size = self_size - payload_i;
-
- if (payload_size <= 0) {
- argv[0] = "ash";
- return fexecve(bbox, argv, environ);
+ if (payload == ENOPAYLOAD) {
+ try(dprintf(rcfile, "echo No payload present, starting shell."));
+ } else {
+ setenv("PAYLOAD", pasprintf("/dev/fd/%i", payload), 1);
}
- const char *tool = NULL;
- for (int i = 0; i < MAGICS_size; i++) {
- if (MAGICS[i].length < payload_size &&
- memcmp(MAGICS[i].byte, &self_map[payload_i], MAGICS[i].length) == 0) {
- tool = MAGICS[i].tool;
- break;
- }
+ if (start_shell || payload == ENOPAYLOAD) {
+ argv[0] = "ash";
+ return fexecve(busybox, argv, environ);
}
- checkerr(script = memfd_create("script", 0), != -1);
- checkerr(write(script, &self_map[payload_i], payload_size), != -1);
- munmap(self_map, self_size);
+ struct magic magic = magic_detect(payload);
+ if (magic.tool) {
+ fd trys(extracted, memfd_create("extracted", 0));
+ char *tool = strdup(magic.tool);
+ struct stdstream std = {payload, extracted, -1};
- char *scriptarg;
- if (tool)
- asprintf(&scriptarg, ". <(%s /dev/fd/%i)", tool, script);
- else
- asprintf(&scriptarg, ". /dev/fd/%i", script);
+ lseek(payload, SEEK_SET, 0);
+ try(memexecv(busybox, (char *[]){tool, NULL}, NULL, std));
+ dup2(extracted, payload);
+ free(tool);
+ }
- char **newargv = malloc(sizeof(char *) * (argc + 4));
- newargv[0] = "ash";
- newargv[1] = "-c";
- newargv[2] = scriptarg;
- for (int i = 0; i < argc; i++) {
- newargv[i + 3] = argv[i];
+ char **bb_argv = malloc(sizeof(char *) * (argc + 4));
+ bb_argv[0] = "ash";
+ bb_argv[1] = "-c";
+ bb_argv[2] = pasprintf(". /dev/fd/%i", payload);
+ for (int i = 0; i <= argc; i++) {
+ bb_argv[i + 3] = argv[i];
}
- newargv[argc + 3] = NULL;
- return fexecve(bbox, newargv, environ);
+ return fexecve(busybox, bb_argv, environ);
}
diff --git a/utils.h b/utils.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+typedef int fd;
+
+#define shift(n) \
+ if (n < argc) { \
+ argv[n] = argv[0]; \
+ argv = &argv[n]; \
+ argc -= n; \
+ }
+
+#define tsizeof(table) sizeof(table) / sizeof(table[0])
+
+#define trys2(nam, cmd, chk) \
+ nam = cmd; \
+ try2(nam, chk)
+
+#define trys(nam, cmd) trys2(nam, cmd, != -1)
+
+#define try2(cmd, chk) \
+ if (!((cmd)chk)) { \
+ fprintf(stderr, "%s:%i: %s: %s\n", __FILE__, __LINE__, #cmd, \
+ strerror(errno)); \
+ return try_return; \
+ }
+
+#define try(cmd) try2(cmd, != -1)
+
+static char *pasprintf(const char *__restrict str, ...) {
+ va_list ap;
+ va_start(ap, str);
+
+ char *out;
+ if (vasprintf(&out, str, ap) == -1)
+ out = NULL;
+
+ va_end(ap);
+ return out;
+}
+
+struct stdstream {
+ fd in;
+ fd out;
+ fd err;
+};
+
+static int memexecv(fd exe, char **argv, char **envp, struct stdstream std) {
+ int try_return = -1;
+ pid_t trys(pid, fork());
+
+ if (pid) {
+ int wstatus;
+ waitpid(pid, &wstatus, 0);
+ if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) {
+ fprintf(stderr, "Child process exited with code %i\n",
+ WEXITSTATUS(wstatus));
+ return -1;
+ }
+ } else {
+ if (std.in >= 0)
+ dup2(std.in, 0);
+ if (std.out >= 0)
+ dup2(std.out, 1);
+ if (std.err >= 0)
+ dup2(std.err, 2);
+
+ exit(fexecve(exe, argv, envp));
+ }
+
+ return 0;
+}