Skip to content

Instantly share code, notes, and snippets.

@supechicken
Last active April 25, 2025 14:17
Show Gist options
  • Save supechicken/4c26ae331b404ea309c2ebb3e0d93c02 to your computer and use it in GitHub Desktop.
Save supechicken/4c26ae331b404ea309c2ebb3e0d93c02 to your computer and use it in GitHub Desktop.
Execute embedded program with custom ld-linux
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <linux/limits.h>
#include <sys/mman.h>
extern const char _binary_executable_start, _binary_executable_end;
bool verbose = false;
int main(int argc, char **argv) {
char *new_args[argc + 4], fd_path[PATH_MAX], *interp_path;
// enable verbose logging if requested
if (strcmp(getenv("LD_WRAPPER_VERBOSE") ?: "0", "1") == 0) verbose = true;
// get interpreter path from environment
interp_path = getenv("LD_WRAPPER_INTERPRETER_PATH") ?: "/usr/local/bin/ld.so";
if (verbose) fprintf(stderr, "[+] ELF interpreter set to %s\n", interp_path);
// create a memfd for the executable
int memfd = memfd_create("real-executable", 0),
executable_size = &_binary_executable_end - &_binary_executable_start;
if (memfd == -1) {
fprintf(stderr, "memfd_create() failed: %s\n", strerror(errno));
exit(errno);
}
// full path of memfd
snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%i", memfd);
// command line arguments for ld.so
new_args[0] = "ld.so";
new_args[1] = "--argv0";
new_args[2] = argv[0];
new_args[3] = fd_path;
// copy all argument pointers to new array
for (int i = 1; i < argc; i++) new_args[3 + i] = argv[i];
new_args[argc + 3] = NULL;
if (verbose) {
fprintf(stderr, "[+] New command line:\n[+]\n[+] ");
for (int i = 0; i < argc + 3; i++) {
fprintf(stderr, "%s ", new_args[i]);
}
fprintf(stderr, "\n[+]\n");
}
// load executable into memfd
if (write(memfd, &_binary_executable_start, executable_size) == -1) {
fprintf(stderr, "Failed to write into memfd: %s\n", strerror(errno));
exit(errno);
}
if (verbose) fprintf(stderr, "[+] Now re-exec with %s...\n", interp_path);
// execute the memfd with our dynamic linker
if (execv(interp_path, new_args) == -1) {
fprintf(stderr, "execv() failed: %s\n", strerror(errno));
exit(errno);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment