1use crate::syscall_info::{SyscallArg, SyscallArgs};
2use byteorder::{LittleEndian, WriteBytesExt};
3use libc::{c_long, c_ulonglong, user_regs_struct};
4use nix::sys::ptrace;
5use nix::sys::ptrace::Options;
6use nix::unistd::Pid;
7use std::ffi::c_void;
8use syscalls::Sysno;
9
10#[cfg(any(target_arch = "aarch64", feature = "aarch64"))]
11pub mod aarch64;
12#[cfg(any(target_arch = "riscv64", feature = "riscv64"))]
23pub mod riscv64;
24#[cfg(any(target_arch = "x86_64", feature = "x86_64"))]
33pub mod x86_64;
34
35#[cfg(target_arch = "aarch64")]
36pub use aarch64::*;
37#[cfg(target_arch = "riscv64")]
48pub use riscv64::*;
49#[cfg(target_arch = "x86_64")]
58pub use x86_64::*;
59
60#[derive(Debug, Copy, Clone)]
61pub enum SyscallArgType {
62 Int,
64 Str,
66 StrArray,
68 Addr,
70}
71
72pub fn read_string(pid: Pid, address: c_ulonglong) -> String {
73 let mut string = String::new();
74 let mut count = 0;
76 let word_size = 8;
77
78 'done: loop {
79 let address = unsafe { (address as *mut c_void).offset(count) };
80
81 let res: c_long = match ptrace::read(pid, address) {
82 Ok(c_long) => c_long,
83 Err(_) => {
84 return format!("{:#x}", address as usize);
87 }
88 };
89
90 let mut bytes: Vec<u8> = vec![];
91 bytes.write_i64::<LittleEndian>(res).unwrap_or_else(|err| {
92 panic!("Failed to write {res} as i64 LittleEndian: {err}");
93 });
94 for b in bytes {
95 if b == 0 {
96 break 'done;
97 }
98 string.push(b as char);
99 }
100
101 count += word_size;
102 }
103
104 string
105}
106
107pub fn ptrace_init_options(pid: Pid) -> nix::Result<()> {
108 ptrace::setoptions(
109 pid,
110 Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT | Options::PTRACE_O_TRACEEXEC,
111 )
112}
113
114pub fn ptrace_init_options_fork(pid: Pid) -> nix::Result<()> {
115 ptrace::setoptions(
116 pid,
117 Options::PTRACE_O_TRACESYSGOOD
118 | Options::PTRACE_O_TRACEEXIT
119 | Options::PTRACE_O_TRACEEXEC
120 | Options::PTRACE_O_TRACEFORK
121 | Options::PTRACE_O_TRACEVFORK
122 | Options::PTRACE_O_TRACECLONE,
123 )
124}
125
126#[allow(clippy::cast_sign_loss)]
127#[must_use]
128pub fn parse_args(pid: Pid, syscall: Sysno, registers: user_regs_struct) -> SyscallArgs {
130 SYSCALLS
131 .get(syscall.id() as usize)
132 .and_then(|option| option.as_ref())
133 .map_or_else(
134 || SyscallArgs(vec![]),
135 |(_, args)| {
136 SyscallArgs(
137 args.iter()
138 .filter_map(Option::as_ref)
139 .enumerate()
140 .map(|(idx, arg_type)| map_arg(pid, registers, idx, *arg_type))
141 .collect(),
142 )
143 },
144 )
145}
146
147fn map_arg(pid: Pid, registers: user_regs_struct, idx: usize, arg: SyscallArgType) -> SyscallArg {
148 let value = get_arg_value(registers, idx);
149 match arg {
150 SyscallArgType::Int => SyscallArg::Int(value as i64),
151 SyscallArgType::Str => SyscallArg::Str(read_string(pid, value)),
152 SyscallArgType::StrArray => {
153 SyscallArg::StrVec(read_string_array(pid, value), Some(value as usize))
154 }
155 SyscallArgType::Addr => SyscallArg::Addr(value as usize),
156 }
157}
158
159pub fn read_string_array(pid: Pid, address: c_ulonglong) -> Vec<String> {
160 let mut vec = Vec::new();
161 if address == 0 {
162 return vec;
163 }
164
165 let mut offset = 0isize;
167 for _ in 0..1024 {
169 let ptr_addr = unsafe { (address as *mut c_void).offset(offset) };
170 let res: c_long = match ptrace::read(pid, ptr_addr) {
171 Ok(v) => v,
172 Err(_) => break,
173 };
174 let mut bytes: Vec<u8> = vec![];
175
176 bytes.write_i64::<LittleEndian>(res).ok();
177 let mut ptr_value: c_ulonglong = 0;
178 for (i, b) in bytes.iter().enumerate() {
179 ptr_value |= c_ulonglong::from(*b) << (i * 8);
180 }
181 if ptr_value == 0 {
182 break;
183 }
184 vec.push(read_string(pid, ptr_value));
185 offset += std::mem::size_of::<c_ulonglong>() as isize;
186 }
187
188 vec
189}
190
191pub fn read_string_array_count(pid: Pid, address: c_ulonglong) -> usize {
195 if address == 0 {
196 return 0;
197 }
198
199 let mut count = 0usize;
200 let mut offset = 0isize;
201 for _ in 0..1024 {
202 let ptr_addr = unsafe { (address as *mut c_void).offset(offset) };
203 let res: c_long = match ptrace::read(pid, ptr_addr) {
204 Ok(v) => v,
205 Err(_) => break,
206 };
207 let mut bytes: Vec<u8> = vec![];
209 bytes.write_i64::<LittleEndian>(res).ok();
210 let mut ptr_value: c_ulonglong = 0;
211 for (i, b) in bytes.iter().enumerate() {
212 ptr_value |= c_ulonglong::from(*b) << (i * 8);
213 }
214 if ptr_value == 0 {
215 break;
216 }
217 count += 1;
218 offset += std::mem::size_of::<c_ulonglong>() as isize;
219 }
220
221 count
222}
223
224pub fn escape_to_string(buf: &Vec<u8>) -> String {
225 let mut string = String::new();
226 for c in buf {
227 let code = *c;
228 if (0x20..=0x7f).contains(&code) {
229 if code == b'\\' {
230 string.push_str("\\\\");
231 } else {
232 string.push(char::from(code));
233 }
234 } else {
235 string.push_str(format!("\\{c:x}").as_str());
236 }
237 }
238 string
239}