diff options
| author | Rusty Wagner <rusty@vector35.com> | 2017-03-01 03:45:51 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty@vector35.com> | 2017-03-01 03:45:51 -0500 |
| commit | 94b38cee51eff16f1e79945806088c7ae60016d7 (patch) | |
| tree | 4857d8240334f2ec40aa7a46f7fcea6a2e9ed899 | |
| parent | dc0f16fa9bbac0388bb844af8d9f6c3b72ec31e8 (diff) | |
Adding framework for medium level IL
| -rw-r--r-- | binaryninjaapi.h | 70 | ||||
| -rw-r--r-- | binaryninjacore.h | 174 | ||||
| -rw-r--r-- | function.cpp | 12 | ||||
| -rw-r--r-- | lowlevelil.cpp | 6 | ||||
| -rw-r--r-- | mediumlevelil.cpp | 378 | ||||
| -rw-r--r-- | python/__init__.py | 1 | ||||
| -rw-r--r-- | python/function.py | 20 | ||||
| -rw-r--r-- | python/lowlevelil.py | 8 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 525 |
9 files changed, 1179 insertions, 15 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 58ea890e..1367e7c1 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1862,6 +1862,7 @@ namespace BinaryNinja }; class FunctionGraph; + class MediumLevelILFunction; class Function: public CoreRefCountObject<BNFunction, BNNewFunctionReference, BNFreeFunction> { @@ -1913,6 +1914,8 @@ namespace BinaryNinja std::set<uint32_t> GetFlagsReadByLiftedILInstruction(size_t i); std::set<uint32_t> GetFlagsWrittenByLiftedILInstruction(size_t i); + Ref<MediumLevelILFunction> GetMediumLevelIL() const; + Ref<Type> GetType() const; void SetAutoType(Type* type); void SetUserType(Type* type); @@ -2182,6 +2185,73 @@ namespace BinaryNinja RegisterValue GetExprValue(size_t expr); }; + struct MediumLevelILLabel: public BNMediumLevelILLabel + { + MediumLevelILLabel(); + }; + + class MediumLevelILFunction: public CoreRefCountObject<BNMediumLevelILFunction, + BNNewMediumLevelILFunctionReference, BNFreeMediumLevelILFunction> + { + public: + MediumLevelILFunction(Architecture* arch, Function* func = nullptr); + MediumLevelILFunction(BNMediumLevelILFunction* func); + + uint64_t GetCurrentAddress() const; + void SetCurrentAddress(Architecture* arch, uint64_t addr); + size_t GetInstructionStart(Architecture* arch, uint64_t addr); + + ExprId AddExpr(BNMediumLevelILOperation operation, size_t size, + ExprId a = 0, ExprId b = 0, ExprId c = 0, ExprId d = 0, ExprId e = 0); + ExprId AddInstruction(ExprId expr); + + ExprId SetVar(size_t size, const BNILVariable& var, ExprId src); + ExprId SetVarField(size_t size, const BNILVariable& var, int64_t offset, ExprId src); + ExprId SetVarSSA(size_t size, const BNILVariable& var, size_t index, ExprId src); + ExprId SetVarFieldSSA(size_t size, const BNILVariable& var, int64_t offset, size_t varIndex, ExprId src); + ExprId Var(size_t size, const BNILVariable& var); + ExprId VarField(size_t size, const BNILVariable& var, int64_t offset); + ExprId VarSSA(size_t size, const BNILVariable& var, size_t index); + ExprId VarFieldSSA(size_t size, const BNILVariable& var, int64_t offset, size_t varIndex); + + ExprId Goto(BNMediumLevelILLabel& label); + ExprId If(ExprId operand, BNMediumLevelILLabel& t, BNMediumLevelILLabel& f); + void MarkLabel(BNMediumLevelILLabel& label); + + std::vector<uint64_t> GetOperandList(ExprId i, size_t listOperand); + ExprId AddLabelList(const std::vector<BNMediumLevelILLabel*>& labels); + ExprId AddOperandList(const std::vector<ExprId> operands); + + BNILVariable GetVariable(ExprId i, size_t varOperand); + + BNMediumLevelILInstruction operator[](size_t i) const; + size_t GetIndexForInstruction(size_t i) const; + size_t GetInstructionCount() const; + + void Finalize(); + + bool GetExprText(Architecture* arch, ExprId expr, std::vector<InstructionTextToken>& tokens); + bool GetInstructionText(Function* func, Architecture* arch, size_t i, + std::vector<InstructionTextToken>& tokens); + + std::vector<Ref<BasicBlock>> GetBasicBlocks() const; + + Ref<MediumLevelILFunction> GetSSAForm() const; + Ref<MediumLevelILFunction> GetNonSSAForm() const; + size_t GetSSAInstructionIndex(size_t instr) const; + size_t GetNonSSAInstructionIndex(size_t instr) const; + size_t GetSSAExprIndex(size_t instr) const; + size_t GetNonSSAExprIndex(size_t instr) const; + + size_t GetSSAVarDefinition(const BNILVariable& var, size_t idx) const; + size_t GetSSAMemoryDefinition(size_t idx) const; + std::set<size_t> GetSSAVarUses(const BNILVariable& var, size_t idx) const; + std::set<size_t> GetSSAMemoryUses(size_t idx) const; + + RegisterValue GetSSAVarValue(const BNILVariable& var, size_t idx); + RegisterValue GetExprValue(size_t expr); + }; + class FunctionRecognizer { static bool RecognizeLowLevelILCallback(void* ctxt, BNBinaryView* data, BNFunction* func, BNLowLevelILFunction* il); diff --git a/binaryninjacore.h b/binaryninjacore.h index 89302c64..aa9bb49b 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -92,6 +92,7 @@ extern "C" struct BNSymbol; struct BNTemporaryFile; struct BNLowLevelILFunction; + struct BNMediumLevelILFunction; struct BNType; struct BNStructure; struct BNNamedTypeReference; @@ -363,7 +364,9 @@ extern "C" NormalFunctionGraph = 0, LowLevelILFunctionGraph = 1, LiftedILFunctionGraph = 2, - LowLevelILSSAFormFunctionGraph = 3 + LowLevelILSSAFormFunctionGraph = 3, + MediumLevelILFunctionGraph = 4, + MediumLevelILSSAFormFunctionGraph = 5 }; enum BNDisassemblyOption @@ -637,6 +640,115 @@ extern "C" bool autoDiscovered; }; + enum BNMediumLevelILOperation + { + MLIL_NOP, + MLIL_SET_VAR, // Not valid in SSA form (see MLIL_SET_VAR_SSA) + MLIL_SET_VAR_FIELD, // Not valid in SSA form (see MLIL_SET_VAR_FIELD) + MLIL_LOAD, // Not valid in SSA form (see MLIL_LOAD_SSA) + MLIL_STORE, // Not valid in SSA form (see MLIL_STORE_SSA) + MLIL_VAR, // Not valid in SSA form (see MLIL_VAR_SSA) + MLIL_VAR_FIELD, // Not valid in SSA form (see MLIL_VAR_SSA_FIELD) + MLIL_CONST, + MLIL_ADD, + MLIL_ADC, + MLIL_SUB, + MLIL_SBB, + MLIL_AND, + MLIL_OR, + MLIL_XOR, + MLIL_LSL, + MLIL_LSR, + MLIL_ASR, + MLIL_ROL, + MLIL_RLC, + MLIL_ROR, + MLIL_RRC, + MLIL_MUL, + MLIL_MULU_DP, + MLIL_MULS_DP, + MLIL_DIVU, + MLIL_DIVU_DP, + MLIL_DIVS, + MLIL_DIVS_DP, + MLIL_MODU, + MLIL_MODU_DP, + MLIL_MODS, + MLIL_MODS_DP, + MLIL_NEG, + MLIL_NOT, + MLIL_SX, + MLIL_ZX, + MLIL_JUMP, + MLIL_JUMP_TO, + MLIL_CALL, + MLIL_RET, + MLIL_NORET, + MLIL_IF, + MLIL_GOTO, + MLIL_CMP_E, + MLIL_CMP_NE, + MLIL_CMP_SLT, + MLIL_CMP_ULT, + MLIL_CMP_SLE, + MLIL_CMP_ULE, + MLIL_CMP_SGE, + MLIL_CMP_UGE, + MLIL_CMP_SGT, + MLIL_CMP_UGT, + MLIL_TEST_BIT, + MLIL_BOOL_TO_INT, + MLIL_SYSCALL, + MLIL_BP, + MLIL_TRAP, + MLIL_UNDEF, + MLIL_UNIMPL, + MLIL_UNIMPL_MEM, + + // The following instructions are only used in SSA form + MLIL_SET_VAR_SSA, + MLIL_SET_VAR_SSA_FIELD, + MLIL_VAR_SSA, + MLIL_VAR_SSA_FIELD, + MLIL_CALL_SSA, + MLIL_SYSCALL_SSA, + MLIL_CALL_PARAM_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions + MLIL_CALL_OUTPUT_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions + MLIL_LOAD_SSA, + MLIL_STORE_SSA, + MLIL_VAR_PHI, + MLIL_MEM_PHI + }; + + struct BNMediumLevelILInstruction + { + BNMediumLevelILOperation operation; + size_t size; + uint64_t operands[5]; + uint64_t address; + }; + + struct BNMediumLevelILLabel + { + bool resolved; + size_t ref; + size_t operand; + }; + + enum BNILVariableSourceType + { + RegisterVariableSourceType, + FlagVariableSourceType, + StackVariableSourceType + }; + + struct BNILVariable + { + BNILVariableSourceType type; + uint32_t index; + int64_t identifier; + }; + // Callbacks struct BNLogListener { @@ -1698,7 +1810,8 @@ extern "C" BINARYNINJACOREAPI size_t BNGetLowLevelILForInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr); BINARYNINJACOREAPI size_t* BNGetLowLevelILExitsForInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr, size_t* count); - BINARYNINJACOREAPI void BNFreeLowLevelILInstructionList(size_t* list); + BINARYNINJACOREAPI void BNFreeILInstructionList(size_t* list); + BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetFunctionMediumLevelIL(BNFunction* func); BINARYNINJACOREAPI BNRegisterValue BNGetRegisterValueAtInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr, uint32_t reg); BINARYNINJACOREAPI BNRegisterValue BNGetRegisterValueAfterInstruction(BNFunction* func, BNArchitecture* arch, @@ -2043,6 +2156,63 @@ extern "C" BINARYNINJACOREAPI BNRegisterValue BNGetLowLevelILExprValue(BNLowLevelILFunction* func, size_t expr); + // Medium-level IL + BINARYNINJACOREAPI BNMediumLevelILFunction* BNCreateMediumLevelILFunction(BNArchitecture* arch, BNFunction* func); + BINARYNINJACOREAPI BNMediumLevelILFunction* BNNewMediumLevelILFunctionReference(BNMediumLevelILFunction* func); + BINARYNINJACOREAPI void BNFreeMediumLevelILFunction(BNMediumLevelILFunction* func); + BINARYNINJACOREAPI uint64_t BNMediumLevelILGetCurrentAddress(BNMediumLevelILFunction* func); + BINARYNINJACOREAPI void BNMediumLevelILSetCurrentAddress(BNMediumLevelILFunction* func, + BNArchitecture* arch, uint64_t addr); + BINARYNINJACOREAPI size_t BNMediumLevelILGetInstructionStart(BNMediumLevelILFunction* func, + BNArchitecture* arch, uint64_t addr); + BINARYNINJACOREAPI size_t BNMediumLevelILAddExpr(BNMediumLevelILFunction* func, BNMediumLevelILOperation operation, + size_t size, uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e); + BINARYNINJACOREAPI size_t BNMediumLevelILAddInstruction(BNMediumLevelILFunction* func, size_t expr); + BINARYNINJACOREAPI size_t BNMediumLevelILGoto(BNMediumLevelILFunction* func, BNMediumLevelILLabel* label); + BINARYNINJACOREAPI size_t BNMediumLevelILIf(BNMediumLevelILFunction* func, uint64_t op, + BNMediumLevelILLabel* t, BNMediumLevelILLabel* f); + BINARYNINJACOREAPI void BNMediumLevelILInitLabel(BNMediumLevelILLabel* label); + BINARYNINJACOREAPI void BNMediumLevelILMarkLabel(BNMediumLevelILFunction* func, BNMediumLevelILLabel* label); + BINARYNINJACOREAPI void BNFinalizeMediumLevelILFunction(BNMediumLevelILFunction* func); + + BINARYNINJACOREAPI size_t BNMediumLevelILAddLabelList(BNMediumLevelILFunction* func, + BNMediumLevelILLabel** labels, size_t count); + BINARYNINJACOREAPI size_t BNMediumLevelILAddOperandList(BNMediumLevelILFunction* func, + uint64_t* operands, size_t count); + BINARYNINJACOREAPI uint64_t* BNMediumLevelILGetOperandList(BNMediumLevelILFunction* func, size_t expr, + size_t operand, size_t* count); + BINARYNINJACOREAPI void BNMediumLevelILFreeOperandList(uint64_t* operands); + + BINARYNINJACOREAPI BNMediumLevelILInstruction BNGetMediumLevelILByIndex(BNMediumLevelILFunction* func, size_t i); + BINARYNINJACOREAPI size_t BNGetMediumLevelILIndexForInstruction(BNMediumLevelILFunction* func, size_t i); + BINARYNINJACOREAPI size_t BNGetMediumLevelILInstructionCount(BNMediumLevelILFunction* func); + + BINARYNINJACOREAPI bool BNGetMediumLevelILExprText(BNMediumLevelILFunction* func, BNArchitecture* arch, size_t i, + BNInstructionTextToken** tokens, size_t* count); + BINARYNINJACOREAPI bool BNGetMediumLevelILInstructionText(BNMediumLevelILFunction* il, BNFunction* func, + BNArchitecture* arch, size_t i, BNInstructionTextToken** tokens, size_t* count); + + BINARYNINJACOREAPI BNBasicBlock** BNGetMediumLevelILBasicBlockList(BNMediumLevelILFunction* func, size_t* count); + + BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetMediumLevelILSSAForm(BNMediumLevelILFunction* func); + BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetMediumLevelILNonSSAForm(BNMediumLevelILFunction* func); + BINARYNINJACOREAPI size_t BNGetMediumLevelILSSAInstructionIndex(BNMediumLevelILFunction* func, size_t instr); + BINARYNINJACOREAPI size_t BNGetMediumLevelILNonSSAInstructionIndex(BNMediumLevelILFunction* func, size_t instr); + BINARYNINJACOREAPI size_t BNGetMediumLevelILSSAExprIndex(BNMediumLevelILFunction* func, size_t expr); + BINARYNINJACOREAPI size_t BNGetMediumLevelILNonSSAExprIndex(BNMediumLevelILFunction* func, size_t expr); + + BINARYNINJACOREAPI size_t BNGetMediumLevelILSSAVarDefinition(BNMediumLevelILFunction* func, + const BNILVariable* var, size_t idx); + BINARYNINJACOREAPI size_t BNGetMediumLevelILSSAMemoryDefinition(BNMediumLevelILFunction* func, size_t idx); + BINARYNINJACOREAPI size_t* BNGetMediumLevelILSSAVarUses(BNMediumLevelILFunction* func, const BNILVariable* var, + size_t idx, size_t* count); + BINARYNINJACOREAPI size_t* BNGetMediumLevelILSSAMemoryUses(BNMediumLevelILFunction* func, + size_t idx, size_t* count); + + BINARYNINJACOREAPI BNRegisterValue BNGetMediumLevelILSSAVarValue(BNMediumLevelILFunction* func, + const BNILVariable* var, size_t idx); + BINARYNINJACOREAPI BNRegisterValue BNGetMediumLevelILExprValue(BNMediumLevelILFunction* func, size_t expr); + // Types BINARYNINJACOREAPI BNType* BNCreateVoidType(void); BINARYNINJACOREAPI BNType* BNCreateBoolType(void); diff --git a/function.cpp b/function.cpp index fe119c9d..9faf68fa 100644 --- a/function.cpp +++ b/function.cpp @@ -161,7 +161,7 @@ vector<size_t> Function::GetLowLevelILExitsForInstruction(Architecture* arch, ui vector<size_t> result; result.insert(result.end(), exits, &exits[count]); - BNFreeLowLevelILInstructionList(exits); + BNFreeILInstructionList(exits); return result; } @@ -343,7 +343,7 @@ set<size_t> Function::GetLiftedILFlagUsesForDefinition(size_t i, uint32_t flag) set<size_t> result; result.insert(&instrs[0], &instrs[count]); - BNFreeLowLevelILInstructionList(instrs); + BNFreeILInstructionList(instrs); return result; } @@ -355,7 +355,7 @@ set<size_t> Function::GetLiftedILFlagDefinitionsForUse(size_t i, uint32_t flag) set<size_t> result; result.insert(&instrs[0], &instrs[count]); - BNFreeLowLevelILInstructionList(instrs); + BNFreeILInstructionList(instrs); return result; } @@ -384,6 +384,12 @@ set<uint32_t> Function::GetFlagsWrittenByLiftedILInstruction(size_t i) } +Ref<MediumLevelILFunction> Function::GetMediumLevelIL() const +{ + return new MediumLevelILFunction(BNGetFunctionMediumLevelIL(m_object)); +} + + Ref<Type> Function::GetType() const { return new Type(BNGetFunctionType(m_object)); diff --git a/lowlevelil.cpp b/lowlevelil.cpp index fecde9c8..5a789981 100644 --- a/lowlevelil.cpp +++ b/lowlevelil.cpp @@ -720,7 +720,7 @@ set<size_t> LowLevelILFunction::GetSSARegisterUses(uint32_t reg, size_t idx) con for (size_t i = 0; i < count; i++) result.insert(instrs[i]); - BNFreeLowLevelILInstructionList(instrs); + BNFreeILInstructionList(instrs); return result; } @@ -734,7 +734,7 @@ set<size_t> LowLevelILFunction::GetSSAFlagUses(uint32_t flag, size_t idx) const for (size_t i = 0; i < count; i++) result.insert(instrs[i]); - BNFreeLowLevelILInstructionList(instrs); + BNFreeILInstructionList(instrs); return result; } @@ -748,7 +748,7 @@ set<size_t> LowLevelILFunction::GetSSAMemoryUses(size_t idx) const for (size_t i = 0; i < count; i++) result.insert(instrs[i]); - BNFreeLowLevelILInstructionList(instrs); + BNFreeILInstructionList(instrs); return result; } diff --git a/mediumlevelil.cpp b/mediumlevelil.cpp new file mode 100644 index 00000000..f6ad5bfd --- /dev/null +++ b/mediumlevelil.cpp @@ -0,0 +1,378 @@ +// Copyright (c) 2017 Vector 35 LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace std; + + +MediumLevelILLabel::MediumLevelILLabel() +{ + BNMediumLevelILInitLabel(this); +} + + +MediumLevelILFunction::MediumLevelILFunction(Architecture* arch, Function* func) +{ + m_object = BNCreateMediumLevelILFunction(arch->GetObject(), func ? func->GetObject() : nullptr); +} + + +MediumLevelILFunction::MediumLevelILFunction(BNMediumLevelILFunction* func) +{ + m_object = func; +} + + +uint64_t MediumLevelILFunction::GetCurrentAddress() const +{ + return BNMediumLevelILGetCurrentAddress(m_object); +} + + +void MediumLevelILFunction::SetCurrentAddress(Architecture* arch, uint64_t addr) +{ + BNMediumLevelILSetCurrentAddress(m_object, arch ? arch->GetObject() : nullptr, addr); +} + + +size_t MediumLevelILFunction::GetInstructionStart(Architecture* arch, uint64_t addr) +{ + return BNMediumLevelILGetInstructionStart(m_object, arch ? arch->GetObject() : nullptr, addr); +} + + +ExprId MediumLevelILFunction::AddExpr(BNMediumLevelILOperation operation, size_t size, + ExprId a, ExprId b, ExprId c, ExprId d, ExprId e) +{ + return BNMediumLevelILAddExpr(m_object, operation, size, a, b, c, d, e); +} + + +ExprId MediumLevelILFunction::AddInstruction(size_t expr) +{ + return BNMediumLevelILAddInstruction(m_object, expr); +} + + +ExprId MediumLevelILFunction::SetVar(size_t size, const BNILVariable& var, ExprId src) +{ + return AddExpr(MLIL_SET_VAR, size, ((uint64_t)var.type << 32) | (uint64_t)var.index, var.identifier, src); +} + + +ExprId MediumLevelILFunction::SetVarField(size_t size, const BNILVariable& var, int64_t offset, ExprId src) +{ + return AddExpr(MLIL_SET_VAR_FIELD, size, ((uint64_t)var.type << 32) | (uint64_t)var.index, var.identifier, + offset, src); +} + + +ExprId MediumLevelILFunction::SetVarSSA(size_t size, const BNILVariable& var, size_t varIndex, ExprId src) +{ + return AddExpr(MLIL_SET_VAR_SSA, size, ((uint64_t)var.type << 32) | (uint64_t)var.index, var.identifier, + varIndex, src); +} + + +ExprId MediumLevelILFunction::SetVarFieldSSA(size_t size, const BNILVariable& var, int64_t offset, + size_t varIndex, ExprId src) +{ + return AddExpr(MLIL_SET_VAR_SSA_FIELD, size, ((uint64_t)var.type << 32) | (uint64_t)var.index, var.identifier, + offset, varIndex, src); +} + + +ExprId MediumLevelILFunction::Var(size_t size, const BNILVariable& var) +{ + return AddExpr(MLIL_VAR, size, ((uint64_t)var.type << 32) | (uint64_t)var.index, var.identifier); +} + + +ExprId MediumLevelILFunction::VarField(size_t size, const BNILVariable& var, int64_t offset) +{ + return AddExpr(MLIL_VAR_FIELD, size, ((uint64_t)var.type << 32) | (uint64_t)var.index, var.identifier, offset); +} + + +ExprId MediumLevelILFunction::VarSSA(size_t size, const BNILVariable& var, size_t varIndex) +{ + return AddExpr(MLIL_VAR_SSA, size, ((uint64_t)var.type << 32) | (uint64_t)var.index, var.identifier, varIndex); +} + + +ExprId MediumLevelILFunction::VarFieldSSA(size_t size, const BNILVariable& var, int64_t offset, + size_t varIndex) +{ + return AddExpr(MLIL_VAR_SSA_FIELD, size, ((uint64_t)var.type << 32) | (uint64_t)var.index, var.identifier, + offset, varIndex); +} + + +ExprId MediumLevelILFunction::Goto(BNMediumLevelILLabel& label) +{ + return BNMediumLevelILGoto(m_object, &label); +} + + +ExprId MediumLevelILFunction::If(ExprId operand, BNMediumLevelILLabel& t, BNMediumLevelILLabel& f) +{ + return BNMediumLevelILIf(m_object, operand, &t, &f); +} + + +void MediumLevelILFunction::MarkLabel(BNMediumLevelILLabel& label) +{ + BNMediumLevelILMarkLabel(m_object, &label); +} + + +vector<uint64_t> MediumLevelILFunction::GetOperandList(ExprId expr, size_t listOperand) +{ + size_t count; + uint64_t* operands = BNMediumLevelILGetOperandList(m_object, expr, listOperand, &count); + vector<uint64_t> result; + for (size_t i = 0; i < count; i++) + result.push_back(operands[i]); + BNMediumLevelILFreeOperandList(operands); + return result; +} + + +ExprId MediumLevelILFunction::AddLabelList(const vector<BNMediumLevelILLabel*>& labels) +{ + BNMediumLevelILLabel** labelList = new BNMediumLevelILLabel*[labels.size()]; + for (size_t i = 0; i < labels.size(); i++) + labelList[i] = labels[i]; + ExprId result = (ExprId)BNMediumLevelILAddLabelList(m_object, labelList, labels.size()); + delete[] labelList; + return result; +} + + +ExprId MediumLevelILFunction::AddOperandList(const vector<ExprId> operands) +{ + uint64_t* operandList = new uint64_t[operands.size()]; + for (size_t i = 0; i < operands.size(); i++) + operandList[i] = operands[i]; + ExprId result = (ExprId)BNMediumLevelILAddOperandList(m_object, operandList, operands.size()); + delete[] operandList; + return result; +} + + +BNILVariable MediumLevelILFunction::GetVariable(ExprId i, size_t varOperand) +{ + BNMediumLevelILInstruction instr = (*this)[i]; + BNILVariable result; + result.type = (BNILVariableSourceType)(instr.operands[varOperand] >> 32); + result.index = (uint32_t)instr.operands[varOperand]; + result.identifier = instr.operands[varOperand + 1]; + return result; +} + + +BNMediumLevelILInstruction MediumLevelILFunction::operator[](size_t i) const +{ + return BNGetMediumLevelILByIndex(m_object, i); +} + + +size_t MediumLevelILFunction::GetIndexForInstruction(size_t i) const +{ + return BNGetMediumLevelILIndexForInstruction(m_object, i); +} + + +size_t MediumLevelILFunction::GetInstructionCount() const +{ + return BNGetMediumLevelILInstructionCount(m_object); +} + + +void MediumLevelILFunction::Finalize() +{ + BNFinalizeMediumLevelILFunction(m_object); +} + + +bool MediumLevelILFunction::GetExprText(Architecture* arch, ExprId expr, vector<InstructionTextToken>& tokens) +{ + size_t count; + BNInstructionTextToken* list; + if (!BNGetMediumLevelILExprText(m_object, arch->GetObject(), expr, &list, &count)) + return false; + + tokens.clear(); + for (size_t i = 0; i < count; i++) + { + InstructionTextToken token; + token.type = list[i].type; + token.text = list[i].text; + token.value = list[i].value; + token.size = list[i].size; + token.operand = list[i].operand; + token.context = list[i].context; + token.address = list[i].address; + tokens.push_back(token); + } + + BNFreeInstructionText(list, count); + return true; +} + + +bool MediumLevelILFunction::GetInstructionText(Function* func, Architecture* arch, size_t instr, + vector<InstructionTextToken>& tokens) +{ + size_t count; + BNInstructionTextToken* list; + if (!BNGetMediumLevelILInstructionText(m_object, func ? func->GetObject() : nullptr, arch->GetObject(), + instr, &list, &count)) + return false; + + tokens.clear(); + for (size_t i = 0; i < count; i++) + { + InstructionTextToken token; + token.type = list[i].type; + token.text = list[i].text; + token.value = list[i].value; + token.size = list[i].size; + token.operand = list[i].operand; + token.context = list[i].context; + token.address = list[i].address; + tokens.push_back(token); + } + + BNFreeInstructionText(list, count); + return true; +} + + +vector<Ref<BasicBlock>> MediumLevelILFunction::GetBasicBlocks() const +{ + size_t count; + BNBasicBlock** blocks = BNGetMediumLevelILBasicBlockList(m_object, &count); + + vector<Ref<BasicBlock>> result; + for (size_t i = 0; i < count; i++) + result.push_back(new BasicBlock(BNNewBasicBlockReference(blocks[i]))); + + BNFreeBasicBlockList(blocks, count); + return result; +} + + +Ref<MediumLevelILFunction> MediumLevelILFunction::GetSSAForm() const +{ + BNMediumLevelILFunction* func = BNGetMediumLevelILSSAForm(m_object); + if (!func) + return nullptr; + return new MediumLevelILFunction(func); +} + + +Ref<MediumLevelILFunction> MediumLevelILFunction::GetNonSSAForm() const +{ + BNMediumLevelILFunction* func = BNGetMediumLevelILNonSSAForm(m_object); + if (!func) + return nullptr; + return new MediumLevelILFunction(func); +} + + +size_t MediumLevelILFunction::GetSSAInstructionIndex(size_t instr) const +{ + return BNGetMediumLevelILSSAInstructionIndex(m_object, instr); +} + + +size_t MediumLevelILFunction::GetNonSSAInstructionIndex(size_t instr) const +{ + return BNGetMediumLevelILNonSSAInstructionIndex(m_object, instr); +} + + +size_t MediumLevelILFunction::GetSSAExprIndex(size_t expr) const +{ + return BNGetMediumLevelILSSAExprIndex(m_object, expr); +} + + +size_t MediumLevelILFunction::GetNonSSAExprIndex(size_t expr) const +{ + return BNGetMediumLevelILNonSSAExprIndex(m_object, expr); +} + + +size_t MediumLevelILFunction::GetSSAVarDefinition(const BNILVariable& var, size_t idx) const +{ + return BNGetMediumLevelILSSAVarDefinition(m_object, &var, idx); +} + + +size_t MediumLevelILFunction::GetSSAMemoryDefinition(size_t idx) const +{ + return BNGetMediumLevelILSSAMemoryDefinition(m_object, idx); +} + + +set<size_t> MediumLevelILFunction::GetSSAVarUses(const BNILVariable& var, size_t idx) const +{ + size_t count; + size_t* instrs = BNGetMediumLevelILSSAVarUses(m_object, &var, idx, &count); + + set<size_t> result; + for (size_t i = 0; i < count; i++) + result.insert(instrs[i]); + + BNFreeILInstructionList(instrs); + return result; +} + + +set<size_t> MediumLevelILFunction::GetSSAMemoryUses(size_t idx) const +{ + size_t count; + size_t* instrs = BNGetMediumLevelILSSAMemoryUses(m_object, idx, &count); + + set<size_t> result; + for (size_t i = 0; i < count; i++) + result.insert(instrs[i]); + + BNFreeILInstructionList(instrs); + return result; +} + + +RegisterValue MediumLevelILFunction::GetSSAVarValue(const BNILVariable& var, size_t idx) +{ + BNRegisterValue value = BNGetMediumLevelILSSAVarValue(m_object, &var, idx); + return RegisterValue::FromAPIObject(value); +} + + +RegisterValue MediumLevelILFunction::GetExprValue(size_t expr) +{ + BNRegisterValue value = BNGetMediumLevelILExprValue(m_object, expr); + return RegisterValue::FromAPIObject(value); +} diff --git a/python/__init__.py b/python/__init__.py index b1f5cd08..7502d205 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -32,6 +32,7 @@ from .basicblock import * from .function import * from .log import * from .lowlevelil import * +from .mediumlevelil import * from .types import * from .functionrecognizer import * from .update import * diff --git a/python/function.py b/python/function.py index 07187080..ed2a537c 100644 --- a/python/function.py +++ b/python/function.py @@ -33,6 +33,7 @@ import associateddatastore import types import basicblock import lowlevelil +import mediumlevelil import binaryview import log @@ -139,6 +140,14 @@ class StackVariableReference(object): return "<operand %d ref to %s>" % (self.source_operand, self.name) +class ILVariable(object): + def __init__(self, func, var_type, index, identifier): + self.function = func + self.type = var_type + self.index = index + self.identifier = identifier + + class ConstantReference(object): def __init__(self, val, size): self.value = val @@ -300,6 +309,11 @@ class Function(object): return lowlevelil.LowLevelILFunction(self.arch, core.BNGetFunctionLiftedIL(self.handle), self) @property + def medium_level_il(self): + """Function medium level IL (read-only)""" + return mediumlevelil.MediumLevelILFunction(self.arch, core.BNGetFunctionMediumLevelIL(self.handle), self) + + @property def function_type(self): """Function type object""" return types.Type(core.BNGetFunctionType(self.handle)) @@ -398,7 +412,7 @@ class Function(object): result = [] for i in xrange(0, count.value): result.append(exits[i]) - core.BNFreeLowLevelILInstructionList(exits) + core.BNFreeILInstructionList(exits) return result def get_reg_value_at(self, addr, reg, arch=None): @@ -597,7 +611,7 @@ class Function(object): result = [] for i in xrange(0, count.value): result.append(instrs[i]) - core.BNFreeLowLevelILInstructionList(instrs) + core.BNFreeILInstructionList(instrs) return result def get_lifted_il_flag_definitions_for_use(self, i, flag): @@ -608,7 +622,7 @@ class Function(object): result = [] for i in xrange(0, count.value): result.append(instrs[i]) - core.BNFreeLowLevelILInstructionList(instrs) + core.BNFreeILInstructionList(instrs) return result def get_flags_read_by_lifted_il_instruction(self, i): diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 6ed179c2..ed1cedd4 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -124,7 +124,7 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_SYSCALL_SSA: [("output", "expr"), ("stack", "expr"), ("param", "expr")], LowLevelILOperation.LLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "reg_ssa_list")], LowLevelILOperation.LLIL_CALL_STACK_SSA: [("src", "reg"), ("index", "int"), ("src_memory", "int")], - LowLevelILOperation.LLIL_CALL_PARAM_SSA: [("dest", "reg_ssa_list")], + LowLevelILOperation.LLIL_CALL_PARAM_SSA: [("src", "reg_ssa_list")], LowLevelILOperation.LLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")], LowLevelILOperation.LLIL_STORE_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")], LowLevelILOperation.LLIL_REG_PHI: [("dest", "reg"), ("index", "int"), ("src", "reg_ssa_list")], @@ -1385,7 +1385,7 @@ class LowLevelILFunction(object): result = [] for i in xrange(0, count.value): result.append(instrs[i]) - core.BNFreeLowLevelILInstructionList(instrs) + core.BNFreeILInstructionList(instrs) return result def get_ssa_flag_uses(self, flag, index): @@ -1394,7 +1394,7 @@ class LowLevelILFunction(object): result = [] for i in xrange(0, count.value): result.append(instrs[i]) - core.BNFreeLowLevelILInstructionList(instrs) + core.BNFreeILInstructionList(instrs) return result def get_ssa_memory_uses(self, index): @@ -1403,7 +1403,7 @@ class LowLevelILFunction(object): result = [] for i in xrange(0, count.value): result.append(instrs[i]) - core.BNFreeLowLevelILInstructionList(instrs) + core.BNFreeILInstructionList(instrs) return result def get_ssa_reg_value(self, reg, index): diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py new file mode 100644 index 00000000..c4c4aa23 --- /dev/null +++ b/python/mediumlevelil.py @@ -0,0 +1,525 @@ +# Copyright (c) 2017 Vector 35 LLC +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import ctypes + +# Binary Ninja components +import _binaryninjacore as core +from .enums import MediumLevelILOperation, InstructionTextTokenType, ILVariableSourceType +import function +import basicblock + + +class MediumLevelILLabel(object): + def __init__(self, handle = None): + if handle is None: + self.handle = (core.BNMediumLevelILLabel * 1)() + core.BNMediumLevelILInitLabel(self.handle) + else: + self.handle = handle + + +class MediumLevelILInstruction(object): + """ + ``class MediumLevelILInstruction`` Medium Level Intermediate Language Instructions are infinite length tree-based + instructions. Tree-based instructions use infix notation with the left hand operand being the destination operand. + Infix notation is thus more natural to read than other notations (e.g. x86 ``mov eax, 0`` vs. MLIL ``eax = 0``). + """ + + ILOperations = { + MediumLevelILOperation.MLIL_NOP: [], + MediumLevelILOperation.MLIL_SET_VAR: [("dest", "var"), ("src", "expr")], + MediumLevelILOperation.MLIL_SET_VAR_FIELD: [("dest", "var"), ("offset", "int"), ("src", "expr")], + MediumLevelILOperation.MLIL_LOAD: [("src", "expr")], + MediumLevelILOperation.MLIL_STORE: [("dest", "expr"), ("src", "expr")], + MediumLevelILOperation.MLIL_VAR: [("src", "var")], + MediumLevelILOperation.MLIL_VAR_FIELD: [("src", "var"), ("offset", "int")], + MediumLevelILOperation.MLIL_CONST: [("constant", "int")], + MediumLevelILOperation.MLIL_ADD: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_ADC: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_SUB: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_SBB: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_AND: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_OR: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_XOR: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_LSL: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_LSR: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_ASR: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_ROL: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_RLC: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_ROR: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_RRC: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MUL: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MULU_DP: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MULS_DP: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_DIVU: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_DIVU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_DIVS: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_DIVS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MODU: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MODU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MODS: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MODS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_NEG: [("src", "expr")], + MediumLevelILOperation.MLIL_NOT: [("src", "expr")], + MediumLevelILOperation.MLIL_SX: [("src", "expr")], + MediumLevelILOperation.MLIL_ZX: [("src", "expr")], + MediumLevelILOperation.MLIL_JUMP: [("dest", "expr")], + MediumLevelILOperation.MLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")], + MediumLevelILOperation.MLIL_CALL: [("dest", "expr")], + MediumLevelILOperation.MLIL_RET: [], + MediumLevelILOperation.MLIL_NORET: [], + MediumLevelILOperation.MLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")], + MediumLevelILOperation.MLIL_GOTO: [("dest", "int")], + MediumLevelILOperation.MLIL_CMP_E: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_NE: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_SLT: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_ULT: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_SLE: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_ULE: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_SGE: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_UGE: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_SGT: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_CMP_UGT: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_TEST_BIT: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_BOOL_TO_INT: [("src", "expr")], + MediumLevelILOperation.MLIL_SYSCALL: [], + MediumLevelILOperation.MLIL_BP: [], + MediumLevelILOperation.MLIL_TRAP: [("vector", "int")], + MediumLevelILOperation.MLIL_UNDEF: [], + MediumLevelILOperation.MLIL_UNIMPL: [], + MediumLevelILOperation.MLIL_UNIMPL_MEM: [("src", "expr")], + MediumLevelILOperation.MLIL_SET_VAR_SSA: [("dest", "var"), ("index", "int"), ("src", "expr")], + MediumLevelILOperation.MLIL_SET_VAR_SSA_FIELD: [("dest", "var"), ("index", "int"), ("offset", "int"), ("src", "expr")], + MediumLevelILOperation.MLIL_VAR_SSA: [("src", "var"), ("index", "int")], + MediumLevelILOperation.MLIL_VAR_SSA_FIELD: [("src", "var"), ("index", "int"), ("offset", "int")], + MediumLevelILOperation.MLIL_CALL_SSA: [("output", "expr"), ("dest", "expr"), ("param", "expr")], + MediumLevelILOperation.MLIL_SYSCALL_SSA: [("output", "expr"), ("param", "expr")], + MediumLevelILOperation.MLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "var_ssa_list")], + MediumLevelILOperation.MLIL_CALL_PARAM_SSA: [("src", "var_ssa_list")], + MediumLevelILOperation.MLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")], + MediumLevelILOperation.MLIL_STORE_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")], + MediumLevelILOperation.MLIL_VAR_PHI: [("dest", "var"), ("index", "int"), ("src", "var_ssa_list")], + MediumLevelILOperation.MLIL_MEM_PHI: [("dest_memory", "int"), ("src_memory", "int_list")] + } + + def __init__(self, func, expr_index, instr_index=None): + instr = core.BNGetMediumLevelILByIndex(func.handle, expr_index) + self.function = func + self.expr_index = expr_index + self.instr_index = instr_index + self.operation = MediumLevelILOperation(instr.operation) + self.size = instr.size + self.address = instr.address + operands = MediumLevelILInstruction.ILOperations[instr.operation] + self.operands = [] + i = 0 + while i < len(operands): + name, operand_type = operands[i] + if operand_type == "int": + value = instr.operands[i] + elif operand_type == "expr": + value = MediumLevelILInstruction(func, instr.operands[i]) + elif operand_type == "var": + var_type = ILVariableSourceType(instr.operands[i] >> 32) + index = instr.operands[i] & 0xffffffff + identifier = instr.operands[i + 1] + i += 1 + value = function.ILVariable(self.function, var_type, index, identifier) + elif operand_type == "int_list": + count = ctypes.c_ulonglong() + operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count) + value = [] + for i in xrange(count.value): + value.append(operand_list[i]) + core.BNMediumLevelILFreeOperandList(operand_list) + elif operand_type == "var_ssa_list": + count = ctypes.c_ulonglong() + operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = [] + for j in xrange(count.value / 3): + var_type = ILVariableSourceType(operand_list[j * 3] >> 32) + index = operand_list[j * 3] & 0xffffffff + identifier = operand_list[(j * 3) + 1] + var_index = operand_list[(j * 3) + 2] + value.append((function.ILVariable(self.function, var_type, index, identifier), var_index)) + core.BNMediumLevelILFreeOperandList(operand_list) + self.operands.append(value) + self.__dict__[name] = value + + def __str__(self): + tokens = self.tokens + if tokens is None: + return "invalid" + result = "" + for token in tokens: + result += token.text + return result + + def __repr__(self): + return "<il: %s>" % str(self) + + @property + def tokens(self): + """MLIL tokens (read-only)""" + count = ctypes.c_ulonglong() + tokens = ctypes.POINTER(core.BNInstructionTextToken)() + if (self.instr_index is not None) and (self.function.source_function is not None): + if not core.BNGetMediumLevelILInstructionText(self.function.handle, self.function.source_function.handle, + self.function.arch.handle, self.instr_index, tokens, count): + return None + else: + if not core.BNGetMediumLevelILExprText(self.function.handle, self.function.arch.handle, + self.expr_index, tokens, count): + return None + result = [] + for i in xrange(0, count.value): + token_type = InstructionTextTokenType(tokens[i].type) + text = tokens[i].text + value = tokens[i].value + size = tokens[i].size + operand = tokens[i].operand + context = tokens[i].context + address = tokens[i].address + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) + core.BNFreeInstructionText(tokens, count.value) + return result + + @property + def ssa_form(self): + """SSA form of expression (read-only)""" + return MediumLevelILInstruction(self.function.ssa_form, + core.BNGetMediumLevelILSSAExprIndex(self.function.handle, self.expr_index)) + + @property + def non_ssa_form(self): + """Non-SSA form of expression (read-only)""" + return MediumLevelILInstruction(self.function.non_ssa_form, + core.BNGetMediumLevelILNonSSAExprIndex(self.function.handle, self.expr_index)) + + @property + def value(self): + """Value of expression using static data flow analysis (read-only)""" + value = core.BNGetMediumLevelILExprValue(self.function.handle, self.expr_index) + result = function.RegisterValue(self.function.arch, value) + core.BNFreeRegisterValue(value) + return result + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + +class MediumLevelILExpr(object): + """ + ``class MediumLevelILExpr`` hold the index of IL Expressions. + + .. note:: This class shouldn't be instantiated directly. Rather the helper members of MediumLevelILFunction should be \ + used instead. + """ + def __init__(self, index): + self.index = index + + +class MediumLevelILFunction(object): + """ + ``class MediumLevelILFunction`` contains the list of MediumLevelILExpr objects that make up a function. MediumLevelILExpr + objects can be added to the MediumLevelILFunction by calling ``append`` and passing the result of the various class + methods which return MediumLevelILExpr objects. + """ + def __init__(self, arch, handle = None, source_func = None): + self.arch = arch + self.source_function = source_func + if handle is not None: + self.handle = core.handle_of_type(handle, core.BNMediumLevelILFunction) + else: + func_handle = None + if self.source_function is not None: + func_handle = self.source_function.handle + self.handle = core.BNCreateMediumLevelILFunction(arch.handle, func_handle) + + def __del__(self): + core.BNFreeMediumLevelILFunction(self.handle) + + def __eq__(self, value): + if not isinstance(value, MediumLevelILFunction): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, MediumLevelILFunction): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + + @property + def current_address(self): + """Current IL Address (read/write)""" + return core.BNMediumLevelILGetCurrentAddress(self.handle) + + @current_address.setter + def current_address(self, value): + core.BNMediumLevelILSetCurrentAddress(self.handle, self.arch.handle, value) + + def set_current_address(self, value, arch = None): + if arch is None: + arch = self.arch + core.BNMediumLevelILSetCurrentAddress(self.handle, arch.handle, value) + + @property + def basic_blocks(self): + """list of MediumLevelILBasicBlock objects (read-only)""" + count = ctypes.c_ulonglong() + blocks = core.BNGetMediumLevelILBasicBlockList(self.handle, count) + result = [] + view = None + if self.source_function is not None: + view = self.source_function.view + for i in xrange(0, count.value): + result.append(MediumLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self)) + core.BNFreeBasicBlockList(blocks, count.value) + return result + + @property + def ssa_form(self): + """Medium level IL in SSA form (read-only)""" + result = core.BNGetMediumLevelILSSAForm(self.handle) + if not result: + return None + return MediumLevelILFunction(self.arch, result, self.source_function) + + @property + def non_ssa_form(self): + """Medium level IL in non-SSA (default) form (read-only)""" + result = core.BNGetMediumLevelILNonSSAForm(self.handle) + if not result: + return None + return MediumLevelILFunction(self.arch, result, self.source_function) + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + def __len__(self): + return int(core.BNGetMediumLevelILInstructionCount(self.handle)) + + def __getitem__(self, i): + if isinstance(i, slice) or isinstance(i, tuple): + raise IndexError("expected integer instruction index") + if isinstance(i, MediumLevelILExpr): + return MediumLevelILInstruction(self, i.index) + if (i < 0) or (i >= len(self)): + raise IndexError("index out of range") + return MediumLevelILInstruction(self, core.BNGetMediumLevelILIndexForInstruction(self.handle, i), i) + + def __setitem__(self, i, j): + raise IndexError("instruction modification not implemented") + + def __iter__(self): + count = ctypes.c_ulonglong() + blocks = core.BNGetMediumLevelILBasicBlockList(self.handle, count) + view = None + if self.source_function is not None: + view = self.source_function.view + try: + for i in xrange(0, count.value): + yield MediumLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self) + finally: + core.BNFreeBasicBlockList(blocks, count.value) + + def get_instruction_start(self, addr, arch = None): + if arch is None: + arch = self.arch + result = core.BNMediumLevelILGetInstructionStart(self.handle, arch.handle, addr) + if result >= core.BNGetMediumLevelILInstructionCount(self.handle): + return None + return result + + def expr(self, operation, a = 0, b = 0, c = 0, d = 0, e = 0, size = 0): + if isinstance(operation, str): + operation = MediumLevelILOperation[operation] + elif isinstance(operation, MediumLevelILOperation): + operation = operation.value + return MediumLevelILExpr(core.BNMediumLevelILAddExpr(self.handle, operation, size, a, b, c, d, e)) + + def append(self, expr): + """ + ``append`` adds the MediumLevelILExpr ``expr`` to the current MediumLevelILFunction. + + :param MediumLevelILExpr expr: the MediumLevelILExpr to add to the current MediumLevelILFunction + :return: number of MediumLevelILExpr in the current function + :rtype: int + """ + return core.BNMediumLevelILAddInstruction(self.handle, expr.index) + + def goto(self, label): + """ + ``goto`` returns a goto expression which jumps to the provided MediumLevelILLabel. + + :param MediumLevelILLabel label: Label to jump to + :return: the MediumLevelILExpr that jumps to the provided label + :rtype: MediumLevelILExpr + """ + return MediumLevelILExpr(core.BNMediumLevelILGoto(self.handle, label.handle)) + + def if_expr(self, operand, t, f): + """ + ``if_expr`` returns the ``if`` expression which depending on condition ``operand`` jumps to the MediumLevelILLabel + ``t`` when the condition expression ``operand`` is non-zero and ``f`` when it's zero. + + :param MediumLevelILExpr operand: comparison expression to evaluate. + :param MediumLevelILLabel t: Label for the true branch + :param MediumLevelILLabel f: Label for the false branch + :return: the MediumLevelILExpr for the if expression + :rtype: MediumLevelILExpr + """ + return MediumLevelILExpr(core.BNMediumLevelILIf(self.handle, operand.index, t.handle, f.handle)) + + def mark_label(self, label): + """ + ``mark_label`` assigns a MediumLevelILLabel to the current IL address. + + :param MediumLevelILLabel label: + :rtype: None + """ + core.BNMediumLevelILMarkLabel(self.handle, label.handle) + + def add_label_list(self, labels): + """ + ``add_label_list`` returns a label list expression for the given list of MediumLevelILLabel objects. + + :param list(MediumLevelILLabel) lables: the list of MediumLevelILLabel to get a label list expression from + :return: the label list expression + :rtype: MediumLevelILExpr + """ + label_list = (ctypes.POINTER(core.BNMediumLevelILLabel) * len(labels))() + for i in xrange(len(labels)): + label_list[i] = labels[i].handle + return MediumLevelILExpr(core.BNMediumLevelILAddLabelList(self.handle, label_list, len(labels))) + + def add_operand_list(self, operands): + """ + ``add_operand_list`` returns an operand list expression for the given list of integer operands. + + :param list(int) operands: list of operand numbers + :return: an operand list expression + :rtype: MediumLevelILExpr + """ + operand_list = (ctypes.c_ulonglong * len(operands))() + for i in xrange(len(operands)): + operand_list[i] = operands[i] + return MediumLevelILExpr(core.BNMediumLevelILAddOperandList(self.handle, operand_list, len(operands))) + + def operand(self, n, expr): + """ + ``operand`` sets the operand number of the expression ``expr`` and passes back ``expr`` without modification. + + :param int n: + :param MediumLevelILExpr expr: + :return: returns the expression ``expr`` unmodified + :rtype: MediumLevelILExpr + """ + core.BNMediumLevelILSetExprSourceOperand(self.handle, expr.index, n) + return expr + + def finalize(self): + """ + ``finalize`` ends the function and computes the list of basic blocks. + + :rtype: None + """ + core.BNFinalizeMediumLevelILFunction(self.handle) + + def get_ssa_instruction_index(self, instr): + return core.BNGetMediumLevelILSSAInstructionIndex(self.handle, instr) + + def get_non_ssa_instruction_index(self, instr): + return core.BNGetMediumLevelILNonSSAInstructionIndex(self.handle, instr) + + def get_ssa_var_definition(self, var, index): + var_data = core.BNILVariable() + var_data.type = var.type + var_data.index = var.index + var_data.identifier = var.identifier + result = core.BNGetMediumLevelILSSAVarDefinition(self.handle, var_data, index) + if result >= core.BNGetMediumLevelILInstructionCount(self.handle): + return None + return result + + def get_ssa_memory_definition(self, index): + result = core.BNGetMediumLevelILSSAMemoryDefinition(self.handle, index) + if result >= core.BNGetMediumLevelILInstructionCount(self.handle): + return None + return result + + def get_ssa_var_uses(self, var, index): + count = ctypes.c_ulonglong() + var_data = core.BNILVariable() + var_data.type = var.type + var_data.index = var.index + var_data.identifier = var.identifier + instrs = core.BNGetMediumLevelILSSAVarUses(self.handle, var_data, index, count) + result = [] + for i in xrange(0, count.value): + result.append(instrs[i]) + core.BNFreeILInstructionList(instrs) + return result + + def get_ssa_memory_uses(self, index): + count = ctypes.c_ulonglong() + instrs = core.BNGetMediumLevelILSSAMemoryUses(self.handle, index, count) + result = [] + for i in xrange(0, count.value): + result.append(instrs[i]) + core.BNFreeILInstructionList(instrs) + return result + + def get_ssa_var_value(self, var, index): + var_data = core.BNILVariable() + var_data.type = var.type + var_data.index = var.index + var_data.identifier = var.identifier + value = core.BNGetMediumLevelILSSAVarValue(self.handle, var_data, index) + result = function.RegisterValue(self.arch, value) + core.BNFreeRegisterValue(value) + return result + + +class MediumLevelILBasicBlock(basicblock.BasicBlock): + def __init__(self, view, handle, owner): + super(MediumLevelILBasicBlock, self).__init__(view, handle) + self.il_function = owner + + def __iter__(self): + for idx in xrange(self.start, self.end): + yield self.il_function[idx] + + def __getitem__(self, idx): + size = self.end - self.start + if idx > size or idx < -size: + raise IndexError("list index is out of range") + if idx >= 0: + return self.il_function[idx + self.start] + else: + return self.il_function[self.end + idx] |
