You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

98 lines
3.0 KiB

// Created by ember@lunar.town with scanf_replacement from Graham Northup
// https://gist.github.com/emberian/33ee7efd815d87a1629671a0e0a185cc
//
#define _GNU_SOURCE
// compile with: gcc -ldl -o find_main_shim.so -shared -fPIC find_main_shim.c
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <sys/mman.h>
// decl ripped from
// https://github.molgen.mpg.de/git-mirror/glibc/blob/master/sysdeps/x86/libc-start.c
#define LIBC_START_DECL \
(int (*main)(int, char **, char **, void *), int argc, char **argv, \
__typeof(main) init, void (*fini)(void), void (*rtld_fini)(void), \
void *stack_end)
#define OFFSET_TO_TARGET_INSTR 135
// this is L: CALL L. a nice tight infinite loop that will eventually overflow
// the stack.
char codecave_call_patch_contents[] = {0xE8, 0xFF, 0xFF, 0xFF, 0xFF};
int scanf_replacement(const char *fmt, ...) {
va_list ap;
static int (*real_vscanf)(const char *, va_list) = NULL;
int res;
int *guessptr;
int magic = 0;
if (!strcmp(fmt, "%s")) { // Assume this is our magic call
magic = 1;
va_start(ap, fmt);
guessptr =
va_arg(ap, int *); // Extract &guess from main (points to the stack)
va_end(ap);
}
va_start(ap, fmt);
if (!real_vscanf) {
real_vscanf = dlsym(RTLD_NEXT, "vscanf");
}
res = real_vscanf(fmt, ap);
va_end(ap);
if (magic && !isdigit(*((char *)guessptr))) {
// This offset is computed by hand, assuming the
// compiler assigned the stack frame in order (flaky)
int guess;
guessptr += 25; // Skip that pesky array
printf("The gods of randomness smile on you! The answer is %d.\n",
guessptr[4]);
guess = guessptr[4];
guessptr -= 25;
snprintf((char *)guessptr, 100, "%d", guess);
return 1;
}
return res;
}
int __libc_start_main LIBC_START_DECL {
int(*real_libc_start) LIBC_START_DECL;
printf("Oh, main is right here: %ld\n", main);
// we need to call the real __libc_start_main. fortunately, dlsym got our back
// (note to grm: i'm a bit confused that there isn't an auxv here, dafuq?)
real_libc_start = dlsym(RTLD_NEXT, "__libc_start_main");
// forgive me for i have sinned
if (mprotect((char *)main - ((long int)main % 4096), 4096 * 2, PROT_WRITE) !=
0) {
printf("Failed to make main writable, %s\n", strerror(errno));
return -1;
}
// here's one way of patching in the thing...
char *main_contents = (char *)main;
int offset = (int)(main_contents + OFFSET_TO_TARGET_INSTR +
5 /* 5 accounts for the size of the call instr, ie, addr of
the following instr */
- (char *)(&scanf_replacement));
*(int *)(&codecave_call_patch_contents[1]) = offset;
memcpy(main_contents + OFFSET_TO_TARGET_INSTR, codecave_call_patch_contents,
sizeof(codecave_call_patch_contents));
real_libc_start(main, argc, argv, init, fini, rtld_fini, stack_end);
}