/* * eggrun -- shellcode loader. Use it as an interpreter with binfmt_misc * see http://www.secdev.org/projects/eggrun/ * for more informations * * echo ':shcode:E::egg::/path/to/eggrun:' > /proc/sys/fs/binfmt_misc/register * * Copyright (C) 2006 Philippe Biondi * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ /* $Id: eggrun.c,v 1.8 2006/11/16 12:23:29 pbi Exp pbi $ */ #include #include #include #include #include #include #include #include #define HIJACK_CORE_SIGS(x) do { \ signal(SIGQUIT, (x)); signal(SIGILL, (x)); signal(SIGABRT, (x)); \ signal(SIGFPE, (x)); signal(SIGSEGV, (x)); signal(SIGBUS, (x)); \ signal(SIGSYS, (x)); signal(SIGTRAP, (x)); \ } while (0) int (*egg)(); off_t len; char *gdb_argv1; char gdb_argv2[32]; int debug; static void crash_handler(int sig) { int gdb; /* Ooops, egg crashed. Let's do it again with gdb attached */ HIJACK_CORE_SIGS(SIG_DFL); switch (gdb=fork()) { case 0: execlp("gdb", "gdb", "--quiet", "-ex=jump *$pc", // prevents system call restart gdb_argv1, gdb_argv2, NULL); exit(0); // If we cannot exec gdb, forget about it. case -1: break; default: waitpid(gdb, NULL, 0); // wait until 'jump *$pc' if ((debug >= 2) && (sig==SIGSEGV)) { mprotect(egg, len, PROT_EXEC|PROT_READ|PROT_WRITE); signal(sig, SIG_IGN); } raise(sig); } } int egg_exec(char *eggfile) { int f; f = open(eggfile, O_RDONLY); if (f == -1) { perror("open"); return -2; } len = lseek(f, 0, SEEK_END); if (len == -1) { perror("lseek"); return -3; } egg = mmap(NULL, len, (debug < 2) ? PROT_EXEC|PROT_READ|PROT_WRITE : PROT_NONE, MAP_PRIVATE, f, 0); if (!egg) { perror("mmap"); return -4; } if (debug) HIJACK_CORE_SIGS(crash_handler); return egg(); } int egg_hex_dump(char *eggfile) { int f,i; unsigned char c; f = open(eggfile, O_RDONLY); while (read(f, &c, 1)) printf("\\x%02x",c); printf("\n"); close(f); return 0; } int egg_c_dump(char *eggfile) { int f,i; unsigned char c; f = open(eggfile, O_RDONLY); i = 0; printf("\""); while (read(f, &c, 1)) { if ((i%16 == 0) && (i>0)) printf("\"\n\""); printf("\\x%02x",c); i++; } printf("\";\n"); close(f); return 0; } int egg_ndisasm(char *eggfile) { execlp("ndisasm", "ndisasm", "-u", eggfile, 0); } void usage(void) { fprintf(stderr, "Usage: shcode.egg [-d[d]|-c|-s|-n]\n" " -d: debug mode 1: launch gdb at first error\n" " -dd: debug mode 2: stop gdb at first instruction\n" " -c,-x: dump hexa string in c mode or raw\n" " -n: run 'ndisasm -u' on the shellcode\n"); exit(0); } int main(int argc, char *argv[]) { char c; struct sigaction act; int (*operation)() = egg_exec; if (argc < 2) return -1; gdb_argv1 = argv[0]; snprintf(gdb_argv2, sizeof(gdb_argv2)-1, "%i", getpid()); while ( (c = getopt(argc-1, argv+1, "dhcxn")) != -1 ) { switch (c) { case 'd': debug++; break; case 'c': operation = egg_c_dump; break; case 'x': operation = egg_hex_dump; break; case 'n': operation = egg_ndisasm; break; case 'h': case '?': /* catch-all for bad options */ default: usage(); } } return (*operation)(argv[1]); }