dumper.c

#define _GNU_SOURCE

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Source: https://ctftime.org/writeup/7670

// CHANGE line 24 (and 12) to the names of the binary you want to dump
// gcc -shared -fPIC -Wall dumper.c -o dumper.so
// env LD_PRELOAD=./dumper.so ./test

int custom_main(int argc, char** argv, char** envp) {
  // parse /proc/self/maps and dump it
  FILE* maps = fopen("/proc/self/maps", "r"); 
  size_t n = 0;
  char* line = NULL;
  while(getline(&line, &n, maps) >= 0) {

    printf("%s", line);

    // Do not dump outside the target
    if(!strstr(line, "test")) continue; // CHANGE HERE 

    // parse start/end address from line
    char* start = (char*)strtoll(strtok(line, "-"), NULL, 16);
    char* end = (char*)strtoll(strtok(NULL, " "), NULL, 16);

    // dump to file
    char outname[100];
    snprintf(outname, 100, "dump.%llx", (long long)start);
    FILE* out = fopen(outname, "wb");
    fwrite(start, 1, (long long)(end - start), out);
    fclose(out);
  }

  free(line);
  fclose(maps);

  printf("dumped process!\n");
  return 0;
}

// our own implementation of __libc_start_main (I copied the function signature from Google search results :)
int __libc_start_main (int (*main)(int, char**, char**), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) {
  // lookup the original __libc_start_main (yes, c function pointer syntax is weird)
  int (*real_start_main)(int (*main) (int, char**, char**), int argc, char** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) = dlsym(RTLD_NEXT, "__libc_start_main");

  // call original __libc_start_main, but replace "main" with our custom implementation
  return real_start_main(&custom_main, argc, ubp_av, init, fini, rtld_fini, stack_end);
}