diff options
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/function.rs | 8 | ||||
| -rw-r--r-- | rust/src/lib.rs | 1 | ||||
| -rw-r--r-- | rust/src/mlil/function.rs | 20 | ||||
| -rw-r--r-- | rust/src/mlil/instruction.rs | 123 | ||||
| -rw-r--r-- | rust/src/mlil/operation.rs | 227 | ||||
| -rw-r--r-- | rust/src/operand_iter.rs | 181 |
6 files changed, 301 insertions, 259 deletions
diff --git a/rust/src/function.rs b/rust/src/function.rs index 273a0861..6547762f 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -435,6 +435,14 @@ impl PartialEq for Function { } } +pub trait ILFunction { + type BNInstruction; + type Instruction; + + fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction; + fn operands_from_idx(&self, expr_idx: usize) -> [u64; 5]; +} + ///////////////// // AddressRange diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 8424cb59..11021bd7 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -124,6 +124,7 @@ extern crate rayon; #[macro_use] mod ffi; +mod operand_iter; pub mod architecture; pub mod backgroundtask; diff --git a/rust/src/mlil/function.rs b/rust/src/mlil/function.rs index 16cc5102..3f96d8bb 100644 --- a/rust/src/mlil/function.rs +++ b/rust/src/mlil/function.rs @@ -2,16 +2,19 @@ use core::hash::{Hash, Hasher}; use binaryninjacore_sys::BNFreeMediumLevelILFunction; use binaryninjacore_sys::BNGetMediumLevelILBasicBlockList; +use binaryninjacore_sys::BNGetMediumLevelILByIndex; use binaryninjacore_sys::BNGetMediumLevelILInstructionCount; use binaryninjacore_sys::BNGetMediumLevelILOwnerFunction; use binaryninjacore_sys::BNGetMediumLevelILSSAForm; use binaryninjacore_sys::BNMediumLevelILFunction; use binaryninjacore_sys::BNMediumLevelILGetInstructionStart; +use binaryninjacore_sys::BNMediumLevelILInstruction; +use binaryninjacore_sys::BNMediumLevelILOperation; use binaryninjacore_sys::BNNewMediumLevelILFunctionReference; use crate::basicblock::BasicBlock; -use crate::function::Function; use crate::function::Location; +use crate::function::{Function, ILFunction}; use crate::rc::{Array, Ref, RefCountable}; use super::{MediumLevelILBlock, MediumLevelILInstruction, MediumLevelILLiftedInstruction}; @@ -93,6 +96,21 @@ impl MediumLevelILFunction { } } +impl ILFunction for MediumLevelILFunction { + type BNInstruction = BNMediumLevelILInstruction; + type Instruction = MediumLevelILInstruction; + + fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction { + self.instruction_from_idx(expr_idx) + } + + fn operands_from_idx(&self, expr_idx: usize) -> [u64; 5] { + let node = unsafe { BNGetMediumLevelILByIndex(self.handle, expr_idx) }; + assert_eq!(node.operation, BNMediumLevelILOperation::MLIL_UNDEF); + node.operands + } +} + impl ToOwned for MediumLevelILFunction { type Owned = Ref<Self>; diff --git a/rust/src/mlil/instruction.rs b/rust/src/mlil/instruction.rs index 7b182010..a25a0859 100644 --- a/rust/src/mlil/instruction.rs +++ b/rust/src/mlil/instruction.rs @@ -1,8 +1,13 @@ +use binaryninjacore_sys::BNFromVariableIdentifier; use binaryninjacore_sys::BNGetMediumLevelILByIndex; +use binaryninjacore_sys::BNMediumLevelILInstruction; use binaryninjacore_sys::BNMediumLevelILOperation; +use crate::operand_iter::OperandIter; use crate::rc::Ref; -use crate::types::{ConstantData, ILIntrinsic, RegisterValue, RegisterValueType}; +use crate::types::{ + ConstantData, ILIntrinsic, RegisterValue, RegisterValueType, SSAVariable, Variable, +}; use super::lift::*; use super::operation::*; @@ -773,8 +778,8 @@ impl MediumLevelILInstruction { }), JumpTo(op) => Lifted::JumpTo(LiftedJumpTo { dest: self.lift_operand(op.dest), - targets: OperandIter::new(&self.function, op.first_operand, op.num_operands) - .as_pairs() + targets: OperandIter::new(&*self.function, op.first_operand, op.num_operands) + .pairs() .collect(), }), Goto(op) => Lifted::Goto(op), @@ -812,13 +817,13 @@ impl MediumLevelILInstruction { }), VarPhi(op) => Lifted::VarPhi(LiftedVarPhi { dest: op.dest, - src: OperandIter::new(&self.function, op.first_operand, op.num_operands) - .as_ssa_vars() + src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) + .ssa_vars() .collect(), }), MemPhi(op) => Lifted::MemPhi(LiftedMemPhi { dest_memory: op.dest_memory, - src_memory: OperandIter::new(&self.function, op.first_operand, op.num_operands) + src_memory: OperandIter::new(&*self.function, op.first_operand, op.num_operands) .collect(), }), VarSplit(op) => Lifted::VarSplit(op), @@ -889,31 +894,31 @@ impl MediumLevelILInstruction { Tailcall(op) => Lifted::Tailcall(self.lift_call(op)), Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic { - output: OperandIter::new(&self.function, op.first_output, op.num_outputs) - .as_vars() + output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) + .vars() .collect(), intrinsic: ILIntrinsic::new(self.function.get_function().arch(), op.intrinsic), - params: OperandIter::new(&self.function, op.first_param, op.num_params) - .as_exprs() + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() .map(|expr| expr.lift()) .collect(), }), Syscall(op) => Lifted::Syscall(LiftedSyscallCall { - output: OperandIter::new(&self.function, op.first_output, op.num_outputs) - .as_vars() + output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) + .vars() .collect(), - params: OperandIter::new(&self.function, op.first_param, op.num_params) - .as_exprs() + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() .map(|expr| expr.lift()) .collect(), }), IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { - output: OperandIter::new(&self.function, op.first_output, op.num_outputs) - .as_ssa_vars() + output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) + .ssa_vars() .collect(), intrinsic: ILIntrinsic::new(self.function.get_function().arch(), op.intrinsic), - params: OperandIter::new(&self.function, op.first_param, op.num_params) - .as_exprs() + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() .map(|expr| expr.lift()) .collect(), }), @@ -926,8 +931,8 @@ impl MediumLevelILInstruction { SyscallSsa(op) => Lifted::SyscallSsa(LiftedSyscallSsa { output: get_call_output_ssa(&self.function, op.output).collect(), - params: OperandIter::new(&self.function, op.first_param, op.num_params) - .as_exprs() + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() .map(|expr| expr.lift()) .collect(), src_memory: op.src_memory, @@ -983,20 +988,20 @@ impl MediumLevelILInstruction { src_memory: op.src_memory, }), Ret(op) => Lifted::Ret(LiftedRet { - src: OperandIter::new(&self.function, op.first_operand, op.num_operands) - .as_exprs() + src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) + .exprs() .map(|expr| expr.lift()) .collect(), }), SeparateParamList(op) => Lifted::SeparateParamList(LiftedSeparateParamList { - params: OperandIter::new(&self.function, op.first_param, op.num_params) - .as_exprs() + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() .map(|expr| expr.lift()) .collect(), }), SharedParamSlot(op) => Lifted::SharedParamSlot(LiftedSharedParamSlot { - params: OperandIter::new(&self.function, op.first_param, op.num_params) - .as_exprs() + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() .map(|expr| expr.lift()) .collect(), }), @@ -1045,12 +1050,12 @@ impl MediumLevelILInstruction { fn lift_call(&self, op: Call) -> LiftedCall { LiftedCall { - output: OperandIter::new(&self.function, op.first_output, op.num_outputs) - .as_vars() + output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) + .vars() .collect(), dest: self.lift_operand(op.dest), - params: OperandIter::new(&self.function, op.first_param, op.num_params) - .as_exprs() + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() .map(|expr| expr.lift()) .collect(), } @@ -1071,8 +1076,8 @@ impl MediumLevelILInstruction { LiftedCallSsa { output: get_call_output_ssa(&self.function, op.output).collect(), dest: self.lift_operand(op.dest), - params: OperandIter::new(&self.function, op.first_param, op.num_params) - .as_exprs() + params: OperandIter::new(&*self.function, op.first_param, op.num_params) + .exprs() .map(|expr| expr.lift()) .collect(), src_memory: op.src_memory, @@ -1090,3 +1095,57 @@ impl MediumLevelILInstruction { } } } + +fn get_float(value: u64, size: usize) -> f64 { + match size { + 4 => f32::from_bits(value as u32) as f64, + 8 => f64::from_bits(value), + // TODO how to handle this value? + size => todo!("float size {}", size), + } +} + +fn get_raw_operation(function: &MediumLevelILFunction, idx: usize) -> BNMediumLevelILInstruction { + unsafe { BNGetMediumLevelILByIndex(function.handle, idx) } +} + +fn get_var(id: u64) -> Variable { + unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) } +} + +fn get_var_ssa(id: u64, version: usize) -> SSAVariable { + SSAVariable::new(get_var(id), version) +} + +fn get_call_output(function: &MediumLevelILFunction, idx: usize) -> impl Iterator<Item = Variable> { + let op = get_raw_operation(function, idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT); + OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).vars() +} + +fn get_call_params( + function: &MediumLevelILFunction, + idx: usize, +) -> impl Iterator<Item = MediumLevelILInstruction> { + let op = get_raw_operation(function, idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM); + OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).exprs() +} + +fn get_call_output_ssa( + function: &MediumLevelILFunction, + idx: usize, +) -> impl Iterator<Item = SSAVariable> { + let op = get_raw_operation(function, idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT_SSA); + OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).ssa_vars() +} + +fn get_call_params_ssa( + function: &MediumLevelILFunction, + idx: usize, +) -> impl Iterator<Item = MediumLevelILInstruction> { + let op = get_raw_operation(function, idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA); + OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).exprs() +} diff --git a/rust/src/mlil/operation.rs b/rust/src/mlil/operation.rs index 319ba34b..eb0c01ea 100644 --- a/rust/src/mlil/operation.rs +++ b/rust/src/mlil/operation.rs @@ -1,235 +1,10 @@ use std::collections::HashMap; -use binaryninjacore_sys::BNFromVariableIdentifier; -use binaryninjacore_sys::BNGetMediumLevelILByIndex; -use binaryninjacore_sys::BNMediumLevelILInstruction; -use binaryninjacore_sys::BNMediumLevelILOperation; - -use crate::rc::Ref; use crate::types; use crate::types::ILIntrinsic; -use crate::types::RegisterValue; -use crate::types::RegisterValueType; use crate::types::{SSAVariable, Variable}; -use super::{MediumLevelILFunction, MediumLevelILInstruction, MediumLevelILLiftedInstruction}; - -pub struct OperandIter { - function: Ref<MediumLevelILFunction>, - remaining: usize, - next_iter_idx: Option<usize>, - current_iter: OperandIterInner, -} - -impl OperandIter { - pub(crate) fn new(function: &MediumLevelILFunction, idx: usize, number: usize) -> Self { - Self { - function: function.to_owned(), - remaining: number, - next_iter_idx: Some(idx), - current_iter: OperandIterInner::empty(), - } - } - - pub fn as_pairs(self) -> OperandPairIter { - assert_eq!(self.len() % 2, 0); - OperandPairIter(self) - } - - pub fn as_exprs(self) -> OperandExprIter { - OperandExprIter(self) - } - - pub fn as_vars(self) -> OperandVarIter { - OperandVarIter(self) - } - - pub fn as_ssa_vars(self) -> OperandSSAVarIter { - OperandSSAVarIter(self.as_pairs()) - } -} - -impl Iterator for OperandIter { - type Item = u64; - fn next(&mut self) -> Option<Self::Item> { - if let Some(item) = self.current_iter.next() { - self.remaining -= 1; - Some(item) - } else { - // Will short-circuit and return `None` once iter is exhausted - let iter_idx = self.next_iter_idx?; - let node = get_raw_operation(&self.function, iter_idx); - assert_eq!(node.operation, BNMediumLevelILOperation::MLIL_UNDEF); - - let next = if self.remaining > 4 { - self.next_iter_idx = Some(node.operands[4] as usize); - &node.operands[..4] - } else { - self.next_iter_idx = None; - &node.operands[..self.remaining] - }; - - self.current_iter = OperandIterInner::from_slice(next); - self.next() - } - } -} -impl ExactSizeIterator for OperandIter { - fn len(&self) -> usize { - self.remaining + self.current_iter.len() - } -} - -struct OperandIterInner { - arr: [u64; 4], - idx: usize, -} - -impl OperandIterInner { - fn from_slice(slice: &[u64]) -> Self { - assert!(slice.len() <= 4); - let idx = 4 - slice.len(); - let mut arr = [0; 4]; - arr[idx..].copy_from_slice(slice); - Self { arr, idx } - } - - fn empty() -> Self { - Self { - arr: [0; 4], - idx: 4, - } - } -} - -impl Iterator for OperandIterInner { - type Item = u64; - - fn next(&mut self) -> Option<Self::Item> { - if self.idx < 4 { - let val = self.arr[self.idx]; - self.idx += 1; - Some(val) - } else { - None - } - } -} -impl ExactSizeIterator for OperandIterInner { - fn len(&self) -> usize { - 4 - self.idx - } -} - -pub struct OperandPairIter(OperandIter); -impl Iterator for OperandPairIter { - type Item = (u64, u64); - - fn next(&mut self) -> Option<Self::Item> { - let first = self.0.next()?; - let second = self.0.next()?; - Some((first, second)) - } -} -impl ExactSizeIterator for OperandPairIter { - fn len(&self) -> usize { - self.0.len() / 2 - } -} - -pub struct OperandExprIter(OperandIter); -impl Iterator for OperandExprIter { - type Item = MediumLevelILInstruction; - - fn next(&mut self) -> Option<Self::Item> { - self.0 - .next() - .map(|idx| self.0.function.instruction_from_idx(idx as usize)) - } -} -impl ExactSizeIterator for OperandExprIter { - fn len(&self) -> usize { - self.0.len() - } -} - -pub struct OperandVarIter(OperandIter); -impl Iterator for OperandVarIter { - type Item = Variable; - - fn next(&mut self) -> Option<Self::Item> { - self.0.next().map(get_var) - } -} -impl ExactSizeIterator for OperandVarIter { - fn len(&self) -> usize { - self.0.len() - } -} - -pub struct OperandSSAVarIter(OperandPairIter); -impl Iterator for OperandSSAVarIter { - type Item = SSAVariable; - - fn next(&mut self) -> Option<Self::Item> { - self.0 - .next() - .map(|(id, version)| get_var_ssa(id, version as usize)) - } -} -impl ExactSizeIterator for OperandSSAVarIter { - fn len(&self) -> usize { - self.0.len() - } -} - -pub(super) fn get_float(value: u64, size: usize) -> f64 { - match size { - 4 => f32::from_bits(value as u32) as f64, - 8 => f64::from_bits(value), - // TODO how to handle this value? - size => todo!("float size {}", size), - } -} - -fn get_raw_operation(function: &MediumLevelILFunction, idx: usize) -> BNMediumLevelILInstruction { - unsafe { BNGetMediumLevelILByIndex(function.handle, idx) } -} - -pub(super) fn get_var(id: u64) -> Variable { - unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) } -} - -pub(super) fn get_var_ssa(id: u64, version: usize) -> SSAVariable { - SSAVariable::new(get_var(id), version) -} - -pub(super) fn get_call_output(function: &MediumLevelILFunction, idx: usize) -> OperandVarIter { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT); - OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).as_vars() -} - -pub(super) fn get_call_params(function: &MediumLevelILFunction, idx: usize) -> OperandExprIter { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM); - OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).as_exprs() -} - -pub(super) fn get_call_output_ssa( - function: &MediumLevelILFunction, - idx: usize, -) -> OperandSSAVarIter { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT_SSA); - OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).as_ssa_vars() -} - -pub(super) fn get_call_params_ssa(function: &MediumLevelILFunction, idx: usize) -> OperandExprIter { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA); - OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).as_exprs() -} +use super::MediumLevelILLiftedInstruction; // IF #[derive(Copy, Clone)] diff --git a/rust/src/operand_iter.rs b/rust/src/operand_iter.rs new file mode 100644 index 00000000..a9b3c753 --- /dev/null +++ b/rust/src/operand_iter.rs @@ -0,0 +1,181 @@ +use binaryninjacore_sys::BNFromVariableIdentifier; + +use crate::function::ILFunction; +use crate::rc::{Ref, RefCountable}; +use crate::types::{SSAVariable, Variable}; + +pub struct OperandIter<F: ILFunction + RefCountable> { + function: Ref<F>, + remaining: usize, + next_iter_idx: Option<usize>, + current_iter: OperandIterInner, +} + +impl<F: ILFunction + RefCountable> OperandIter<F> { + pub(crate) fn new(function: &F, idx: usize, number: usize) -> Self { + Self { + function: function.to_owned(), + remaining: number, + next_iter_idx: Some(idx), + current_iter: OperandIterInner::empty(), + } + } + + pub fn pairs(self) -> OperandPairIter<F> { + assert_eq!(self.len() % 2, 0); + OperandPairIter(self) + } + + pub fn exprs(self) -> OperandExprIter<F> { + OperandExprIter(self) + } + + pub fn vars(self) -> OperandVarIter<F> { + OperandVarIter(self) + } + + pub fn ssa_vars(self) -> OperandSSAVarIter<F> { + OperandSSAVarIter(self.pairs()) + } +} + +impl<F: ILFunction + RefCountable> Iterator for OperandIter<F> { + type Item = u64; + fn next(&mut self) -> Option<Self::Item> { + if let Some(item) = self.current_iter.next() { + self.remaining -= 1; + Some(item) + } else { + // Will short-circuit and return `None` once iter is exhausted + let iter_idx = self.next_iter_idx?; + let operands = self.function.operands_from_idx(iter_idx); + + let next = if self.remaining > 4 { + self.next_iter_idx = Some(operands[4] as usize); + &operands[..4] + } else { + self.next_iter_idx = None; + &operands[..self.remaining] + }; + + self.current_iter = OperandIterInner::from_slice(next); + self.next() + } + } +} +impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandIter<F> { + fn len(&self) -> usize { + self.remaining + self.current_iter.len() + } +} + +struct OperandIterInner { + arr: [u64; 4], + idx: usize, +} + +impl OperandIterInner { + fn from_slice(slice: &[u64]) -> Self { + assert!(slice.len() <= 4); + let idx = 4 - slice.len(); + let mut arr = [0; 4]; + arr[idx..].copy_from_slice(slice); + Self { arr, idx } + } + + fn empty() -> Self { + Self { + arr: [0; 4], + idx: 4, + } + } +} + +impl Iterator for OperandIterInner { + type Item = u64; + + fn next(&mut self) -> Option<Self::Item> { + if self.idx < 4 { + let val = self.arr[self.idx]; + self.idx += 1; + Some(val) + } else { + None + } + } +} +impl ExactSizeIterator for OperandIterInner { + fn len(&self) -> usize { + 4 - self.idx + } +} + +pub struct OperandPairIter<F: ILFunction + RefCountable>(OperandIter<F>); +impl<F: ILFunction + RefCountable> Iterator for OperandPairIter<F> { + type Item = (u64, u64); + + fn next(&mut self) -> Option<Self::Item> { + let first = self.0.next()?; + let second = self.0.next()?; + Some((first, second)) + } +} +impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandPairIter<F> { + fn len(&self) -> usize { + self.0.len() / 2 + } +} + +pub struct OperandExprIter<F: ILFunction + RefCountable>(OperandIter<F>); +impl<F: ILFunction + RefCountable> Iterator for OperandExprIter<F> { + type Item = F::Instruction; + + fn next(&mut self) -> Option<Self::Item> { + self.0 + .next() + .map(|idx| self.0.function.il_instruction_from_idx(idx as usize)) + } +} +impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandExprIter<F> { + fn len(&self) -> usize { + self.0.len() + } +} + +pub struct OperandVarIter<F: ILFunction + RefCountable>(OperandIter<F>); +impl<F: ILFunction + RefCountable> Iterator for OperandVarIter<F> { + type Item = Variable; + + fn next(&mut self) -> Option<Self::Item> { + self.0.next().map(get_var) + } +} +impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandVarIter<F> { + fn len(&self) -> usize { + self.0.len() + } +} + +pub struct OperandSSAVarIter<F: ILFunction + RefCountable>(OperandPairIter<F>); +impl<F: ILFunction + RefCountable> Iterator for OperandSSAVarIter<F> { + type Item = SSAVariable; + + fn next(&mut self) -> Option<Self::Item> { + self.0 + .next() + .map(|(id, version)| get_var_ssa(id, version as usize)) + } +} +impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandSSAVarIter<F> { + fn len(&self) -> usize { + self.0.len() + } +} + +pub fn get_var(id: u64) -> Variable { + unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) } +} + +pub fn get_var_ssa(id: u64, version: usize) -> SSAVariable { + SSAVariable::new(get_var(id), version) +} |
