scanmem alternative with concurrent memory scanning
at master 3.7 kB view raw
1use anyhow::Result; 2use rustyline::Editor; 3use rustyline::error::ReadlineError; 4 5use crate::process::Process; 6use crate::scanner::{MemoryScanner, ScanValueType}; 7 8pub fn run_interactive_mode(process_name: &str) -> Result<()> { 9 println!( 10 "# Scanning for process \"{}\" like how pgrep -f works", 11 process_name 12 ); 13 14 let process = Process::find_by_name(process_name)?; 15 let mut scanner = MemoryScanner::new(process)?; 16 17 println!("Please enter current value, or \"help\" for other commands."); 18 19 let mut rl = Editor::<(), rustyline::history::DefaultHistory>::new()?; 20 let mut first_scan = true; 21 22 loop { 23 let prompt = if first_scan { 24 "> ".to_string() 25 } else { 26 format!("{}> ", scanner.get_matches_count()) 27 }; 28 29 let readline = rl.readline(&prompt); 30 match readline { 31 Ok(line) => { 32 let _ = rl.add_history_entry(&line); 33 let line = line.trim(); 34 35 if line.is_empty() { 36 continue; 37 } 38 39 if line == "help" { 40 print_help(); 41 continue; 42 } 43 44 if line == "exit" || line == "quit" { 45 break; 46 } 47 48 if line.starts_with("set ") { 49 handle_set_command(&mut scanner, line)?; 50 continue; 51 } 52 match parse_value(line) { 53 Ok(value) => { 54 if first_scan { 55 match scanner.scan_for_value(value) { 56 Ok(_) => first_scan = false, 57 Err(e) => println!("Error scanning: {}", e), 58 } 59 } else { 60 match scanner.filter_matches(value) { 61 Ok(_) => {} 62 Err(e) => println!("Error filtering: {}", e), 63 } 64 } 65 } 66 Err(e) => println!("Invalid value: {}", e), 67 } 68 } 69 Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => { 70 println!("Exiting..."); 71 break; 72 } 73 Err(err) => { 74 println!("Error: {}", err); 75 break; 76 } 77 } 78 } 79 80 Ok(()) 81} 82 83fn print_help() { 84 println!("Available commands:"); 85 println!(" <value> - Search for value or narrow down existing results"); 86 println!(" set <idx> <value> - Set value at the memory address at index <idx>"); 87 println!(" help - Show this help message"); 88 println!(" exit/quit - Exit the program"); 89} 90 91fn handle_set_command(scanner: &mut MemoryScanner, command: &str) -> Result<()> { 92 let parts: Vec<&str> = command.split_whitespace().collect(); 93 if parts.len() != 3 { 94 anyhow::bail!("Invalid set command format. Use: set <idx> <value>"); 95 } 96 97 let idx = match parts[1].parse::<usize>() { 98 Ok(idx) => idx, 99 Err(_) => anyhow::bail!("Invalid index: {}", parts[1]), 100 }; 101 102 let value = match parse_value(parts[2])? { 103 ScanValueType::I32(val) => val, 104 _ => anyhow::bail!("Only i32 values are currently supported for setting"), 105 }; 106 107 scanner.set_value(idx, value) 108} 109 110fn parse_value(value_str: &str) -> Result<ScanValueType> { 111 if let Ok(val) = value_str.parse::<i32>() { 112 return Ok(ScanValueType::I32(val)); 113 } 114 115 // TODO missing implementation for all the other types 116 117 anyhow::bail!("Could not parse '{}' as a valid number", value_str) 118}