Created
March 9, 2020 19:51
-
-
Save llandsmeer/81ad107189ae5a8b6581c3c45a36a684 to your computer and use it in GitHub Desktop.
Execute syscall in other process
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <errno.h> | |
#include <signal.h> | |
#include <stdarg.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/ptrace.h> | |
#include <sys/syscall.h> | |
#include <sys/resource.h> | |
#include <sys/types.h> | |
#include <sys/user.h> | |
#include <sys/wait.h> | |
long try_(long err, const char * cmd, int line) { | |
if (err < 0 && errno != 0) { | |
printf("line : %d\n", line); | |
perror(cmd); | |
exit(1); | |
} | |
return err; | |
} | |
#define try(x) try_(x, #x, __LINE__) | |
#ifdef __amd64__ | |
typedef struct user_regs_struct regs_struct; | |
#define IP(regs) regs.rip | |
#define SP(regs) regs.rsp | |
#define SYSCALL_RESULT(regs) regs.rax | |
#endif | |
#ifdef __arm__ | |
typedef struct user_regs regs_struct; | |
#define IP(regs) regs.uregs[15] | |
#define SP(regs) regs.uregs[13] | |
#define SYSCALL_RESULT(regs) regs.uregs[0] | |
#endif | |
#define ALIGN(addr) ((addr) & ~(sizeof(long)-1)) | |
long tsyscall(pid_t pid, long number, ...) { | |
long asm_orig; | |
va_list ap; | |
regs_struct regs_orig, regs; | |
try(ptrace(PTRACE_GETREGS, pid, 0, ®s_orig)); | |
regs = regs_orig; | |
va_start(ap, number); | |
#ifdef __amd64__ | |
static uint8_t asm_syscall[8] __attribute__ ((aligned (8))) = { /*syscall*/ 0x0f, 0x05, /* ud2 */ 0x0f, 0x0b, 0, 0, 0, 0}; | |
regs.rax = number; | |
regs.rdi = va_arg(ap, long); | |
regs.rsi = va_arg(ap, long); | |
regs.rdx = va_arg(ap, long); | |
regs.r10 = va_arg(ap, long); | |
regs.r8 = va_arg(ap, long); | |
regs.r9 = va_arg(ap, long); | |
#endif | |
#ifdef __arm__ | |
static uint8_t asm_syscall[8] __attribute__ ((aligned (4))) = { /*swi 0*/ 0x00, 0xdf, /* illegal */ 0x00, 0xde }; | |
regs.uregs[7] = number; | |
regs.uregs[0] = va_arg(ap, long); | |
regs.uregs[1] = va_arg(ap, long); | |
regs.uregs[2] = va_arg(ap, long); | |
regs.uregs[3] = va_arg(ap, long); | |
regs.uregs[4] = va_arg(ap, long); | |
regs.uregs[5] = va_arg(ap, long); | |
regs.uregs[6] = va_arg(ap, long); | |
#endif | |
assert(sizeof(asm_orig) == sizeof(asm_syscall)); | |
va_end(ap); | |
IP(regs) = ALIGN(IP(regs_orig)); | |
void * ip = (void*)IP(regs); | |
errno = 0; /* must do this for error checking in peektext */ | |
asm_orig = try(ptrace(PTRACE_PEEKTEXT, pid, ip, 0)); | |
try(ptrace(PTRACE_SETREGS, pid, 0, ®s)); | |
try(ptrace(PTRACE_POKETEXT, pid, ip, *(long*)asm_syscall)); | |
try(ptrace(PTRACE_SINGLESTEP, pid, 0, 0)); | |
int wstatus; | |
try(waitpid(pid, &wstatus, 0)); | |
if (WIFEXITED(wstatus)) return WEXITSTATUS(wstatus); | |
try(ptrace(PTRACE_GETREGS, pid, 0, ®s)); | |
try(ptrace(PTRACE_POKETEXT, pid, ip, asm_orig)); | |
try(ptrace(PTRACE_SETREGS, pid, 0, ®s_orig)); | |
return SYSCALL_RESULT(regs); | |
} | |
pid_t pid; | |
void onexit() { | |
kill(pid, SIGKILL); | |
kill(pid, SIGCONT); | |
} | |
int main() { | |
pid = try(fork()); | |
atexit(onexit); | |
if (pid == 0) { | |
raise(SIGSTOP); | |
return 1; | |
} | |
try(ptrace(PTRACE_SEIZE, pid, 0, 0)); | |
waitpid(pid, 0, 0); | |
pid_t p = tsyscall(pid, __NR_getpid); | |
printf("PID: %d %d\n", pid, p); | |
try(ptrace(PTRACE_DETACH, pid, 0, SIGCONT)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment