commit a6af6f76a4805ca6d477c6735753278eb832191c Author: TheBrokenRail Date: Tue Jun 4 17:22:15 2024 -0400 Horrors Beyond Human Comprehension diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dcecd37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/build* +/CMakeLists.txt.user +/cmake-build-* +/.idea diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a41f182 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.17.0) + +# Start Project +project(native-trampoline) + +# Build +add_executable(qemu-arm src/memory.cpp src/main.cpp src/trampoline.cpp src/ptrace.cpp) + +# Warnings +target_compile_options(qemu-arm PRIVATE -Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference) + +# Link +target_link_libraries(qemu-arm dl) \ No newline at end of file diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..bbc5763 --- /dev/null +++ b/src/log.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +#define ERR(format, ...) \ + { \ + fprintf(stderr, "TRAMPOLINE ERROR: " format "\n", ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ee7196e --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +#include "log.h" +#include "memory.h" +#include "trampoline.h" +#include "ptrace.h" + +// Main +int main(__attribute__((unused)) int argc, char *argv[]) { + // Fork + pid_t pid = fork(); + if (pid == -1) { + ERR("Unable To Fork Process: %s", strerror(errno)); + } else if (pid == 0) { + // Child + ptrace(PTRACE_TRACEME, 0, 0, 0); + execvp(argv[1], (char *const *) &argv[1]); + ERR("Unable To Execute Program: %s: %s", argv[1], strerror(errno)); + } else { + // Parent + + // Wait For PTrace + waitpid(pid, nullptr, 0); + // Configure PTrace + ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD); + + // Setup Trampoline + init_memory(pid); + init_trampoline(); + + // Start PTrace Loop + loop_ptrace(pid); + } +} \ No newline at end of file diff --git a/src/memory.cpp b/src/memory.cpp new file mode 100644 index 0000000..cf3e692 --- /dev/null +++ b/src/memory.cpp @@ -0,0 +1,38 @@ +#include + +#include "memory.h" +#include "log.h" + +// Store PID +static pid_t guest_pid; +void init_memory(pid_t pid) { + guest_pid = pid; +} + +// Read Memory +void memory_reader(uint32_t guest_addr, void *data, uint32_t size) { + iovec local[1]; + local[0].iov_base = data; + local[0].iov_len = size; + iovec remote[1]; + remote[0].iov_base = (void *) (uint64_t) guest_addr; + remote[0].iov_len = size; + ssize_t ret = process_vm_readv(guest_pid, local, 1, remote, 1, 0); + if (ret != size) { + ERR("Unable To Read Data"); + } +} + +// Write Memory +void memory_writer(uint32_t guest_addr, void *data, uint32_t size) { + iovec local[1]; + local[0].iov_base = data; + local[0].iov_len = size; + iovec remote[1]; + remote[0].iov_base = (void *) (uint64_t) guest_addr; + remote[0].iov_len = size; + ssize_t ret = process_vm_writev(guest_pid, local, 1, remote, 1, 0); + if (ret != size) { + ERR("Unable To Write Data"); + } +} \ No newline at end of file diff --git a/src/memory.h b/src/memory.h new file mode 100644 index 0000000..06aa54b --- /dev/null +++ b/src/memory.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +void memory_reader(uint32_t guest_addr, void *data, uint32_t size); +void memory_writer(uint32_t guest_addr, void *data, uint32_t size); +void init_memory(pid_t guest_pid); \ No newline at end of file diff --git a/src/ptrace.cpp b/src/ptrace.cpp new file mode 100644 index 0000000..d87d2f0 --- /dev/null +++ b/src/ptrace.cpp @@ -0,0 +1,113 @@ +#include +#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 +static 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)); + } +} +static void safe_wait(pid_t guest_pid, int *status) { + if (waitpid(guest_pid, status, 0) == -1) { + ERR("Unable To Wait For Guest"); + } + if (WIFEXITED(*status)) { + // Process Exited + exit(WEXITSTATUS(*status)); + } +} +static void ptrace_wait_syscall(pid_t guest_pid) { + while (true) { + safe_ptrace(PTRACE_SYSCALL, guest_pid, nullptr, nullptr); + int status; + safe_wait(guest_pid, &status); + if (WIFSTOPPED(status) && (WSTOPSIG(status) & 0x80)) { + 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, nullptr, ®s); + if (io.iov_len != sizeof(regs)) { + ERR("Guest Must Be 32-Bit"); + } + // Check Syscall + if (regs.regs[7] != TRAMPOLINE_SYSCALL) { + // Not Trampoline + return false; + } + // 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[1]; + *arg2 = regs->regs[2]; + *arg3 = regs->regs[3]; +} +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 Entrance + 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)); + } + + // Handle Syscall Exit + ptrace_wait_syscall(guest_pid); + + // Set Syscall Return + if (is_trampoline) { + set_syscall_return(guest_pid, ®s); + } + } +} \ No newline at end of file diff --git a/src/ptrace.h b/src/ptrace.h new file mode 100644 index 0000000..d11bfb1 --- /dev/null +++ b/src/ptrace.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void loop_ptrace(pid_t guest_pid); \ No newline at end of file diff --git a/src/trampoline.cpp b/src/trampoline.cpp new file mode 100644 index 0000000..353c154 --- /dev/null +++ b/src/trampoline.cpp @@ -0,0 +1,24 @@ +#include + +#include "trampoline.h" +#include "memory.h" +#include "log.h" + +// Run Trampoline +typedef uint32_t (*trampoline_t)(typeof(memory_writer) *writer, uint32_t id, const unsigned char *args); +static trampoline_t func = nullptr; +uint32_t trampoline(uint32_t id, const unsigned char *args) { + return func(memory_writer, id, args); +} + +// Init +void init_trampoline() { + // Open Library + void *handle = dlopen("libmedia-layer-trampoline.so", RTLD_NOW); + if (handle != nullptr) { + func = (trampoline_t) dlsym(handle, "trampoline"); + } + if (func == nullptr) { + ERR("Unable To Load Media Layer Trampoline: %s", dlerror()); + } +} \ No newline at end of file diff --git a/src/trampoline.h b/src/trampoline.h new file mode 100644 index 0000000..c8d66b3 --- /dev/null +++ b/src/trampoline.h @@ -0,0 +1,7 @@ +#pragma once + +#include "../../minecraft-pi-reborn/media-layer/trampoline/src/common/types.h" + +#define MAX_TRAMPOLINE_ARGS_SIZE 2097152 // See media-layer/trampoline/src/guest/guest.h +uint32_t trampoline(uint32_t id, const unsigned char *args); +void init_trampoline(); \ No newline at end of file