Horrors Beyond Human Comprehension
This commit is contained in:
commit
a6af6f76a4
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/build*
|
||||||
|
/CMakeLists.txt.user
|
||||||
|
/cmake-build-*
|
||||||
|
/.idea
|
13
CMakeLists.txt
Normal file
13
CMakeLists.txt
Normal file
@ -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)
|
10
src/log.h
Normal file
10
src/log.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#define ERR(format, ...) \
|
||||||
|
{ \
|
||||||
|
fprintf(stderr, "TRAMPOLINE ERROR: " format "\n", ##__VA_ARGS__); \
|
||||||
|
exit(EXIT_FAILURE); \
|
||||||
|
}
|
38
src/main.cpp
Normal file
38
src/main.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
38
src/memory.cpp
Normal file
38
src/memory.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#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");
|
||||||
|
}
|
||||||
|
}
|
8
src/memory.h
Normal file
8
src/memory.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
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);
|
113
src/ptrace.cpp
Normal file
113
src/ptrace.cpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#include <sys/ptrace.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <elf.h>
|
||||||
|
|
||||||
|
#ifndef __aarch64__
|
||||||
|
#error "Unsupported Host Architecture"
|
||||||
|
#endif
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
src/ptrace.h
Normal file
5
src/ptrace.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
void loop_ptrace(pid_t guest_pid);
|
24
src/trampoline.cpp
Normal file
24
src/trampoline.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#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());
|
||||||
|
}
|
||||||
|
}
|
7
src/trampoline.h
Normal file
7
src/trampoline.h
Normal file
@ -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();
|
Loading…
Reference in New Issue
Block a user