diff options
author | Santo Cariotti <santo@dcariotti.me> | 2023-10-20 22:40:26 +0200 |
---|---|---|
committer | Santo Cariotti <santo@dcariotti.me> | 2023-10-20 22:40:26 +0200 |
commit | 10f48592388c78f93487ea96bcc9ad40c4864584 (patch) | |
tree | bfff7a3980baa242c86f478fee11679a37142878 | |
parent | 2fa8e3c69079f9fa4ebbf0adba7ac319a55fa8fe (diff) |
Show buffer value
-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 { |