diff options
| author | Ryan Snyder <ryan@vector35.com> | 2021-01-21 18:27:48 +0000 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2021-01-21 19:06:55 +0000 |
| commit | d3140edec185f47235b9e4642bdd56d6c585a341 (patch) | |
| tree | a61859c29e4e3539daea2b761bb1439d942beaf4 /rust/src/llil/operation.rs | |
| parent | c0ddbf0c76d3f1bb7a2b2024f749afc8b9482575 (diff) | |
This is a combination of 23 commits, the work of Ryan Snyder:
Initial fresh repo
Add support for recent calling convention API updates and folds the binaryninjacore-sys crate directly into this one.
Add support for auto function analysis suppression
Finish moving binaryninjacore-sys back into this crate
Update for Symbol/Segment core API changes
Update for Symbol API cleanup
api: advance submodule reference, support Token changes
arch/lifting: support for flags in custom architectures
arch/lifting: support default flag write behaviors, handle more ops
build: enable headless binary support on MacOS via evil hack
bv: add BinaryView wrapper support, remove wrong comment
api: update to latest binja dev branch support
deps: bump dep versions
rust: bump to 2018 edition
api: bump to avoid cargo submodule brokenness
build: improve binaryninja path detection; enable linux linkhack
bv: stub for bv load settings
arch: fix flag related crash, minor llil update
api: update for recent changes
macos: disable linkhack briefly
Diffstat (limited to 'rust/src/llil/operation.rs')
| -rw-r--r-- | rust/src/llil/operation.rs | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/rust/src/llil/operation.rs b/rust/src/llil/operation.rs new file mode 100644 index 00000000..81d72d57 --- /dev/null +++ b/rust/src/llil/operation.rs @@ -0,0 +1,765 @@ +use binaryninjacore_sys::BNLowLevelILInstruction; + +use std::marker::PhantomData; +use std::mem; + +use super::*; + +pub struct Operation<'func, A, M, F, O> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + O: OperationArguments, +{ + pub(crate) function: &'func Function<A, M, F>, + pub(crate) op: BNLowLevelILInstruction, + _args: PhantomData<O>, +} + +impl<'func, A, M, F, O> Operation<'func, A, M, F, O> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + O: OperationArguments, +{ + pub(crate) fn new(function: &'func Function<A, M, F>, op: BNLowLevelILInstruction) -> Self { + Self { + function: function, + op: op, + _args: PhantomData, + } + } + + pub fn address(&self) -> u64 { + self.op.address + } +} + +impl<'func, A, M, O> Operation<'func, A, M, NonSSA<LiftedNonSSA>, O> +where + A: 'func + Architecture, + M: FunctionMutability, + O: OperationArguments, +{ + pub fn flag_write(&self) -> Option<A::FlagWrite> { + match self.op.flags { + 0 => None, + id => self.function.arch().flag_write_from_id(id) + } + } +} + +// LLIL_NOP, LLIL_NORET, LLIL_BP, LLIL_UNDEF, LLIL_UNIMPL +pub struct NoArgs; + + + +// LLIL_POP +pub struct Pop; + +impl<'func, A, M, F> Operation<'func, A, M, F, Pop> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } +} + + + + +// LLIL_SYSCALL, LLIL_SYSCALL_SSA +pub struct Syscall; + + + + +// LLIL_SET_REG, LLIL_SET_REG_SSA, LLIL_SET_REG_PARTIAL_SSA +pub struct SetReg; + +impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, SetReg> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_reg(&self) -> Register<A::Register> { + let raw_id = self.op.operands[0] as u32; + + if raw_id >= 0x8000_0000 { + Register::Temp(raw_id & 0x7fff_ffff) + } else { + self.function.arch().register_from_id(raw_id) + .map(Register::ArchReg) + .unwrap_or_else(|| { + error!("got garbage register from LLIL_SET_REG @ 0x{:x}", + self.op.address); + + Register::Temp(0) + }) + } + } + + pub fn source_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[1] as usize, + _ty: PhantomData, + } + } +} + + +// LLIL_SET_REG_SPLIT, LLIL_SET_REG_SPLIT_SSA +pub struct SetRegSplit; + +impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, SetRegSplit> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_reg_high(&self) -> Register<A::Register> { + let raw_id = self.op.operands[0] as u32; + + if raw_id >= 0x8000_0000 { + Register::Temp(raw_id & 0x7fff_ffff) + } else { + self.function.arch().register_from_id(raw_id) + .map(Register::ArchReg) + .unwrap_or_else(|| { + error!("got garbage register from LLIL_SET_REG_SPLIT @ 0x{:x}", + self.op.address); + + Register::Temp(0) + }) + } + } + + pub fn dest_reg_low(&self) -> Register<A::Register> { + let raw_id = self.op.operands[1] as u32; + + if raw_id >= 0x8000_0000 { + Register::Temp(raw_id & 0x7fff_ffff) + } else { + self.function.arch().register_from_id(raw_id) + .map(Register::ArchReg) + .unwrap_or_else(|| { + error!("got garbage register from LLIL_SET_REG_SPLIT @ 0x{:x}", + self.op.address); + + Register::Temp(0) + }) + } + } + + pub fn source_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[2] as usize, + _ty: PhantomData, + } + } +} + + + + +// LLIL_SET_FLAG, LLIL_SET_FLAG_SSA +pub struct SetFlag; + +impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, SetFlag> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub fn source_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[1] as usize, + _ty: PhantomData, + } + } +} + + +// LLIL_LOAD, LLIL_LOAD_SSA +pub struct Load; + +impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Load> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_mem_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } +} + + + +// LLIL_STORE, LLIL_STORE_SSA +pub struct Store; + +impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Store> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_mem_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } + + pub fn source_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[1] as usize, + _ty: PhantomData, + } + } +} + + + +// LLIL_REG, LLIL_REG_SSA, LLIL_REG_SSA_PARTIAL +pub struct Reg; + +impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Reg> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_reg(&self) -> Register<A::Register> { + let raw_id = self.op.operands[0] as u32; + + if raw_id >= 0x8000_0000 { + Register::Temp(raw_id & 0x7fff_ffff) + } else { + self.function.arch().register_from_id(raw_id) + .map(Register::ArchReg) + .unwrap_or_else(|| { + error!("got garbage register from LLIL_REG @ 0x{:x}", + self.op.address); + + Register::Temp(0) + }) + } + } +} + + + +// LLIL_FLAG, LLIL_FLAG_SSA +pub struct Flag; + + + + +// LLIL_FLAG_BIT, LLIL_FLAG_BIT_SSA +pub struct FlagBit; + + + +// LLIL_JUMP +pub struct Jump; + +impl<'func, A, M, F> Operation<'func, A, M, F, Jump> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn target(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } +} + + + +// LLIL_JUMP_TO +pub struct JumpTo; + +impl<'func, A, M, F> Operation<'func, A, M, F, JumpTo> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn target(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } + // TODO target list +} + + + +// LLIL_CALL, LLIL_CALL_SSA +pub struct Call; + +impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Call> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub fn target(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } + + pub fn stack_adjust(&self) -> Option<u64> { + use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CALL_STACK_ADJUST; + + if self.op.operation == LLIL_CALL_STACK_ADJUST { + Some(self.op.operands[1]) + } else { + None + } + } +} + + + +// LLIL_RET +pub struct Ret; + +impl<'func, A, M, F> Operation<'func, A, M, F, Ret> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn target(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } +} + + + +// LLIL_IF +pub struct If; + +impl<'func, A, M, F> Operation<'func, A, M, F, If> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn condition(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } + + pub fn true_target(&self) -> Instruction<'func, A, M, F> { + Instruction { + function: self.function, + instr_idx: self.op.operands[1] as usize, + } + } + + pub fn false_target(&self) -> Instruction<'func, A, M, F> { + Instruction { + function: self.function, + instr_idx: self.op.operands[2] as usize, + } + } +} + + + +// LLIL_GOTO +pub struct Goto; + +impl<'func, A, M, F> Operation<'func, A, M, F, Goto> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn target(&self) -> Instruction<'func, A, M, F> { + Instruction { + function: self.function, + instr_idx: self.op.operands[0] as usize, + } + } +} + + + +// LLIL_FLAG_COND +pub struct FlagCond; + + + +// LLIL_FLAG_GROUP +pub struct FlagGroup; + +impl<'func, A, M> Operation<'func, A, M, NonSSA<LiftedNonSSA>, FlagGroup> +where + A: 'func + Architecture, + M: FunctionMutability, +{ + pub fn flag_group(&self) -> A::FlagGroup { + let id = self.op.operands[0] as u32; + self.function.arch().flag_group_from_id(id).unwrap() + } +} + + + +// LLIL_TRAP +pub struct Trap; + +impl<'func, A, M, F> Operation<'func, A, M, F, Trap> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn vector(&self) -> u64 { + self.op.operands[0] + } +} + + + +// LLIL_REG_PHI +pub struct RegPhi; + + + +// LLIL_FLAG_PHI +pub struct FlagPhi; + + + +// LLIL_MEM_PHI +pub struct MemPhi; + + + +// LLIL_CONST, LLIL_CONST_PTR +pub struct Const; + +impl<'func, A, M, F> Operation<'func, A, M, F, Const> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn value(&self) -> u64 { + #[cfg(debug_assertions)] + { + let raw = self.op.operands[0] as i64; + + let is_safe = match raw.overflowing_shr(self.op.size as u32 * 8) { + (_, true) => true, + (res, false) => [-1, 0].contains(&res), + }; + + if !is_safe { + error!("il expr @ {:x} contains constant 0x{:x} as {} byte value (doesn't fit!)", + self.op.address, self.op.operands[0], self.op.size); + } + } + + let mut mask = -1i64 as u64; + + if self.op.size < mem::size_of::<u64>() { + mask <<= self.op.size * 8; + mask = !mask; + } + + self.op.operands[0] & mask + } +} + + + +// LLIL_ADD, LLIL_SUB, LLIL_AND, LLIL_OR +// LLIL_XOR, LLIL_LSL, LLIL_LSR, LLIL_ASR +// LLIL_ROL, LLIL_ROR, LLIL_MUL, LLIL_MULU_DP, +// LLIL_MULS_DP, LLIL_DIVU, LLIL_DIVS, LLIL_MODU, +// LLIL_MODS +pub struct BinaryOp; + +impl<'func, A, M, F> Operation<'func, A, M, F, BinaryOp> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn left(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } + + pub fn right(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[1] as usize, + _ty: PhantomData, + } + } +} + + + +// LLIL_ADC, LLIL_SBB, LLIL_RLC, LLIL_RRC +pub struct BinaryOpCarry; + +impl<'func, A, M, F> Operation<'func, A, M, F, BinaryOpCarry> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn left(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } + + pub fn right(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[1] as usize, + _ty: PhantomData, + } + } + + pub fn carry(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[2] as usize, + _ty: PhantomData, + } + } +} + + + +// LLIL_DIVS_DP, LLIL_DIVU_DP, LLIL_MODU_DP, LLIL_MODS_DP +pub struct DoublePrecDivOp; + +impl<'func, A, M, F> Operation<'func, A, M, F, DoublePrecDivOp> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn high(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } + + pub fn low(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[1] as usize, + _ty: PhantomData, + } + } + + pub fn right(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[2] as usize, + _ty: PhantomData, + } + } +} + + + +// LLIL_PUSH, LLIL_NEG, LLIL_NOT, LLIL_SX, +// LLIL_ZX, LLIL_LOW_PART, LLIL_BOOL_TO_INT, LLIL_UNIMPL_MEM +pub struct UnaryOp; + +impl<'func, A, M, F> Operation<'func, A, M, F, UnaryOp> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn operand(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } +} + + + +// LLIL_CMP_X +pub struct Condition; + +impl<'func, A, M, F> Operation<'func, A, M, F, Condition> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn left(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } + + pub fn right(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[1] as usize, + _ty: PhantomData, + } + } +} + + +// LLIL_UNIMPL_MEM +pub struct UnimplMem; + +impl<'func, A, M, F> Operation<'func, A, M, F, UnimplMem> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn mem_expr(&self) -> Expression<'func, A, M, F, ValueExpr> { + Expression { + function: self.function, + expr_idx: self.op.operands[0] as usize, + _ty: PhantomData, + } + } +} + +// TODO TEST_BIT + +pub trait OperationArguments: 'static {} + +impl OperationArguments for NoArgs {} +impl OperationArguments for Pop {} +impl OperationArguments for Syscall {} +impl OperationArguments for SetReg {} +impl OperationArguments for SetRegSplit {} +impl OperationArguments for SetFlag {} +impl OperationArguments for Load {} +impl OperationArguments for Store {} +impl OperationArguments for Reg {} +impl OperationArguments for Flag {} +impl OperationArguments for FlagBit {} +impl OperationArguments for Jump {} +impl OperationArguments for JumpTo {} +impl OperationArguments for Call {} +impl OperationArguments for Ret {} +impl OperationArguments for If {} +impl OperationArguments for Goto {} +impl OperationArguments for FlagCond {} +impl OperationArguments for FlagGroup {} +impl OperationArguments for Trap {} +impl OperationArguments for RegPhi {} +impl OperationArguments for FlagPhi {} +impl OperationArguments for MemPhi {} +impl OperationArguments for Const {} +impl OperationArguments for BinaryOp {} +impl OperationArguments for BinaryOpCarry {} +impl OperationArguments for DoublePrecDivOp {} +impl OperationArguments for UnaryOp {} +impl OperationArguments for Condition {} +impl OperationArguments for UnimplMem {} |
