use crate::memory::{Memory, READ_CACHE};
use crate::r2_api::{Endian, Information, R2Api};
use crate::registers::Registers;
use crate::sims::fs::SimFilesytem;
use crate::solver::{BitVec, Solver};
use crate::value::{byte_values, vc, Value};
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::u8;
pub const DO_EVENT_HOOKS: bool = false;
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
pub enum EventTrigger {
Before, After, }
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
pub enum Event {
SymbolicRead(EventTrigger), SymbolicWrite(EventTrigger), SymbolicExec(EventTrigger), Alloc(EventTrigger), SymbolicAlloc(EventTrigger), Free(EventTrigger), SymbolicFree(EventTrigger), Search(EventTrigger), SymbolicSearch(EventTrigger), Compare(EventTrigger), SymbolicCompare(EventTrigger), StringLength(EventTrigger), SymbolicStrlen(EventTrigger), Move(EventTrigger), SymbolicMove(EventTrigger), All(EventTrigger), }
#[derive(Debug, Clone, PartialEq)]
pub enum EventContext {
ReadContext(Value, Value),
WriteContext(Value, Value),
ExecContext(Value, Vec<u64>),
AllocContext(Value),
FreeContext(Value),
SearchContext(Value, Value, Value),
CompareContext(Value, Value, Value),
StrlenContext(Value, Value),
MoveContext(Value, Value, Value),
}
pub type EventHook = dyn Fn(&mut State, &EventContext);
#[derive(Debug, Clone, PartialEq)]
pub enum ExecMode {
If, Else, Exec, NoExec, Uncon, }
#[derive(Debug, Clone)]
pub struct EsilState {
pub mode: ExecMode,
pub prev_pc: Value,
pub previous: Value,
pub current: Value,
pub last_sz: usize,
pub stored_address: Option<Value>,
pub temp1: Vec<StackItem>,
pub temp2: Vec<StackItem>,
pub pcs: Vec<u64>,
}
#[derive(Debug, Clone)]
pub enum StackItem {
StackRegister(usize),
StackValue(Value),
}
impl Default for StackItem {
fn default() -> Self {
StackItem::StackValue(Value::Concrete(0, 0))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum StateStatus {
Active,
Break,
Merge,
PostMerge, Unsat,
Inactive,
Crash(u64, char),
Exit,
}
#[derive(Clone)]
pub struct State {
pub solver: Solver,
pub r2api: R2Api,
pub info: Information,
pub stack: Vec<StackItem>,
pub esil: EsilState,
pub condition: Option<BitVec>,
pub registers: Registers,
pub memory: Memory,
pub filesystem: SimFilesytem,
pub status: StateStatus,
pub context: HashMap<String, Vec<Value>>,
pub taints: HashMap<String, u64>,
pub hooks: HashMap<Event, Rc<EventHook>>,
pub visits: HashMap<u64, usize>,
pub pid: u64,
pub backtrace: Vec<(u64, u64)>,
pub blank: bool,
pub debug: bool,
pub check: bool,
pub strict: bool,
pub has_event_hooks: bool,
}
impl PartialEq for State {
fn eq(&self, other: &Self) -> bool {
other.get_visit() == self.get_visit()
}
}
impl Eq for State {}
impl Ord for State {
fn cmp(&self, other: &Self) -> Ordering {
other.get_visit().cmp(&self.get_visit())
}
}
impl PartialOrd for State {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl State {
pub fn new(
r2api: &mut R2Api,
eval_max: usize,
debug: bool,
blank: bool,
check: bool,
strict: bool,
) -> Self {
let esil_state = EsilState {
mode: ExecMode::Uncon,
prev_pc: Value::Concrete(0, 0),
previous: Value::Concrete(0, 0),
current: Value::Concrete(0, 0),
last_sz: 64,
stored_address: None,
temp1: vec![], temp2: vec![],
pcs: Vec::with_capacity(64),
};
let solver = Solver::new(eval_max);
let registers = Registers::new(r2api, solver.clone(), blank);
let memory = Memory::new(r2api, solver.clone(), blank);
State {
solver,
r2api: r2api.clone(),
info: r2api.info.clone(),
stack: Vec::with_capacity(128),
esil: esil_state,
condition: None,
registers,
memory,
filesystem: SimFilesytem::new(),
status: StateStatus::Active,
context: HashMap::new(),
taints: HashMap::new(),
hooks: HashMap::new(),
visits: HashMap::with_capacity(512),
backtrace: Vec::with_capacity(128),
pid: 1337, blank,
debug,
check,
strict,
has_event_hooks: false,
}
}
pub fn duplicate(&mut self) -> Self {
let solver = self.solver.duplicate();
let mut registers = self.registers.clone();
registers.solver = solver.clone();
registers.values = registers
.values
.iter()
.map(|r| solver.translate_value(r))
.collect();
let mut memory = self.memory.clone();
memory.solver = solver.clone();
let addrs = memory.addresses();
for addr in addrs {
let values = memory.mem.remove(&addr).unwrap();
memory.mem.insert(
addr,
values.iter().map(|v| solver.translate_value(&v)).collect(),
);
}
let mut context = HashMap::new();
for key in self.context.keys() {
let values = self.context.get(key).unwrap();
let new_values = values.iter().map(|v| solver.translate_value(v)).collect();
context.insert(key.to_owned(), new_values);
}
let mut filesystem = self.filesystem.clone();
for f in &mut filesystem.files {
let content = f.content.clone();
f.content = content.iter().map(|v| solver.translate_value(v)).collect();
}
let esil_state = EsilState {
mode: ExecMode::Uncon,
prev_pc: self.esil.prev_pc.clone(),
previous: vc(0),
current: vc(0),
last_sz: 64,
stored_address: None,
temp1: Vec::with_capacity(128),
temp2: Vec::with_capacity(128),
pcs: Vec::with_capacity(64),
};
State {
solver,
r2api: self.r2api.clone(),
info: self.info.clone(),
stack: Vec::with_capacity(128),
esil: esil_state,
condition: None,
registers,
memory,
filesystem,
status: self.status.clone(),
context,
taints: self.taints.clone(),
hooks: self.hooks.clone(),
visits: self.visits.clone(),
backtrace: self.backtrace.clone(),
pid: self.pid,
blank: self.blank,
debug: self.debug,
check: self.check,
strict: self.strict,
has_event_hooks: self.has_event_hooks,
}
}
pub fn hook_event(&mut self, event: Event, hook: Rc<EventHook>) {
self.has_event_hooks = true;
self.hooks.insert(event, hook);
}
pub fn do_hooked(&mut self, event: &Event, event_context: &EventContext) {
if !self.hooks.contains_key(event) {
return;
}
let hook = self.hooks.get(event).unwrap().clone();
hook(self, event_context)
}
pub fn memory_alloc(&mut self, length: &Value) -> Value {
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if length.is_symbolic() {
Event::SymbolicAlloc(EventTrigger::Before)
} else {
Event::Alloc(EventTrigger::Before)
};
self.do_hooked(&event, &EventContext::AllocContext(length.to_owned()));
}
let ret = self.memory.alloc_sym(length, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if length.is_symbolic() {
Event::SymbolicAlloc(EventTrigger::After)
} else {
Event::Alloc(EventTrigger::After)
};
self.do_hooked(&event, &EventContext::AllocContext(length.to_owned()));
}
ret
}
pub fn memory_free(&mut self, addr: &Value) -> Value {
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if addr.is_symbolic() {
Event::SymbolicFree(EventTrigger::Before)
} else {
Event::Free(EventTrigger::Before)
};
self.do_hooked(&event, &EventContext::FreeContext(addr.to_owned()));
}
if self.check && self.check_crash(addr, &vc(1), 'r') {
return vc(-1i64 as u64);
}
let ret = self.memory.free_sym(addr, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if addr.is_symbolic() {
Event::SymbolicFree(EventTrigger::After)
} else {
Event::Free(EventTrigger::After)
};
self.do_hooked(&event, &EventContext::FreeContext(addr.to_owned()));
}
ret
}
pub fn memory_read(&mut self, address: &Value, length: &Value) -> Vec<Value> {
if DO_EVENT_HOOKS && self.has_event_hooks && (address.is_symbolic() || length.is_symbolic())
{
self.do_hooked(
&Event::SymbolicRead(EventTrigger::Before),
&EventContext::ReadContext(address.to_owned(), length.to_owned()),
);
}
if self.check && self.check_crash(address, length, 'r') {
return vec![];
}
let ret = self.memory.read_sym_len(address, length, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks && (address.is_symbolic() || length.is_symbolic())
{
self.do_hooked(
&Event::SymbolicRead(EventTrigger::After),
&EventContext::ReadContext(address.to_owned(), length.to_owned()),
);
}
ret
}
pub fn memory_write(&mut self, address: &Value, values: &[Value], length: &Value) {
if DO_EVENT_HOOKS && self.has_event_hooks && (address.is_symbolic() || length.is_symbolic())
{
self.do_hooked(
&Event::SymbolicWrite(EventTrigger::Before),
&EventContext::WriteContext(address.to_owned(), length.to_owned()),
);
}
if self.check && self.check_crash(address, length, 'r') {
return;
}
let ret = self
.memory
.write_sym_len(address, values, length, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks && (address.is_symbolic() || length.is_symbolic())
{
self.do_hooked(
&Event::SymbolicWrite(EventTrigger::After),
&EventContext::WriteContext(address.to_owned(), length.to_owned()),
);
}
ret
}
#[inline]
pub fn memory_read_value(&mut self, address: &Value, length: usize) -> Value {
if DO_EVENT_HOOKS && self.has_event_hooks && address.is_symbolic() {
self.do_hooked(
&Event::SymbolicRead(EventTrigger::Before),
&EventContext::ReadContext(address.to_owned(), Value::Concrete(length as u64, 0)),
);
}
if self.check && self.check_crash(address, &vc(length as u64), 'r') {
return vc(-1i64 as u64);
}
let ret = self.memory.read_sym(address, length, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks && address.is_symbolic() {
self.do_hooked(
&Event::SymbolicRead(EventTrigger::After),
&EventContext::ReadContext(address.to_owned(), Value::Concrete(length as u64, 0)),
);
}
ret
}
#[inline]
pub fn memory_write_value(&mut self, address: &Value, value: &Value, length: usize) {
if DO_EVENT_HOOKS && self.has_event_hooks && address.is_symbolic() {
self.do_hooked(
&Event::SymbolicRead(EventTrigger::Before),
&EventContext::ReadContext(address.to_owned(), Value::Concrete(length as u64, 0)),
);
}
if self.check && self.check_crash(address, &vc(length as u64), 'w') {
return;
}
let ret = self
.memory
.write_sym(address, value, length, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks && address.is_symbolic() {
self.do_hooked(
&Event::SymbolicWrite(EventTrigger::After),
&EventContext::WriteContext(address.to_owned(), Value::Concrete(length as u64, 0)),
);
}
ret
}
pub fn memory_search(
&mut self,
addr: &Value,
needle: &Value,
length: &Value,
reverse: bool,
) -> Value {
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if addr.is_symbolic() || length.is_symbolic() {
Event::SymbolicSearch(EventTrigger::Before)
} else {
Event::Search(EventTrigger::Before)
};
self.do_hooked(
&event,
&EventContext::SearchContext(addr.to_owned(), needle.to_owned(), length.to_owned()),
);
}
if self.check && self.check_crash(addr, &vc(1), 'r') {
return vc(-1i64 as u64);
}
let ret = self
.memory
.search(addr, needle, length, reverse, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if addr.is_symbolic() || length.is_symbolic() {
Event::SymbolicSearch(EventTrigger::After)
} else {
Event::Search(EventTrigger::After)
};
self.do_hooked(
&event,
&EventContext::SearchContext(addr.to_owned(), needle.to_owned(), length.to_owned()),
);
}
ret
}
pub fn memory_compare(&mut self, dst: &Value, src: &Value, length: &Value) -> Value {
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if dst.is_symbolic() || src.is_symbolic() || length.is_symbolic() {
Event::SymbolicCompare(EventTrigger::Before)
} else {
Event::Compare(EventTrigger::Before)
};
self.do_hooked(
&event,
&EventContext::CompareContext(dst.to_owned(), src.to_owned(), length.to_owned()),
);
}
if self.check && (self.check_crash(src, &vc(1), 'r') || self.check_crash(dst, &vc(1), 'r'))
{
return vc(-1i64 as u64);
}
let ret = self.memory.compare(dst, src, length, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if dst.is_symbolic() || src.is_symbolic() || length.is_symbolic() {
Event::SymbolicCompare(EventTrigger::After)
} else {
Event::Compare(EventTrigger::After)
};
self.do_hooked(
&event,
&EventContext::CompareContext(dst.to_owned(), src.to_owned(), length.to_owned()),
);
}
ret
}
pub fn memory_strlen(&mut self, addr: &Value, length: &Value) -> Value {
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if addr.is_symbolic() || length.is_symbolic() {
Event::SymbolicStrlen(EventTrigger::Before)
} else {
Event::StringLength(EventTrigger::Before)
};
self.do_hooked(
&event,
&EventContext::StrlenContext(addr.to_owned(), length.to_owned()),
);
}
if self.check && self.check_crash(addr, &vc(1), 'r') {
return vc(-1i64 as u64);
}
let ret = self.memory.strlen(addr, length, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if addr.is_symbolic() || length.is_symbolic() {
Event::SymbolicStrlen(EventTrigger::After)
} else {
Event::StringLength(EventTrigger::After)
};
self.do_hooked(
&event,
&EventContext::StrlenContext(addr.to_owned(), length.to_owned()),
);
}
ret
}
pub fn memory_move(&mut self, dst: &Value, src: &Value, length: &Value) {
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if dst.is_symbolic() || src.is_symbolic() || length.is_symbolic() {
Event::SymbolicMove(EventTrigger::Before)
} else {
Event::Move(EventTrigger::Before)
};
self.do_hooked(
&event,
&EventContext::MoveContext(dst.to_owned(), src.to_owned(), length.to_owned()),
);
}
if self.check && (self.check_crash(src, length, 'r') || self.check_crash(dst, length, 'w'))
{
return;
}
self.memory.memmove(dst, src, length, &mut self.solver);
if DO_EVENT_HOOKS && self.has_event_hooks {
let event = if dst.is_symbolic() || src.is_symbolic() || length.is_symbolic() {
Event::SymbolicMove(EventTrigger::After)
} else {
Event::Move(EventTrigger::After)
};
self.do_hooked(
&event,
&EventContext::MoveContext(dst.to_owned(), src.to_owned(), length.to_owned()),
);
}
}
pub fn memory_read_ptr(&mut self, address: &Value) -> Value {
let ptr_len = self.memory.bits as usize / 8;
self.memory_read_value(address, ptr_len)
}
pub fn memory_write_ptr(&mut self, address: &Value, value: &Value) {
let ptr_len = self.memory.bits as usize / 8;
self.memory_write_value(address, value, ptr_len)
}
pub fn memory_read_bytes(&mut self, address: u64, length: usize) -> Vec<u8> {
self.memory.read_bytes(address, length, &mut self.solver)
}
pub fn memory_read_string(&mut self, address: u64, length: usize) -> String {
self.memory.read_string(address, length, &mut self.solver)
}
pub fn memory_read_cstring(&mut self, address: u64) -> String {
let length = self.memory_strlen(&vc(address), &vc(4096));
let len = self.solver.evalcon_to_u64(&length).unwrap_or(0);
self.memory
.read_string(address, len as usize, &mut self.solver)
}
pub fn memory_write_string(&mut self, address: u64, string: &str) {
self.memory.write_string(address, string)
}
pub fn pack(&self, data: &[Value]) -> Value {
self.memory.pack(data)
}
pub fn unpack(&self, data: &Value, length: usize) -> Vec<Value> {
let mut values = vec![Value::Concrete(0, 0); length];
self.memory.unpack(data, length, &mut values);
values
}
pub fn fill_file(&mut self, fd: usize, data: &[Value]) {
self.filesystem.fill(fd, data)
}
pub fn fill_file_string(&mut self, fd: usize, string: &str) {
let data = byte_values(string);
self.filesystem.fill(fd, &data)
}
pub fn dump_path(&mut self, path: &str) -> Vec<Value> {
if let Some(fd) = self.filesystem.getfd(path) {
self.filesystem.dump(fd)
} else {
vec![]
}
}
pub fn dump_file(&mut self, fd: usize) -> Vec<Value> {
self.filesystem.dump(fd)
}
pub fn dump_file_bytes(&mut self, fd: usize) -> Vec<u8> {
let values = self.filesystem.dump(fd);
let bytes = values
.iter()
.map(|v| self.solver.evalcon_to_u64(v).unwrap_or(0) as u8)
.collect();
bytes
}
pub fn dump_file_string(&mut self, fd: usize) -> Option<String> {
String::from_utf8(self.dump_file_bytes(fd)).ok()
}
pub fn apply(&mut self) {
let mut inds = Vec::with_capacity(256);
for reg in &self.registers.indexes {
if !inds.contains(®.value_index) {
inds.push(reg.value_index);
let rval = self.registers.values[reg.value_index].to_owned();
let r = self.solver.evalcon_to_u64(&rval).unwrap();
self.r2api.set_register_value(®.reg_info.name, r);
}
}
let mut bvals = vec![Value::Concrete(0, 0); READ_CACHE];
for addr in self.memory.addresses() {
self.memory.read(addr, READ_CACHE, &mut bvals);
let bytes: Vec<u8> = bvals
.iter()
.map(|bval| self.solver.evalcon_to_u64(&bval).unwrap() as u8)
.collect();
self.r2api.write(addr, bytes.clone());
}
}
pub fn merge(&mut self, state: &mut State) {
let state_asserts = &state.solver.assertions;
let assertion = state.solver.and_all(state_asserts);
let asserted = Value::Symbolic(assertion, 0);
let reg_count = state.registers.values.len();
for index in 0..reg_count {
let reg = &self.registers.values[index];
let curr_reg = &state.registers.values[index];
self.registers.values[index] = state.solver.conditional(&asserted, curr_reg, reg);
}
let merge_addrs = self.memory.addresses();
let state_addrs = state.memory.addresses();
let mut addrs = HashSet::with_capacity(READ_CACHE);
addrs.extend(merge_addrs);
addrs.extend(state_addrs);
let mut tmp1 = Vec::with_capacity(READ_CACHE);
let mut tmp2 = Vec::with_capacity(READ_CACHE);
for addr in addrs {
let newvec = if let Some(m) = self.memory.mem.get_mut(&addr) {
m
} else {
self.memory.read(addr, READ_CACHE, &mut tmp1);
&mut tmp1
};
let curvec = if let Some(m) = state.memory.mem.get(&addr) {
m
} else {
state.memory.read(addr, READ_CACHE, &mut tmp2);
&tmp2
};
for i in 0..READ_CACHE {
if newvec.len() > i && curvec.len() > i {
newvec[i] = state.cond(&asserted, &curvec[i], &newvec[i]);
}
}
}
for (k, v) in &state.context {
for i in 0..v.len() {
if let Some(nv) = self.context.get_mut(k) {
if i < nv.len() {
nv[i] = state.cond(&asserted, &v[i], &nv[i]);
} else {
nv.push(state.cond(&asserted, &v[i], &vc(0)))
}
}
}
}
for file in &state.filesystem.files {
for cfile in &mut self.filesystem.files {
if file.path == cfile.path {
let mlen = if file.content.len() > cfile.content.len() {
file.content.len()
} else {
cfile.content.len()
};
for i in 0..mlen {
let space = vc(0x20); let v = file.content.get(i).unwrap_or(&space);
let cv = cfile.content.get(i).unwrap_or(&space);
if i < cfile.content.len() {
cfile.content[i] = state.cond(&asserted, &v, &cv);
} else {
cfile.content.push(state.cond(&asserted, &v, &cv));
}
}
}
}
}
let assertions = &self.solver.assertions;
let current = state.solver.and_all(assertions);
self.solver.reset();
self.assert_bv(¤t.or(&asserted.as_bv().unwrap()));
}
pub fn constrain_with_state(&mut self, state: &Self) {
self.solver = state.solver.clone();
}
pub fn bv(&self, s: &str, n: u32) -> BitVec {
self.solver.bv(s, n)
}
pub fn bvv(&self, v: u64, n: u32) -> BitVec {
self.solver.bvv(v, n)
}
pub fn concrete_value(&self, v: u64, n: u32) -> Value {
let mask = if n < 64 { (1 << n) - 1 } else { -1i64 as u64 };
Value::Concrete(v & mask, 0)
}
pub fn symbolic_value(&self, s: &str, n: u32) -> Value {
Value::Symbolic(self.bv(s, n), 0)
}
pub fn tainted_concrete_value(&mut self, t: &str, v: u64, n: u32) -> Value {
let mask = if n < 64 { (1 << n) - 1 } else { -1i64 as u64 };
let taint = self.get_tainted_identifier(t);
Value::Concrete(v & mask, taint)
}
pub fn tainted_symbolic_value(&mut self, t: &str, s: &str, n: u32) -> Value {
let taint = self.get_tainted_identifier(t);
Value::Symbolic(self.bv(s, n), taint)
}
pub fn get_tainted_identifier(&mut self, t: &str) -> u64 {
if let Some(taint) = self.taints.get(t) {
*taint
} else {
let index = self.taints.len();
if index < 64 {
let new_taint = 1 << index as u64;
self.taints.insert(t.to_owned(), new_taint);
new_taint
} else {
println!("Max of 64 taints allowed!");
0
}
}
}
pub fn is_tainted_with(&mut self, value: &Value, taint: &str) -> bool {
(value.get_taint() & self.get_tainted_identifier(taint)) != 0
}
pub fn translate(&self, bv: &BitVec) -> Option<BitVec> {
self.solver.translate(bv)
}
pub fn translate_value(&self, value: &Value) -> Value {
self.solver.translate_value(value)
}
pub fn eval(&mut self, val: &Value) -> Option<Value> {
self.solver.eval(val)
}
pub fn evaluate(&mut self, bv: &BitVec) -> Option<Value> {
self.solver.evaluate(bv)
}
pub fn evalcon(&mut self, bv: &BitVec) -> Option<u64> {
self.solver.evalcon(bv)
}
pub fn constrain_bytes_bv(&mut self, bv: &BitVec, pattern: &str) {
if &pattern[..1] != "[" {
for (i, c) in pattern.chars().enumerate() {
self.assert_bv(
&bv.slice(8 * (i as u32 + 1) - 1, 8 * i as u32)
._eq(&self.bvv(c as u64, 8)),
);
}
} else {
let patlen = pattern.len();
let newpat = &pattern[1..patlen - 1];
let mut assertions = Vec::with_capacity(256);
for ind in 0..bv.get_width() / 8 {
assertions.clear();
let s = &bv.slice(8 * (ind + 1) - 1, 8 * ind);
let mut i = 0;
while i < patlen - 2 {
let c = newpat.as_bytes()[i] as u64;
if patlen > 4 && i < patlen - 4 && &newpat[i + 1..i + 2] == "-" {
let n = newpat.as_bytes()[i + 2] as u64;
i += 3;
assertions.push(s.ugte(&self.bvv(c, 8)).and(&s.ulte(&self.bvv(n, 8))));
} else {
i += 1;
assertions.push(s._eq(&self.bvv(c, 8)));
}
}
self.assert_bv(&self.solver.or_all(&assertions));
}
}
}
pub fn constrain_bytes(&mut self, bv: &Value, pattern: &str) {
if let Value::Symbolic(s, _) = bv {
self.constrain_bytes_bv(s, pattern)
}
}
pub fn constrain_fd(&mut self, fd: usize, content: &str) {
let fbytes = self.dump_file(fd);
let fbv = self.pack(&fbytes);
self.constrain_bytes(&fbv, content);
}
pub fn constrain_file(&mut self, path: &str, content: &str) {
if let Some(fd) = self.filesystem.getfd(path) {
self.constrain_fd(fd, content);
}
}
pub fn search_file(&mut self, path: &str, content: &str) -> Value {
if let Some(fd) = self.filesystem.getfd(path) {
self.search_fd(fd, content)
} else {
vc(-1i64 as u64)
}
}
pub fn search_fd(&mut self, fd: usize, content: &str) -> Value {
let data = self.dump_file(fd);
let length = vc(data.len() as u64);
let addr = self.memory_alloc(&length);
self.memory_write(&addr, &data, &length);
let needle = self.pack(&byte_values(content));
let result = self.memory_search(&addr, &needle, &length, false);
self.memory_free(&addr);
self.cond(&result.eq(&vc(0)), &vc(-1i64 as u64), &result)
}
pub fn is_sat(&mut self) -> bool {
if self.solver.is_sat() {
true
} else {
self.status = StateStatus::Unsat;
false
}
}
pub fn visit(&mut self) {
if let Some(pc) = self.registers.get_pc().as_u64() {
self.visits.entry(pc).and_modify(|c| *c += 1).or_insert(1);
}
}
pub fn get_visit(&self) -> usize {
if let Some(pc) = self.registers.get_pc().as_u64() {
*self.visits.get(&pc).unwrap_or(&0)
} else {
0
}
}
pub fn print_backtrace(&mut self) {
for (i, bt) in self.backtrace.iter().rev().enumerate() {
let name = self.r2api.get_flag(bt.1).unwrap_or_default();
println!("\n#{} 0x{:08x} ({})\n", i, bt.1, name.trim());
}
}
pub fn set_status(&mut self, status: StateStatus) {
self.status = status;
}
pub fn get_status(&mut self) -> StateStatus {
self.status.clone()
}
pub fn set_inactive(&mut self) {
self.set_status(StateStatus::Inactive);
}
pub fn set_crash(&mut self, addr: u64, perm: char) {
self.set_status(StateStatus::Crash(addr, perm));
}
pub fn check_crash(&mut self, addr: &Value, len: &Value, perm: char) -> bool {
let length = self.solver.max_value(len);
match addr {
Value::Concrete(address, _t) => {
let crash = !self.memory.check_permission(*address, length, perm);
if crash {
self.set_crash(*address, perm);
}
crash
}
Value::Symbolic(address, _t) => {
let min = self.solver.min(address);
let max = self.solver.max(address);
let min_crash = !self.memory.check_permission(min, length, perm);
let max_crash = !self.memory.check_permission(max, length, perm);
if min_crash {
self.set_crash(min, perm);
} else if max_crash {
self.set_crash(max, perm);
}
min_crash || max_crash
}
}
}
pub fn set_break(&mut self) {
self.set_status(StateStatus::Break);
}
pub fn get_args(&mut self) -> Vec<Value> {
let pc = self.registers.get_pc().as_u64().unwrap();
let cc = self.r2api.get_cc(pc).unwrap_or_default();
let mut args = Vec::with_capacity(16);
if !cc.args.is_empty() {
for arg in &cc.args {
args.push(self.registers.get_with_alias(arg));
}
} else {
let mut sp = self.registers.get_with_alias("SP");
let length = self.memory.bits as usize / 8;
for _ in 0..8 {
sp = sp + Value::Concrete(length as u64, 0);
let value = self.memory_read_value(&sp, length);
args.push(value);
}
}
args
}
pub fn get_ret(&mut self) -> Value {
let pc = self.registers.get_pc().as_u64().unwrap();
let cc = self.r2api.get_cc(pc).unwrap_or_default();
self.registers.get(&cc.ret)
}
pub fn set_args(&mut self, mut values: Vec<Value>) {
let pc = self.registers.get_pc().as_u64().unwrap();
let cc = self.r2api.get_cc(pc).unwrap_or_default();
if !cc.args.is_empty() {
for arg in &cc.args {
if !values.is_empty() {
self.registers.set_with_alias(arg, values.remove(0));
}
}
} else {
let mut sp = self.registers.get_with_alias("SP");
let length = self.memory.bits as usize / 8;
for _ in 0..8 {
sp = sp + Value::Concrete(length as u64, 0);
if !values.is_empty() {
self.memory_write_value(&sp, &values.remove(0), length);
}
}
}
}
pub fn assert_bv(&mut self, bv: &BitVec) {
self.solver.assert_bv(bv)
}
pub fn assert(&mut self, value: &Value) {
self.solver.assert(value)
}
pub fn check(&mut self, val: &Value) -> bool {
self.solver.check_sat(val)
}
pub fn cond(&self, condition: &Value, if_val: &Value, else_val: &Value) -> Value {
self.solver.conditional(condition, if_val, else_val)
}
pub fn evaluate_many(&mut self, bv: &BitVec) -> Vec<u64> {
self.solver.evaluate_many(bv)
}
pub fn evaluate_bytes_bv(&mut self, bv: &BitVec) -> Option<Vec<u8>> {
let new_bv = bv; let mut data: Vec<u8> = vec![];
if self.solver.is_sat() {
let solution_opt = self.solver.solution(new_bv);
if let Some(solution) = solution_opt {
for i in 0..(new_bv.get_width() / 8) as usize {
let sol = u8::from_str_radix(&solution[i * 8..(i + 1) * 8], 2);
data.push(sol.unwrap());
}
if self.memory.endian == Endian::Little {
data.reverse();
}
Some(data)
} else {
None
}
} else {
None
}
}
pub fn evaluate_string_bv(&mut self, bv: &BitVec) -> Option<String> {
if let Some(bytes) = self.evaluate_bytes_bv(bv) {
String::from_utf8(bytes).ok()
} else {
None
}
}
pub fn evaluate_bytes(&mut self, value: &Value) -> Option<Vec<u8>> {
self.evaluate_bytes_bv(value.as_bv().as_ref().unwrap())
}
pub fn evaluate_string(&mut self, value: &Value) -> Option<String> {
self.evaluate_string_bv(value.as_bv().as_ref().unwrap())
}
}