diff options
| -rw-r--r-- | Cargo.lock | 7 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/registers.rs | 40 | ||||
| -rw-r--r-- | src/trace.rs | 56 | ||||
| -rw-r--r-- | src/ui.rs | 4 | 
5 files changed, 92 insertions, 16 deletions
| @@ -96,6 +96,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"  [[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]]  name = "cassowary"  version = "0.3.0"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -431,6 +437,7 @@ name = "sigma"  version = "0.0.1"  dependencies = [   "anyhow", + "byteorder",   "chrono",   "clap",   "crossterm", @@ -8,6 +8,7 @@ authors = ["Santo Cariotti <santo@dcariotti.me>"]  [dependencies]  anyhow = "1.0.75" +byteorder = "1.5.0"  chrono = "0.4.31"  clap = { version = "4.4.6", features = ["derive"] }  crossterm = "0.27.0" diff --git a/src/registers.rs b/src/registers.rs index c42bb12..44d7271 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -1,5 +1,5 @@  use chrono::{DateTime, Local}; -use nix::libc::user_regs_struct; +use nix::{libc::user_regs_struct, unistd::Pid};  use owo_colors::OwoColorize;  use ratatui::{      prelude::{Line, Span, Style}, @@ -10,9 +10,10 @@ use ratatui::{  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;  /// Struct used to manipulate registers data from https://docs.rs/libc/0.2.147/libc/struct.user_regs_struct.html -#[derive(Debug)] +#[derive(Debug, Clone, Copy)]  pub struct RegistersData {      timestamp: DateTime<Local>,      orig_rax: u64, @@ -52,10 +53,10 @@ impl RegistersData {      }      /// Returns a good string which shows the output for a line -    pub fn output(&self) -> String { +    pub fn output(&self, pid: Pid) -> String {          let mut output = format!("[{}]: ", self.date()); -        if self.name().len() > 0 { +        if !self.name().is_empty() {              output.push_str(&format!("{}(", self.name().bold()));          } else {              output.push_str(&format!("{}(", self.orig_rax.yellow().bold())); @@ -73,9 +74,16 @@ impl RegistersData {          ];          for param in params { -            if param.1.len() != 0 { +            if !param.1.is_empty() {                  let output_param = param.1.to_owned() + ":"; -                output.push_str(&format!("{} {}, ", output_param.blue(), param.0)); +                let output_value = if output_param.starts_with("const char *") +                    || output_param.starts_with("char *") +                { +                    read_memory(pid, param.0) +                } else { +                    param.0.to_string() +                }; +                output.push_str(&format!("{} {}, ", output_param.blue(), output_value));                  has_param = true;              }          } @@ -90,10 +98,10 @@ impl RegistersData {      }      /// Returns a good line for TUI -    pub fn output_ui(&self) -> Line { +    pub fn output_ui(&self, pid: Pid) -> Line {          let mut spans: Vec<Span> = vec![];          spans.push(Span::raw(format!("[{}]: ", self.date()))); -        if self.name().len() > 0 { +        if !self.name().is_empty() {              spans.push(Span::styled(                  format!("{}(", self.name()),                  Style::default().add_modifier(Modifier::BOLD), @@ -117,13 +125,25 @@ impl RegistersData {          ];          for param in params { -            if param.1.len() != 0 { +            if !param.1.is_empty() {                  let output_param = param.1.to_owned() + ":";                  spans.push(Span::styled(                      format!("{} ", output_param),                      Style::default().fg(Color::Blue),                  )); -                spans.push(Span::styled(format!("{}, ", param.0), Style::default())); + +                // FIXME: read memory does not work +                let output_value = if output_param.starts_with("const char *") +                    || output_param.starts_with("char *") +                { +                    read_memory(pid, param.0) +                } else { +                    param.0.to_string() +                }; +                spans.push(Span::styled( +                    format!("{}, ", output_value), +                    Style::default(), +                ));              }          } diff --git a/src/trace.rs b/src/trace.rs index 157f2e7..e424d09 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -1,5 +1,6 @@  use crate::cli::Args;  use crate::registers::RegistersData; +use byteorder::{LittleEndian, WriteBytesExt};  use nix::{      sys::{          ptrace, @@ -11,7 +12,7 @@ use nix::{  use std::{      fs::File,      io::{self, Write}, -    os::unix::process::CommandExt, +    os::{raw::c_void, unix::process::CommandExt},      process::{Command, Stdio},      str,  }; @@ -60,7 +61,7 @@ pub fn trace(pid: Pid, args: &Args) -> anyhow::Result<Vec<RegistersData>> {      let mut have_to_print = true;      let filters: Vec<&str> = match &args.filter { -        Some(filter) => filter.split(",").collect::<Vec<&str>>(), +        Some(filter) => filter.split(',').collect::<Vec<&str>>(),          None => vec![],      };      while let Some(reg) = trace_next(pid)? { @@ -71,11 +72,11 @@ pub fn trace(pid: Pid, args: &Args) -> anyhow::Result<Vec<RegistersData>> {              }              if let Some(ref mut f) = f { -                writeln!(f, "{}", reg.output())?; +                writeln!(f, "{}", reg.output(pid))?;              }              if args.no_tui { -                writeln!(io::stdout(), "{}", reg.output())?; +                writeln!(io::stdout(), "{}", reg.output(pid))?;              }              lines.push(reg); @@ -84,6 +85,53 @@ pub fn trace(pid: Pid, args: &Args) -> anyhow::Result<Vec<RegistersData>> {      Ok(lines)  } +/// Read memory and returns a string. +/// Thank you https://github.com/JakWai01/lurk/blob/e3a3d6c026bbf818fe1329f8d458be544c3c5ebc/src/arch/mod.rs#L66 +pub fn read_memory(pid: Pid, address: u64) -> String { +    let mut string = String::new(); + +    let mut count = 0; +    let word_size = 8; + +    loop { +        let address = unsafe { (address as *mut c_void).offset(count) }; + +        match ptrace::read(pid, address) { +            Ok(read) => { +                let mut bytes: Vec<u8> = vec![]; +                bytes.write_i64::<LittleEndian>(read).unwrap_or_else(|err| { +                    panic!("Failed to write {read} as i64 LittleEndian: {err}"); +                }); + +                if !bytes +                    .iter() +                    .filter(|&b| *b == 0x0) +                    .collect::<Vec<&u8>>() +                    .is_empty() +                { +                    break; +                } + +                bytes.iter().for_each(|b| { +                    string.push(*b as char); +                }); + +                count += word_size; +            } +            Err(_) => break, +        }; +    } + +    if string.len() > 24 { +        string = string[..24].to_string(); +        string.push_str("..."); +    } + +    string = string.replace('\n', "\\n"); + +    format!("\"{string}\"") +} +  /// Get the next step for a ptrace process  pub fn trace_next(pid: Pid) -> anyhow::Result<Option<RegistersData>> {      ptrace::syscall(pid, None)?; @@ -35,7 +35,7 @@ impl UI {      }      pub fn get_paragraph(&self, pid: Pid) -> Paragraph { -        let lines: Vec<Line> = self.lines.iter().map(|x| x.output_ui()).collect(); +        let lines: Vec<Line> = self.lines.iter().map(|x| x.output_ui(pid)).collect();          let paragraph = Paragraph::new(lines)              .block(                  Block::default() @@ -77,7 +77,7 @@ impl UI {          }          let filters: Vec<&str> = match &args.filter { -            Some(filter) => filter.split(",").collect::<Vec<&str>>(), +            Some(filter) => filter.split(',').collect::<Vec<&str>>(),              None => vec![],          };          while !should_quit { | 
