Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Hauyne.Injector/linux/arch/aarch64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub const UserRegsStruct = extern struct {
};

pub const SYS_mmap: u64 = 222;
pub const SYS_mprotect: u64 = 226;
pub const syscall_insn_size: u64 = 0;

pub const idle_syscalls = [_]i64{
Expand Down Expand Up @@ -50,6 +51,13 @@ pub fn setupMmapRegs(regs: *UserRegsStruct, scratch_size: u64, prot: u64, flags:
regs.regs[5] = 0;
}

pub fn setupMprotectRegs(regs: *UserRegsStruct, addr: u64, len: u64, prot: u64) void {
regs.regs[8] = SYS_mprotect;
regs.regs[0] = addr;
regs.regs[1] = len;
regs.regs[2] = prot;
}

pub fn setupShimRegs(regs: *UserRegsStruct, shim_addr: usize) void {
regs.pc = shim_addr;
}
Expand Down
10 changes: 10 additions & 0 deletions Hauyne.Injector/linux/arch/x86_64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub const UserRegsStruct = extern struct {
};

pub const SYS_mmap: u64 = 9;
pub const SYS_mprotect: u64 = 10;
pub const syscall_insn_size: u64 = 2;

pub const idle_syscalls = [_]i64{
Expand Down Expand Up @@ -75,6 +76,15 @@ pub fn setupMmapRegs(regs: *UserRegsStruct, scratch_size: u64, prot: u64, flags:
regs.orig_rax = @bitCast(@as(i64, -1));
}

pub fn setupMprotectRegs(regs: *UserRegsStruct, addr: u64, len: u64, prot: u64) void {
regs.rip -= 2;
regs.rax = SYS_mprotect;
regs.rdi = addr;
regs.rsi = len;
regs.rdx = prot;
regs.orig_rax = @bitCast(@as(i64, -1));
}

pub fn setupShimRegs(regs: *UserRegsStruct, shim_addr: usize) void {
regs.rip = shim_addr;
regs.orig_rax = @bitCast(@as(i64, -1));
Expand Down
18 changes: 17 additions & 1 deletion Hauyne.Injector/linux/linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ pub fn inject(
var page = shim.buildScratchPage(so_path, payload_path, type_name, method_name, dlopen_addr, dlsym_addr, pthread_create_addr, pthread_detach_addr, scratch, self_pid);
try ptrace_mod.writeMemory(victim, scratch, &page);

try bootstrapMprotect(victim, saved, scratch + shim.CodePageOff, shim.ScratchSize - shim.CodePageOff, PROT_READ | PROT_EXEC);

try runVictimShim(victim, saved, scratch + shim.VictimShimOff);

try ptrace_mod.setRegs(victim, saved);
Expand All @@ -161,7 +163,7 @@ pub fn inject(

fn bootstrapMmap(pid: i32, saved: UserRegsStruct) !usize {
var regs = saved;
arch.setupMmapRegs(&regs, shim.ScratchSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS);
arch.setupMmapRegs(&regs, shim.ScratchSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS);

try ptrace_mod.setRegs(pid, regs);
try continueAndWait(pid, ptrace_mod.PTRACE_SYSCALL, "mmap-enter");
Expand All @@ -175,6 +177,20 @@ fn bootstrapMmap(pid: i32, saved: UserRegsStruct) !usize {
return @intCast(ret);
}

fn bootstrapMprotect(pid: i32, saved: UserRegsStruct, addr: usize, len: usize, prot: u64) !void {
var regs = saved;
arch.setupMprotectRegs(&regs, @intCast(addr), @intCast(len), prot);

try ptrace_mod.setRegs(pid, regs);
try continueAndWait(pid, ptrace_mod.PTRACE_SYSCALL, "mprotect-enter");
try continueAndWait(pid, ptrace_mod.PTRACE_SYSCALL, "mprotect-exit");

const after = try ptrace_mod.getRegs(pid);
const ret: i64 = @bitCast(arch.getSyscallResult(after));
if (ret < 0 and ret > -4096)
return error.MprotectInTargetFailed;
}

fn runVictimShim(pid: i32, saved: UserRegsStruct, shim_addr: usize) !void {
var regs = saved;
arch.setupShimRegs(&regs, shim_addr);
Expand Down
17 changes: 11 additions & 6 deletions Hauyne.Injector/linux/shim.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@

const std = @import("std");

pub const ScratchSize: usize = 0x2000; // 8 KiB (two pages)
pub const PathOffset: usize = 0x40; // bootstrap .so path (1984)
pub const PayloadOffset: usize = 0x800; // payload triple, NUL-separated (4096)
pub const SymbolOffset: usize = 0x1800; // "hauyne_start\0" (256)
pub const VictimShimOff: usize = 0x1900; // pthread_create + pthread_detach (256)
pub const PayloadShimOff: usize = 0x1A00; // dlopen + dlsym + hauyne_start (1536)
pub const ScratchSize: usize = 0x2000; // 8 KiB (two 4K pages)

// P1 RW: data region, pthread_handle
pub const PathOffset: usize = 0x40; // bootstrap .so path (1984)
pub const PayloadOffset: usize = 0x800; // payload triple, NUL-separated (2048)

// P2 RX: read-only data + executable shims
pub const CodePageOff: usize = 0x1000; // page boundary for mprotect
pub const SymbolOffset: usize = 0x1800; // "hauyne_start\0" (256)
pub const VictimShimOff: usize = 0x1900; // pthread_create + pthread_detach (256)
pub const PayloadShimOff: usize = 0x1A00; // dlopen + dlsym + hauyne_start (1536)

const arch = @import("arch.zig").emitter;

Expand Down
Loading