use chrono::{DateTime, Local}; use nix::{libc::user_regs_struct, unistd::Pid}; use owo_colors::OwoColorize; use ratatui::{ prelude::{Line, Span, Style}, style::{Color, Modifier}, }; #[cfg(all(target_arch = "x86_64", target_os = "linux"))] use crate::arch::linux::x86_64::*; #[cfg(not(all(target_arch = "x86_64", target_os = "linux")))] use crate::arch::syscall_name; use crate::trace::read_memory; #[derive(Clone, Debug)] /// Structure use to monitor what a register has for (argument: value) struct RegisterOutput { /// Value for a register, by default is a number which could be a real value or a memory /// address value: String, /// Argument for a register, eg: "const char *buf" argument: &'static str, } impl RegisterOutput { fn new(address: u64, argument: &'static str) -> Self { Self { value: address.to_string(), argument, } } } /// Struct used to manipulate registers data from https://docs.rs/libc/0.2.147/libc/struct.user_regs_struct.html #[derive(Debug)] pub struct RegistersData { timestamp: DateTime, orig_rax: u64, rdi: RegisterOutput, rsi: RegisterOutput, rdx: RegisterOutput, r10: RegisterOutput, r8: RegisterOutput, r9: RegisterOutput, rax: u64, } impl RegistersData { /// Create new `RegistersData` from an `user_regs_struct`'C structure pub fn new(registers: user_regs_struct) -> RegistersData { let (rdi, rsi, rdx, r10, r8, r9) = ( RegisterOutput::new(registers.rdi, rdi(registers.orig_rax)), RegisterOutput::new(registers.rsi, rsi(registers.orig_rax)), RegisterOutput::new(registers.rdx, rdx(registers.orig_rax)), RegisterOutput::new(registers.r10, r10(registers.orig_rax)), RegisterOutput::new(registers.r8, r8(registers.orig_rax)), RegisterOutput::new(registers.r9, r9(registers.orig_rax)), ); RegistersData { timestamp: Local::now(), orig_rax: registers.orig_rax, rax: registers.rax, rdi, rsi, rdx, r10, r8, r9, } } /// Get date in ISO 8601 / RFC 3339 date & time string format pub fn date(&self) -> String { self.timestamp.format("%+").to_string() } /// Return the rax name as syscall name pub fn name(&self) -> &str { syscall_name(self.orig_rax) } /// Returns a good string which shows the output for a line pub fn output(&mut self, pid: Pid) -> String { let mut output = format!("[{}]: ", self.date()); if !self.name().is_empty() { output.push_str(&format!("{}(", self.name().bold())); } else { output.push_str(&format!("{}(", self.orig_rax.yellow().bold())); } let mut has_reg = false; let mut regs = [ &mut self.rdi, &mut self.rsi, &mut self.rdx, &mut self.r10, &mut self.r8, &mut self.r9, ]; for reg in &mut regs { if !reg.argument.is_empty() { let output_reg = reg.argument.to_owned() + ":"; reg.value = if (output_reg.starts_with("const char *") || output_reg.starts_with("char *")) && !reg.value.starts_with("\"") { read_memory(pid, reg.value.parse::().unwrap()) } else { reg.value.to_string() }; output.push_str(&format!("{} {}, ", output_reg.blue(), reg.value)); has_reg = true; } } if has_reg { output.remove(output.len() - 1); output.remove(output.len() - 1); } output.push_str(&format!(") = 0x{:x}", self.rax)[..]); output } /// Returns a good line for TUI pub fn output_ui(&mut self, _pid: Pid) -> Line { let mut spans: Vec = vec![]; spans.push(Span::raw(format!("[{}]: ", self.date()))); if !self.name().is_empty() { spans.push(Span::styled( format!("{}(", self.name()), Style::default().add_modifier(Modifier::BOLD), )); } else { spans.push(Span::styled( format!("{}(", self.orig_rax), Style::default() .fg(Color::Yellow) .add_modifier(Modifier::BOLD), )); } let mut regs = [ &mut self.rdi, &mut self.rsi, &mut self.rdx, &mut self.r10, &mut self.r8, &mut self.r9, ]; for reg in &mut regs { if !reg.argument.is_empty() { let output_reg = reg.argument.to_owned() + ":"; spans.push(Span::styled( format!("{} ", output_reg), Style::default().fg(Color::Blue), )); // FIXME: read memory does not work // reg.value = if (output_reg.starts_with("const char *") // || output_reg.starts_with("char *")) // && !reg.value.starts_with("\"") // { // read_memory(pid, reg.value.parse::().unwrap()) // } else { // reg.value.to_string() // }; spans.push(Span::styled(format!("{}, ", reg.value), Style::default())); } } spans.push(Span::styled( format!(") = 0x{:x}", self.rax), Style::default(), )); Line::from(spans) } }