#include #include #include #include #include #ifndef __aarch64__ #error "Unsupported Host Architecture" #endif #include #include "ptrace.h" #include "../log.h" #include "../trampoline.h" #include "../memory.h" // Helper Functions void safe_ptrace(__ptrace_request request, pid_t pid, void *addr, void *data) { if (ptrace(request, pid, addr, data) == -1) { ERR("PTrace Error: %s", strerror(errno)); } } void safe_wait(pid_t guest_pid, int *status) { int real_status; if (waitpid(guest_pid, &real_status, 0) == -1) { ERR("Unable To Wait For Guest"); } if (WIFEXITED(real_status)) { // Process Exited exit(WEXITSTATUS(real_status)); } if (status != nullptr) { *status = real_status; } } static void ptrace_wait_syscall(pid_t guest_pid) { while (true) { safe_ptrace(PTRACE_CONT, guest_pid, nullptr, nullptr); int status; safe_wait(guest_pid, &status); if ((status >> 8) == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) { return; } } } // Registers struct arm32_pt_regs { uint32_t regs[18]; }; static bool check_syscall(pid_t guest_pid, arm32_pt_regs *out) { // Read Registers arm32_pt_regs regs = {}; iovec io = { .iov_base = ®s, .iov_len = sizeof(regs) }; safe_ptrace(PTRACE_GETREGSET, guest_pid, (void *) NT_PRSTATUS, &io); if (io.iov_len != sizeof(regs)) { ERR("Guest Must Be 32-Bit"); } // Check Syscall if (regs.regs[7] != TRAMPOLINE_SYSCALL) { // Not Trampoline return false; } // Block Syscall int new_syscall = -1; iovec syscall_io = { .iov_base = &new_syscall, .iov_len = sizeof(int), }; safe_ptrace(PTRACE_SETREGSET, guest_pid, (void *) NT_ARM_SYSTEM_CALL, &syscall_io); // Export Registers *out = regs; // Return return true; } static void get_arguments(arm32_pt_regs *regs, uint32_t *arg1, uint32_t *arg2, uint32_t *arg3) { *arg1 = regs->regs[0]; *arg2 = regs->regs[1]; *arg3 = regs->regs[2]; } static void set_syscall_return(pid_t guest_pid, arm32_pt_regs *regs) { regs->regs[0] = 0; iovec io = { .iov_base = regs, .iov_len = sizeof(arm32_pt_regs) }; safe_ptrace(PTRACE_SETREGSET, guest_pid, (void *) NT_PRSTATUS, &io); } // Main Loop void loop_ptrace(pid_t guest_pid) { while (true) { // Wait For Syscall ptrace_wait_syscall(guest_pid); // Handle Syscall arm32_pt_regs regs = {}; bool is_trampoline = check_syscall(guest_pid, ®s); if (is_trampoline) { // Get Arguments uint32_t id; uint32_t length; uint32_t args_addr; get_arguments(®s, &id, &length, &args_addr); static unsigned char args[MAX_TRAMPOLINE_ARGS_SIZE]; memory_reader(args_addr, args, length); // Run Trampoline uint32_t ret = trampoline(id, args); memory_writer(args_addr, &ret, sizeof(uint32_t)); // Set Syscall Return set_syscall_return(guest_pid, ®s); } } }