Skip to content

Instantly share code, notes, and snippets.

@llandsmeer
Created March 9, 2020 19:51
Show Gist options
  • Save llandsmeer/81ad107189ae5a8b6581c3c45a36a684 to your computer and use it in GitHub Desktop.
Save llandsmeer/81ad107189ae5a8b6581c3c45a36a684 to your computer and use it in GitHub Desktop.
Execute syscall in other process
#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, &regs_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, &regs));
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, &regs));
try(ptrace(PTRACE_POKETEXT, pid, ip, asm_orig));
try(ptrace(PTRACE_SETREGS, pid, 0, &regs_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