1use nix::{libc::user_regs_struct, Result, sys::{ptrace, wait::waitpid}, unistd::Pid};
2use tracing::debug;
3
4use crate::rc::{injector::RemoteOperation, senders::RemoteString};
5
6pub trait RemoteSyscall {
7 fn registers(&self, regs: &mut user_regs_struct);
8
9 fn prepare_registers(regs: &mut user_regs_struct, rax: u64, rdi: u64, rsi: u64, rdx: u64, r10: u64, r8: u64, r9: u64) {
10 regs.rax = rax;
11 regs.rdi = rdi;
12 regs.rsi = rsi;
13 regs.rdx = rdx;
14 regs.r10 = r10;
15 regs.r8 = r8;
16 regs.r9 = r9;
17 }
18}
19
20impl<T> RemoteOperation for T where T: RemoteSyscall {
21 fn inject(&mut self, pid: Pid, syscall: usize) -> Result<u64> {
22 let mut regs = ptrace::getregs(pid)?;
23 regs.rip = syscall as u64;
24 self.registers(&mut regs);
25 let syscall_nr = regs.rax;
26 ptrace::setregs(pid, regs)?;
27 ptrace::step(pid, None)?;
28 waitpid(pid, None)?;
29 regs = ptrace::getregs(pid)?;
30 debug!(target: "remote-syscall", "executed syscall #{} -> {}", syscall_nr, regs.rax);
31 Ok(regs.rax)
32 }
33
34 fn revert(&mut self, _pid: Pid, _syscall: usize) -> Result<u64> { Ok(0) }
35}
36
37pub struct RemoteMMap {
38 addr: u64,
39 len: usize,
40 prot: i32,
41 flags: i32,
42 fd: i64,
43 off: u64,
44}
45
46
47
48impl RemoteMMap {
49 pub fn args(addr: u64, len: usize, prot: i32, flags: i32, fd: i64, off: u64) -> Self {
50 RemoteMMap { addr, len, prot, flags, fd, off }
51 }
52}
53
54impl RemoteSyscall for RemoteMMap {
55 fn registers(&self, regs: &mut user_regs_struct) {
56 Self::prepare_registers(regs, 9, self.addr, self.len as u64, self.prot as u64, self.flags as u64, self.fd as u64, self.off);
57 }
58}
59
60pub struct RemoteMUnmap {
61 addr: usize,
62 len: usize,
63}
64
65impl RemoteMUnmap {
66 pub fn args(addr: usize, len: usize) -> Self {
67 RemoteMUnmap { addr, len }
68 }
69}
70
71impl RemoteSyscall for RemoteMUnmap {
72 fn registers(&self, regs: &mut user_regs_struct) {
73 regs.rax = 11;
74 regs.rdi = self.addr as u64;
75 regs.rsi = self.len as u64;
76 }
77}
78
79pub struct RemoteOpen {
80 filename: RemoteString,
81 flags: u64,
82 mode: u64,
83}
84
85#[allow(unused)]
86impl RemoteOpen {
87 pub fn args(filename: RemoteString, flags: u64, mode: u64) -> Self {
88 RemoteOpen { filename, flags, mode }
89 }
90}
91
92impl RemoteSyscall for RemoteOpen {
93 fn registers(&self, regs: &mut user_regs_struct) { regs.rax = 2;
95 regs.rdi = self.filename.ptr.unwrap() as u64;
96 regs.rsi = self.flags;
97 regs.rdx = self.mode;
98 }
99}
100
101pub struct RemoteWrite {
102 fd: i64,
103 ptr: u64,
104 len: u64,
105}
106
107#[allow(unused)]
108impl RemoteWrite {
109 pub fn args(fd: i64, ptr: u64, len: u64) -> Self {
110 RemoteWrite { fd, ptr, len }
111 }
112
113 pub fn string(fd: i64, txt: RemoteString) -> Self {
114 RemoteWrite { fd, ptr: txt.ptr.expect("remote write with uninjected remote str") as u64, len: txt.txt.len() as u64 }
115 }
116}
117
118impl RemoteSyscall for RemoteWrite {
119 fn registers(&self, regs: &mut user_regs_struct) {
120 regs.rax = 1;
121 regs.rdi = self.fd as u64;
122 regs.rsi = self.ptr;
123 regs.rdx = self.len;
124 }
125}
126
127pub struct RemoteExit {
128 code: i64,
129}
130
131#[allow(unused)]
132impl RemoteExit {
133 pub fn args(code: i64) -> Self {
134 RemoteExit { code }
135 }
136
137 pub fn exit(&mut self, pid: Pid, syscall: usize) -> Result<u64> {
140 let mut regs = ptrace::getregs(pid)?;
141 regs.rip = syscall as u64;
142 self.registers(&mut regs);
143 ptrace::setregs(pid, regs)?;
144 ptrace::step(pid, None)?;
145 Ok(self.code as u64)
146 }
147}
148
149impl RemoteSyscall for RemoteExit {
150 fn registers(&self, regs: &mut user_regs_struct) {
151 regs.rax = 60;
152 regs.rdi = self.code as u64;
153 }
154}