int inject_shellcode(HIJACK *hijack, unsigned long addr, void *data, size_t sz) { return inject_shellcode_freebsd(hijack, addr, data, sz); }
int inject_shellcode(HIJACK *hijack, unsigned long addr, void *data, size_t sz) { REGS origregs; #if defined(FreeBSD) return inject_shellcode_freebsd(hijack, addr, data, sz); #endif write_data(hijack, addr, data, sz); if (ptrace(PTRACE_GETREGS, hijack->pid, NULL, &origregs) < 0) return SetError(hijack, ERROR_SYSCALL); /* There's a lot of duplicated logic here for x86 and x86_64. It used to be unified, but it looked ugly, so I seperated it out. */ #if defined(i686) origregs.esp -= sizeof(unsigned long); if (ptrace(PTRACE_SETREGS, hijack->pid, NULL, &origregs) < 0) return SetError(hijack, ERROR_SYSCALL); write_data(hijack, (unsigned long)(origregs.esp), &(origregs.eip), sizeof(unsigned long)); origregs.eip = (long)addr; /* EIP might need to be adjusted further, depending on if we interrupted a syscall More Info: http://fxr.watson.org/fxr/source/arch/i386/kernel/signal.c?v=linux-2.6#L623 Link valid on 09 April 2009 */ if (origregs.orig_eax >= 0) { switch (origregs.eax) { case -514: /* -ERESTARTNOHAND */ case -512: /* -ERESTARTSYS */ case -513: /* -ERESTARTNOINTR */ case -516: /* -ERESTART_RESTARTBLOCK */ if (IsFlagSet(hijack, F_DEBUG)) fprintf(stderr, "[*] Adjusting EIP due to syscall restart.\n"); origregs.eip += strlen(SYSCALLSEARCH); break; } } #elif defined(x86_64) origregs.rsp -= sizeof(unsigned long); if (ptrace(PTRACE_SETREGS, hijack->pid, NULL, &origregs) < 0) return SetError(hijack, ERROR_SYSCALL); if (IsFlagSet(hijack, F_DEBUG_VERBOSE)) fprintf(stderr, "[*] Pushing RIP: 0x%016lx\n", origregs.rip); write_data(hijack, origregs.rsp, &(origregs.rip), sizeof(unsigned long)); origregs.rip = (unsigned long)addr; /* Above comment about adjusting EIP is valid for x86_64, too. */ if (origregs.orig_rax >= 0) { switch (origregs.rax) { case -514: /* -ERESTARTNOHAND */ case -512: /* -ERESTARTSYS */ case -513: /* -ERESTARTNOINTR */ case -516: /* -ERESTART_RESTARTBLOCK */ if (IsFlagSet(hijack, F_DEBUG)) fprintf(stderr, "[*] Adjusting RIP due to syscall restart.\n"); origregs.rip += strlen(SYSCALLSEARCH); break; } } #endif if (ptrace(PTRACE_SETREGS, hijack->pid, NULL, &origregs) < 0) return SetError(hijack, ERROR_SYSCALL); return SetError(hijack, ERROR_NONE); }