1pub use crate::processor::{HookMethod, Processor, RunMode};
2use crate::r2_api::{BasicBlock, FunctionInfo, Information, Instruction, R2Api, R2Result};
3use crate::state::State;
4use crate::sims::syscall::indirect;
6use crate::sims::{get_sims, zero, Sim, SimMethod};
7use crate::value::{vc, Value};
8
9use std::collections::HashMap;
11use std::sync::{Arc, Mutex};
12
13#[derive(Debug, Clone, PartialEq)]
16pub enum RadiusOption {
17 Syscalls(bool),
19 Sims(bool),
21 SimAll(bool),
23 Optimize(bool),
25 Debug(bool),
27 Strict(bool),
29 Lazy(bool),
31 Permissions(bool),
33 Force(bool),
35 Topological(bool),
37 AutoMerge(bool),
39 EvalMax(usize),
41 R2Argument(&'static str),
43 SelfModify(bool),
45 LoadPlugins(bool),
47 LoadLibs(bool),
49 ColorOutput(bool),
51 LibPath(String),
53}
54
55pub struct Radius {
68 pub r2api: R2Api,
70 pub processor: Processor,
72 processors: Arc<Mutex<Vec<Processor>>>,
73 pub eval_max: usize,
75 pub check: bool,
77 pub debug: bool,
79 pub strict: bool,
81}
82
83impl Radius {
84 pub fn new<T: AsRef<str>>(filename: T) -> Self {
95 Radius::new_with_options(Some(filename), &[])
97 }
98
99 pub fn new_with_options<T: AsRef<str>>(filename: Option<T>, options: &[RadiusOption]) -> Self {
112 let mut argv = vec!["-2"];
113 let mut eval_max = 256;
114 let mut paths = vec![];
115 for o in options {
116 if let RadiusOption::R2Argument(arg) = o {
117 argv.push(*arg);
118 } else if let RadiusOption::EvalMax(m) = o {
119 eval_max = *m;
120 } else if let RadiusOption::LibPath(p) = o {
121 paths.push(p.to_owned());
122 }
123 }
124
125 let debug = options.contains(&RadiusOption::Debug(true));
126 let color = options.contains(&RadiusOption::ColorOutput(true));
127 let use_sims = !options.contains(&RadiusOption::Sims(false));
128
129 if !options.contains(&RadiusOption::LoadPlugins(true)) {
130 argv.push("-NN");
131 }
132
133 if debug && color {
134 argv.push("-e scr.color=3");
136 argv.push("-e asm.lines=false");
138 argv.push("-e asm.emu=false");
139 argv.push("-e asm.xrefs=false");
140 argv.push("-e asm.functions=false");
141 }
142
143 let args = if !argv.is_empty() || filename.is_none() {
144 Some(argv)
145 } else {
146 None
147 };
148
149 let mut r2api = R2Api::new(filename, args);
150 r2api.set_option("io.cache", "true").unwrap();
151 let arch = &r2api.info.bin.arch;
154
155 let opt = !options.contains(&RadiusOption::Optimize(false))
157 && arch.as_str() != "arm"
158 && arch.as_str() != "dalvik";
159
160 let lazy = !options.contains(&RadiusOption::Lazy(false));
161 let force = options.contains(&RadiusOption::Force(true));
162 let topo = options.contains(&RadiusOption::Topological(true));
163 let check = options.contains(&RadiusOption::Permissions(true));
164 let sim_all = options.contains(&RadiusOption::SimAll(true));
165 let selfmod = options.contains(&RadiusOption::SelfModify(true));
166 let strict = options.contains(&RadiusOption::Strict(true));
167 let automerge = options.contains(&RadiusOption::AutoMerge(true));
168
169 let mut processor = Processor::new(selfmod, opt, debug, lazy, force, topo, automerge, color);
170 let processors = Arc::new(Mutex::new(vec![]));
171
172 if !options.contains(&RadiusOption::Syscalls(false)) {
173 let syscalls = r2api.get_syscalls().unwrap();
174 if let Some(sys) = syscalls.get(0) {
175 processor.traps.insert(sys.swi, indirect);
176 }
177 for sys in &syscalls {
178 processor.syscalls.insert(sys.num, sys.to_owned());
179 }
180 }
181
182 let _libs = if options.contains(&RadiusOption::LoadLibs(true)) {
183 r2api.load_libraries(&paths).unwrap()
184 } else {
185 vec![]
186 };
187
188 if use_sims {
190 Radius::register_sims(&mut r2api, &mut processor, sim_all);
191 }
192
193 Radius {
194 r2api,
195 processor,
196 processors,
197 eval_max,
198 check,
199 debug,
200 strict,
201 }
202 }
203
204 pub fn call_state(&mut self, addr: u64) -> State {
217 self.r2api.seek(addr);
218 self.r2api.init_vm();
219 let mut state = self.init_state();
220 state.memory.add_stack();
221 state.memory.add_heap();
222 state.memory.add_std_streams();
223 state
224 }
225
226 pub fn callsym_state<T: AsRef<str>>(&mut self, sym: T) -> State {
239 let addr = self.get_address(sym).unwrap_or_default();
240 self.call_state(addr)
241 }
242
243 pub fn debug_state(&mut self, addr: u64, args: &[String]) -> State {
246 self.r2api.set_option("io.cache", "false").unwrap();
248 self.r2api.init_debug(addr, args);
249 self.init_state()
250 }
251
252 pub fn frida_state(&mut self, addr: u64) -> State {
255 self.r2api.seek(addr);
256 let mut state = self.init_state();
257 self.processor.fetch_instruction(&mut state, addr); let context = self.r2api.init_frida(addr).unwrap();
259
260 for reg in context.keys() {
261 if state.registers.regs.contains_key(reg) {
262 state.registers.set(reg, vc(context[reg]));
263 }
264 }
265 state
266 }
267
268 pub fn entry_state(&mut self) -> State {
278 let entrypoints = self.r2api.get_entrypoints().unwrap_or_default();
280 if !entrypoints.is_empty() {
281 self.r2api.seek(entrypoints[0].vaddr);
282 }
283 self.r2api.init_vm();
284 let mut state = self.init_state();
285 state.memory.add_stack();
286 state.memory.add_heap();
287 state.memory.add_std_streams();
288
289 let start_main_reloc = self.r2api.get_address("reloc.__libc_start_main").unwrap_or(0);
290 if start_main_reloc != 0 {
291 self.r2api.cmd("af").unwrap(); let callers = self.r2api.get_references(start_main_reloc).unwrap_or_default();
293 if !callers.is_empty() {
294 self.hook(callers[0].from, __libc_start_main);
295 }
296 }
297 state
298 }
299
300 pub fn set_argv_env(&mut self, state: &mut State, args: &[Value], env: &[Value]) {
302 let sp = state.registers.get_with_alias("SP");
305 let ptrlen = (state.memory.bits / 8) as usize;
306 let argc = Value::Concrete(args.len() as u64, 0);
307 state.memory_write_value(&sp, &argc, ptrlen);
308 state.registers.set_with_alias("A0", argc);
309
310 let types = ["argv", "env"];
311 let mut current = sp + Value::Concrete(ptrlen as u64, 0);
312 for (i, strings) in [args, env].iter().enumerate() {
313 state
314 .context
315 .insert(types[i].to_owned(), vec![current.clone()]);
316 let alias = format!("A{}", i + 1);
317 state.registers.set_with_alias(&alias, current.clone());
318 for string in strings.iter() {
319 let addr = state
320 .memory
321 .alloc(&Value::Concrete((string.size() / 8) as u64 + 1, 0));
322
323 state.memory_write_value(
324 &Value::Concrete(addr, 0),
325 string,
326 string.size() as usize / 8,
327 );
328
329 state.memory.write_value(
330 addr + (string.size() / 8) as u64,
331 &Value::Concrete(0, 0),
332 1,
333 );
334
335 state.memory_write_value(¤t, &Value::Concrete(addr, 0), ptrlen);
336 current = current + Value::Concrete(ptrlen as u64, 0);
337 }
338 state.memory_write_value(¤t, &Value::Concrete(0, 0), ptrlen);
339 current = current + Value::Concrete(ptrlen as u64, 0);
340 }
341 }
342
343 pub fn init_state(&mut self) -> State {
345 State::new(
346 &mut self.r2api,
347 self.eval_max,
348 self.debug,
349 false,
350 self.check,
351 self.strict,
352 )
353 }
354
355 pub fn blank_state(&mut self) -> State {
357 State::new(
358 &mut self.r2api,
359 self.eval_max,
360 self.debug,
361 true,
362 self.check,
363 self.strict,
364 )
365 }
366
367 pub fn blank_call_state(&mut self, addr: u64) -> State {
369 self.r2api.seek(addr);
370 self.r2api.init_vm();
371 let mut state = self.blank_state();
372 let sp = self.r2api.get_register_value("SP").unwrap();
373 state
374 .registers
375 .set_with_alias("PC", Value::Concrete(addr, 0));
376 state.registers.set_with_alias("SP", Value::Concrete(sp, 0));
377 state.memory.add_stack();
378 state.memory.add_heap();
379 state.memory.add_std_streams();
380 state
381 }
382
383 pub fn hook(&mut self, addr: u64, hook_callback: HookMethod) {
403 self.processor
404 .hooks
405 .entry(addr)
406 .or_insert(vec![])
407 .push(hook_callback);
408 }
409
410 pub fn esil_hook(&mut self, addr: u64, esil: &str) {
417 self.processor
418 .esil_hooks
419 .entry(addr)
420 .or_insert(vec![])
421 .push(esil.to_owned());
422 }
423
424 pub fn hook_symbol(&mut self, sym: &str, hook_callback: HookMethod) {
426 let addr = self.get_address(sym).unwrap();
427 self.hook(addr, hook_callback);
428 }
429
430 fn register_sims(r2api: &mut R2Api, processor: &mut Processor, sim_all: bool) {
432 let sims = get_sims();
433 let files = r2api.get_files().unwrap();
434
435 for file in files {
436 if file.uri.starts_with("null://") {
437 continue;
438 }
439
440 r2api.set_file_fd(file.fd);
441 let symbols = r2api.get_imports().unwrap();
442 let mut symmap: HashMap<String, u64> = HashMap::new();
443
444 for symbol in symbols {
445 symmap.insert(symbol.name, symbol.plt);
446 }
447
448 for sim in &sims {
450 let addropt = symmap.remove(&sim.symbol);
451 if let Some(addr) = addropt {
452 processor.sims.insert(addr, sim.to_owned());
453 }
454 }
455
456 if sim_all {
457 for name in symmap.keys() {
458 processor.sims.insert(
460 symmap[name],
461 Sim {
462 symbol: name.to_owned(),
463 function: zero,
464 arguments: 0,
465 },
466 );
467 }
468 }
469 }
470
471 r2api.set_file_fd(3);
473 }
474
475 pub fn trap(&mut self, trap_num: u64, sim: SimMethod) {
477 self.processor.traps.insert(trap_num, sim);
478 }
479
480 pub fn simulate(&mut self, addr: u64, sim: Sim) {
504 self.processor.sims.insert(addr, sim);
505 }
506
507 pub fn breakpoint(&mut self, addr: u64) {
510 self.processor.breakpoints.insert(addr);
511 }
512
513 pub fn mergepoint(&mut self, addr: u64) {
516 self.processor.mergepoints.insert(addr);
517 }
518
519 pub fn avoid(&mut self, addrs: &[u64]) {
525 for addr in addrs {
526 self.processor.avoidpoints.insert(*addr);
527 }
528 }
529
530 pub fn get_steps(&self) -> u64 {
532 self.processor.steps
533 + self
534 .processors
535 .lock()
536 .unwrap()
537 .iter()
538 .map(|p| p.steps)
539 .sum::<u64>()
540 }
541
542 pub fn call_function(&mut self, sym: &str, state: State, args: Vec<Value>) -> Option<State> {
544 let addr = self.r2api.get_address(sym).unwrap_or_default();
545 self.call_address(addr, state, args)
546 }
547
548 pub fn call_address(&mut self, addr: u64, mut state: State, args: Vec<Value>) -> Option<State> {
551 state.set_args(args);
552 state.registers.set_pc(vc(addr));
553
554 let mut states = self.run_all(state);
555 let count = states.len();
556
557 if !states.is_empty() {
558 let mut end = states.remove(0);
559 for _ in 1..count {
560 end.merge(&mut states.remove(0));
561 }
562 Some(end)
563 } else {
564 None
565 }
566 }
567
568 pub fn run_until(&mut self, state: State, target: u64, avoid: &[u64]) -> Option<State> {
575 self.breakpoint(target);
576 self.avoid(avoid);
577 self.processor.run(state, RunMode::Single).pop()
578 }
579
580 pub fn run_all(&mut self, state: State) -> Vec<State> {
582 self.processor.run(state, RunMode::Multiple)
583 }
584
585 pub fn run(&mut self, state: State, _threads: usize) -> Option<State> {
599 self.processor.run(state, RunMode::Single).pop()
601 }
602
603 pub fn analyze(&mut self, n: usize) {
605 let _r = self.r2api.analyze(n);
606 }
607
608 pub fn get_info(&mut self) -> R2Result<Information> {
610 self.r2api.get_info()
611 }
612
613 pub fn get_address<T: AsRef<str>>(&mut self, symbol: T) -> R2Result<u64> {
615 self.r2api.get_address(symbol.as_ref())
616 }
617
618 pub fn get_functions(&mut self) -> R2Result<Vec<FunctionInfo>> {
620 self.r2api.get_functions()
621 }
622
623 pub fn get_function(&mut self, address: u64) -> R2Result<FunctionInfo> {
625 self.r2api.get_function_info(address)
626 }
627
628 pub fn get_blocks(&mut self, address: u64) -> R2Result<Vec<BasicBlock>> {
630 self.r2api.get_blocks(address)
631 }
632
633 pub fn disassemble(&mut self, address: u64, num: usize) -> R2Result<Vec<Instruction>> {
635 self.r2api.disassemble(address, num)
636 }
637
638 pub fn disassemble_function(&mut self, address: u64) -> R2Result<Vec<Instruction>> {
640 self.r2api.disassemble_function(address)
641 }
642
643 pub fn assemble(&mut self, instruction: &str) -> R2Result<Vec<u8>> {
645 self.r2api.assemble(instruction)
646 }
647
648 pub fn read(&mut self, address: u64, length: usize) -> R2Result<Vec<u8>> {
650 self.r2api.read(address, length)
651 }
652
653 pub fn write(&mut self, address: u64, data: Vec<u8>) {
655 self.r2api.write(address, data)
656 }
657
658 pub fn write_string(&mut self, address: u64, string: &str) {
660 self.r2api
661 .write(address, string.chars().map(|c| c as u8).collect::<Vec<_>>())
662 }
663
664 pub fn set_option(&mut self, key: &str, value: &str) {
666 self.r2api.set_option(key, value).unwrap();
667 }
668
669 pub fn cmd(&mut self, cmd: &str) -> R2Result<String> {
671 self.r2api.cmd(cmd)
672 }
673
674 pub fn cont(&mut self) {
676 self.r2api.cont().unwrap();
677 }
678
679 pub fn close(&mut self) {
681 self.r2api.close()
682 }
683
684 pub fn clear(&mut self) {
686 self.r2api.clear();
687 self.processors.lock().unwrap().clear();
688 }
689}
690
691pub fn __libc_start_main(state: &mut State) -> bool {
692 let mut args = state.get_args();
693 let main = args.remove(0);
694
695 state.registers.set_with_alias("PC", main);
701 state.set_args(args);
702
703 false
704}