From 95a7be141a07a20b8465981b01116fcafb6b5f41 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 3 Oct 2017 23:07:48 -0400 Subject: Adding support for register stacks in IL (for x87) --- python/function.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) (limited to 'python/function.py') diff --git a/python/function.py b/python/function.py index 5daa7b2a..eb8796f1 100644 --- a/python/function.py +++ b/python/function.py @@ -51,11 +51,11 @@ class LookupTableEntry(object): class RegisterValue(object): def __init__(self, arch = None, value = None, confidence = types.max_confidence): + self.is_constant = False if value is None: self.type = RegisterValueType.UndeterminedValue else: self.type = RegisterValueType(value.state) - self.is_constant = False if value.state == RegisterValueType.EntryValue: self.arch = arch if arch is not None: @@ -103,6 +103,54 @@ class RegisterValue(object): result.value = self.value return result + @classmethod + def undetermined(self): + return RegisterValue() + + @classmethod + def entry_value(self, arch, reg): + result = RegisterValue() + result.type = RegisterValueType.EntryValue + result.arch = arch + result.reg = reg + return result + + @classmethod + def constant(self, value): + result = RegisterValue() + result.type = RegisterValueType.ConstantValue + result.value = value + result.is_constant = True + return result + + @classmethod + def constant_ptr(self, value): + result = RegisterValue() + result.type = RegisterValueType.ConstantPointerValue + result.value = value + result.is_constant = True + return result + + @classmethod + def stack_frame_offset(self, offset): + result = RegisterValue() + result.type = RegisterValueType.StackFrameOffset + result.offset = offset + return result + + @classmethod + def imported_address(self, value): + result = RegisterValue() + result.type = RegisterValueType.ImportedAddressValue + result.value = value + return result + + @classmethod + def return_address(self): + result = RegisterValue() + result.type = RegisterValueType.ReturnAddressValue + return result + class ValueRange(object): def __init__(self, start, end, step): @@ -1678,6 +1726,15 @@ class RegisterInfo(object): return "" % (self.size, self.offset, self.full_width_reg, extend) +class RegisterStackInfo(object): + def __init__(self, storage_regs, stack_top_reg): + self.storage_regs = storage_regs + self.stack_top_reg = stack_top_reg + + def __repr__(self): + return "" % (len(self.storage_regs), self.stack_top_reg) + + class InstructionBranch(object): def __init__(self, branch_type, target = 0, arch = None): self.type = branch_type -- cgit v1.3.1 From d5db0ddb807265b295bb6b4ff07613776945c92b Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 23 Oct 2017 21:45:37 -0400 Subject: Top relative register stack access as a normal register --- architecture.cpp | 4 +++- binaryninjacore.h | 4 ++-- lowlevelilinstruction.cpp | 2 +- python/architecture.py | 28 +++++++++++++++++++++++----- python/function.py | 3 ++- 5 files changed, 31 insertions(+), 10 deletions(-) (limited to 'python/function.py') diff --git a/architecture.cpp b/architecture.cpp index 56af3f80..169a8c0c 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -731,7 +731,9 @@ BNRegisterStackInfo Architecture::GetRegisterStackInfo(uint32_t) { BNRegisterStackInfo result; result.firstStorageReg = BN_INVALID_REGISTER; - result.count = 0; + result.topRelativeCount = BN_INVALID_REGISTER; + result.storageCount = 0; + result.topRelativeCount = 0; result.stackTopReg = BN_INVALID_REGISTER; return result; } diff --git a/binaryninjacore.h b/binaryninjacore.h index f50c28c8..c32d42e3 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -679,8 +679,8 @@ extern "C" struct BNRegisterStackInfo { - uint32_t firstStorageReg; - uint32_t count; + uint32_t firstStorageReg, firstTopRelativeReg; + uint32_t storageCount, topRelativeCount; uint32_t stackTopReg; }; diff --git a/lowlevelilinstruction.cpp b/lowlevelilinstruction.cpp index 4130dd2a..91af36b1 100644 --- a/lowlevelilinstruction.cpp +++ b/lowlevelilinstruction.cpp @@ -2179,7 +2179,7 @@ ExprId LowLevelILFunction::SetRegisterStackTopRelativeSSA(size_t size, uint32_t ExprId LowLevelILFunction::SetRegisterStackAbsoluteSSA(size_t size, uint32_t regStack, size_t destVersion, size_t srcVersion, uint32_t reg, ExprId val, const ILSourceLocation& loc) { - return AddExprWithLocation(LLIL_SET_REG_STACK_REL_SSA, loc, size, 0, + return AddExprWithLocation(LLIL_SET_REG_STACK_ABS_SSA, loc, size, 0, AddExprWithLocation(LLIL_REG_STACK_DEST_SSA, loc, size, 0, regStack, destVersion, srcVersion), reg, val); } diff --git a/python/architecture.py b/python/architecture.py index 289b0abd..04179e7f 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -225,10 +225,13 @@ class Architecture(object): name = core.BNGetArchitectureRegisterStackName(self.handle, regs[i]) info = core.BNGetArchitectureRegisterStackInfo(self.handle, regs[i]) storage = [] - for j in xrange(0, info.count): + for j in xrange(0, info.storageCount): storage.append(core.BNGetArchitectureRegisterName(self.handle, info.firstStorageReg + j)) + top_rel = [] + for j in xrange(0, info.topRelativeCount): + top_rel.append(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j)) top = core.BNGetArchitectureRegisterName(self.handle, info.stackTopReg) - self.reg_stacks[name] = function.RegisterStackInfo(storage, top) + self.reg_stacks[name] = function.RegisterStackInfo(storage, top_rel, top) core.BNFreeRegisterList(regs) else: startup._init_plugins() @@ -310,6 +313,11 @@ class Architecture(object): self._regs_by_index[reg_index] = reg self.regs[reg].index = reg_index reg_index += 1 + for reg in info.top_relative_regs: + self._all_regs[reg] = reg_index + self._regs_by_index[reg_index] = reg + self.regs[reg].index = reg_index + reg_index += 1 if reg_stack not in self._all_reg_stacks: self._all_reg_stacks[reg_stack] = reg_stack_index self._reg_stacks_by_index[reg_stack_index] = reg_stack @@ -808,17 +816,27 @@ class Architecture(object): try: if reg_stack not in self._reg_stacks_by_index: result[0].firstStorageReg = 0 - result[0].count = 0 + result[0].firstTopRelativeReg = 0 + result[0].storageCount = 0 + result[0].topRelativeCount = 0 result[0].stackTopReg = 0 return info = self.__class__.regs[self._reg_stacks_by_index[reg_stack]] result[0].firstStorageReg = self._all_regs[info.storage_regs[0]] - result[0].count = len(info.storage_regs) + result[0].storageCount = len(info.storage_regs) + if len(info.top_relative_regs) > 0: + result[0].firstTopRelativeReg = self._all_regs[info.top_relative_regs[0]] + result[0].topRelativeCount = len(info.top_relative_regs) + else: + result[0].firstTopRelativeReg = 0 + result[0].topRelativeCount = 0 result[0].stackTopReg = self._all_regs[info.stack_top_reg] except KeyError: log.log_error(traceback.format_exc()) result[0].firstStorageReg = 0 - result[0].count = 0 + result[0].firstTopRelativeReg = 0 + result[0].storageCount = 0 + result[0].topRelativeCount = 0 result[0].stackTopReg = 0 def _assemble(self, ctxt, code, addr, result, errors): diff --git a/python/function.py b/python/function.py index eb8796f1..ba00147e 100644 --- a/python/function.py +++ b/python/function.py @@ -1727,8 +1727,9 @@ class RegisterInfo(object): class RegisterStackInfo(object): - def __init__(self, storage_regs, stack_top_reg): + def __init__(self, storage_regs, top_relative_regs, stack_top_reg): self.storage_regs = storage_regs + self.top_relative_regs = top_relative_regs self.stack_top_reg = stack_top_reg def __repr__(self): -- cgit v1.3.1 From c24b1bd108ee2885d7164cecd15f75aa1715a8df Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 27 Nov 2017 17:15:03 -0500 Subject: Register stack adjustments in calling conventions --- binaryninjaapi.h | 21 +++++- binaryninjacore.h | 29 +++++++- callingconvention.cpp | 44 ++++++++++++ function.cpp | 48 ++++++++++++- lowlevelilinstruction.cpp | 172 ++++++++++++++++++++++++++++++++++++++------ lowlevelilinstruction.h | 57 ++++++++++++--- python/architecture.py | 2 +- python/callingconvention.py | 85 ++++++++++++++++++++++ python/function.py | 67 ++++++++++++++--- python/lowlevelil.py | 24 ++++++- python/types.py | 15 ++++ 11 files changed, 512 insertions(+), 52 deletions(-) (limited to 'python/function.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 5c122966..af067ae9 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2208,6 +2208,7 @@ namespace BinaryNinja Confidence> GetParameterVariables() const; Confidence HasVariableArguments() const; Confidence GetStackAdjustment() const; + std::map> GetRegisterStackAdjustments() const; Confidence> GetClobberedRegisters() const; void SetAutoType(Type* type); @@ -2217,6 +2218,7 @@ namespace BinaryNinja void SetAutoHasVariableArguments(const Confidence& varArgs); void SetAutoCanReturn(const Confidence& returns); void SetAutoStackAdjustment(const Confidence& stackAdjust); + void SetAutoRegisterStackAdjustments(const std::map>& regStackAdjust); void SetAutoClobberedRegisters(const Confidence>& clobbered); void SetUserType(Type* type); @@ -2226,6 +2228,7 @@ namespace BinaryNinja void SetHasVariableArguments(const Confidence& varArgs); void SetCanReturn(const Confidence& returns); void SetStackAdjustment(const Confidence& stackAdjust); + void SetRegisterStackAdjustments(const std::map>& regStackAdjust); void SetClobberedRegisters(const Confidence>& clobbered); void ApplyImportedTypes(Symbol* sym); @@ -2558,11 +2561,12 @@ namespace BinaryNinja ExprId JumpTo(ExprId dest, const std::vector& targets, const ILSourceLocation& loc = ILSourceLocation()); ExprId Call(ExprId dest, const ILSourceLocation& loc = ILSourceLocation()); - ExprId CallStackAdjust(ExprId dest, size_t adjust, const ILSourceLocation& loc = ILSourceLocation()); - ExprId CallSSA(const std::vector& output, ExprId dest, const std::vector& params, + ExprId CallStackAdjust(ExprId dest, size_t adjust, const std::map& regStackAdjust, + const ILSourceLocation& loc = ILSourceLocation()); + ExprId CallSSA(const std::vector& output, ExprId dest, const std::vector& params, const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer, const ILSourceLocation& loc = ILSourceLocation()); - ExprId SystemCallSSA(const std::vector& output, const std::vector& params, + ExprId SystemCallSSA(const std::vector& output, const std::vector& params, const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer, const ILSourceLocation& loc = ILSourceLocation()); ExprId Return(size_t dest, const ILSourceLocation& loc = ILSourceLocation()); @@ -3184,6 +3188,11 @@ namespace BinaryNinja static void GetIncomingRegisterValueCallback(void* ctxt, uint32_t reg, BNFunction* func, BNRegisterValue* result); static void GetIncomingFlagValueCallback(void* ctxt, uint32_t reg, BNFunction* func, BNRegisterValue* result); + static void GetIncomingVariableForParameterVariableCallback(void* ctxt, const BNVariable* var, + BNFunction* func, BNVariable* result); + static void GetParameterVariableForIncomingVariableCallback(void* ctxt, const BNVariable* var, + BNFunction* func, BNVariable* result); + public: Ref GetArchitecture() const; std::string GetName() const; @@ -3204,6 +3213,9 @@ namespace BinaryNinja virtual std::vector GetImplicitlyDefinedRegisters(); virtual RegisterValue GetIncomingRegisterValue(uint32_t reg, Function* func); virtual RegisterValue GetIncomingFlagValue(uint32_t flag, Function* func); + + virtual Variable GetIncomingVariableForParameterVariable(const Variable& var, Function* func); + virtual Variable GetParameterVariableForIncomingVariable(const Variable& var, Function* func); }; class CoreCallingConvention: public CallingConvention @@ -3227,6 +3239,9 @@ namespace BinaryNinja virtual std::vector GetImplicitlyDefinedRegisters() override; virtual RegisterValue GetIncomingRegisterValue(uint32_t reg, Function* func) override; virtual RegisterValue GetIncomingFlagValue(uint32_t flag, Function* func) override; + + virtual Variable GetIncomingVariableForParameterVariable(const Variable& var, Function* func) override; + virtual Variable GetParameterVariableForIncomingVariable(const Variable& var, Function* func) override; }; /*! diff --git a/binaryninjacore.h b/binaryninjacore.h index c32d42e3..278299bc 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1341,6 +1341,11 @@ extern "C" uint32_t* (*getImplicitlyDefinedRegisters)(void* ctxt, size_t* count); void (*getIncomingRegisterValue)(void* ctxt, uint32_t reg, BNFunction* func, BNRegisterValue* result); void (*getIncomingFlagValue)(void* ctxt, uint32_t flag, BNFunction* func, BNRegisterValue* result); + + void (*getIncomingVariableForParameterVariable)(void* ctxt, const BNVariable* var, + BNFunction* func, BNVariable* result); + void (*getParameterVariableForIncomingVariable)(void* ctxt, const BNVariable* var, + BNFunction* func, BNVariable* result); }; struct BNVariableNameAndType @@ -1658,6 +1663,13 @@ extern "C" ArrayDataType }; + struct BNRegisterStackAdjustment + { + uint32_t regStack; + int32_t adjustment; + uint8_t confidence; + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); BINARYNINJACOREAPI char** BNAllocStringList(const char** contents, size_t size); @@ -2173,6 +2185,8 @@ extern "C" BINARYNINJACOREAPI void BNFreeParameterVariables(BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI BNBoolWithConfidence BNFunctionHasVariableArguments(BNFunction* func); BINARYNINJACOREAPI BNSizeWithConfidence BNGetFunctionStackAdjustment(BNFunction* func); + BINARYNINJACOREAPI BNRegisterStackAdjustment* BNGetFunctionRegisterStackAdjustments(BNFunction* func, size_t* count); + BINARYNINJACOREAPI void BNFreeRegisterStackAdjustments(BNRegisterStackAdjustment* adjustments); BINARYNINJACOREAPI BNRegisterSetWithConfidence BNGetFunctionClobberedRegisters(BNFunction* func); BINARYNINJACOREAPI void BNFreeClobberedRegisters(BNRegisterSetWithConfidence* regs); @@ -2182,6 +2196,8 @@ extern "C" BINARYNINJACOREAPI void BNSetAutoFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); BINARYNINJACOREAPI void BNSetAutoFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns); BINARYNINJACOREAPI void BNSetAutoFunctionStackAdjustment(BNFunction* func, BNSizeWithConfidence* stackAdjust); + BINARYNINJACOREAPI void BNSetAutoFunctionRegisterStackAdjustments(BNFunction* func, + BNRegisterStackAdjustment* adjustments, size_t count); BINARYNINJACOREAPI void BNSetAutoFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNSetUserFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type); @@ -2190,6 +2206,8 @@ extern "C" BINARYNINJACOREAPI void BNSetUserFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); BINARYNINJACOREAPI void BNSetUserFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns); BINARYNINJACOREAPI void BNSetUserFunctionStackAdjustment(BNFunction* func, BNSizeWithConfidence* stackAdjust); + BINARYNINJACOREAPI void BNSetUserFunctionRegisterStackAdjustments(BNFunction* func, + BNRegisterStackAdjustment* adjustments, size_t count); BINARYNINJACOREAPI void BNSetUserFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNApplyImportedTypes(BNFunction* func, BNSymbol* sym); @@ -2241,7 +2259,7 @@ extern "C" BINARYNINJACOREAPI void BNFreeStringReferenceList(BNStringReference* strings); BINARYNINJACOREAPI BNVariableNameAndType* BNGetStackLayout(BNFunction* func, size_t* count); - BINARYNINJACOREAPI void BNFreeVariableList(BNVariableNameAndType* vars, size_t count); + BINARYNINJACOREAPI void BNFreeVariableNameAndTypeList(BNVariableNameAndType* vars, size_t count); BINARYNINJACOREAPI void BNCreateAutoStackVariable(BNFunction* func, int64_t offset, BNTypeWithConfidence* type, const char* name); BINARYNINJACOREAPI void BNCreateUserStackVariable(BNFunction* func, int64_t offset, @@ -2917,6 +2935,15 @@ extern "C" BINARYNINJACOREAPI BNRegisterValue BNGetIncomingRegisterValue(BNCallingConvention* cc, uint32_t reg, BNFunction* func); BINARYNINJACOREAPI BNRegisterValue BNGetIncomingFlagValue(BNCallingConvention* cc, uint32_t reg, BNFunction* func); + BINARYNINJACOREAPI BNVariable BNGetIncomingVariableForParameterVariable(BNCallingConvention* cc, + const BNVariable* var, BNFunction* func); + BINARYNINJACOREAPI BNVariable BNGetParameterVariableForIncomingVariable(BNCallingConvention* cc, + const BNVariable* var, BNFunction* func); + BINARYNINJACOREAPI BNVariable BNGetDefaultIncomingVariableForParameterVariable(BNCallingConvention* cc, + const BNVariable* var); + BINARYNINJACOREAPI BNVariable BNGetDefaultParameterVariableForIncomingVariable(BNCallingConvention* cc, + const BNVariable* var); + BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureDefaultCallingConvention(BNArchitecture* arch); BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureCdeclCallingConvention(BNArchitecture* arch); BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureStdcallCallingConvention(BNArchitecture* arch); diff --git a/callingconvention.cpp b/callingconvention.cpp index b29d51e2..2eb57567 100644 --- a/callingconvention.cpp +++ b/callingconvention.cpp @@ -49,6 +49,8 @@ CallingConvention::CallingConvention(Architecture* arch, const string& name) cc.getImplicitlyDefinedRegisters = GetImplicitlyDefinedRegistersCallback; cc.getIncomingRegisterValue = GetIncomingRegisterValueCallback; cc.getIncomingFlagValue = GetIncomingFlagValueCallback; + cc.getIncomingVariableForParameterVariable = GetIncomingVariableForParameterVariableCallback; + cc.getParameterVariableForIncomingVariable = GetParameterVariableForIncomingVariableCallback; AddRefForRegistration(); m_object = BNCreateCallingConvention(arch->GetObject(), name.c_str(), &cc); @@ -189,6 +191,24 @@ void CallingConvention::GetIncomingFlagValueCallback(void* ctxt, uint32_t reg, B } +void CallingConvention::GetIncomingVariableForParameterVariableCallback(void* ctxt, const BNVariable* var, + BNFunction* func, BNVariable* result) +{ + CallingConvention* cc = (CallingConvention*)ctxt; + *result = cc->GetIncomingVariableForParameterVariable(*var, + func ? new Function(BNNewFunctionReference(func)) : nullptr); +} + + +void CallingConvention::GetParameterVariableForIncomingVariableCallback(void* ctxt, const BNVariable* var, + BNFunction* func, BNVariable* result) +{ + CallingConvention* cc = (CallingConvention*)ctxt; + *result = cc->GetParameterVariableForIncomingVariable(*var, + func ? new Function(BNNewFunctionReference(func)) : nullptr); +} + + Ref CallingConvention::GetArchitecture() const { return new CoreArchitecture(BNGetCallingConventionArchitecture(m_object)); @@ -284,6 +304,18 @@ RegisterValue CallingConvention::GetIncomingFlagValue(uint32_t, Function*) } +Variable CallingConvention::GetIncomingVariableForParameterVariable(const Variable& var, Function*) +{ + return BNGetDefaultIncomingVariableForParameterVariable(m_object, &var); +} + + +Variable CallingConvention::GetParameterVariableForIncomingVariable(const Variable& var, Function*) +{ + return BNGetDefaultParameterVariableForIncomingVariable(m_object, &var); +} + + CoreCallingConvention::CoreCallingConvention(BNCallingConvention* cc): CallingConvention(cc) { } @@ -385,3 +417,15 @@ RegisterValue CoreCallingConvention::GetIncomingFlagValue(uint32_t flag, Functio { return RegisterValue::FromAPIObject(BNGetIncomingFlagValue(m_object, flag, func ? func->GetObject() : nullptr)); } + + +Variable CoreCallingConvention::GetIncomingVariableForParameterVariable(const Variable& var, Function* func) +{ + return BNGetIncomingVariableForParameterVariable(m_object, &var, func ? func->GetObject() : nullptr); +} + + +Variable CoreCallingConvention::GetParameterVariableForIncomingVariable(const Variable& var, Function* func) +{ + return BNGetParameterVariableForIncomingVariable(m_object, &var, func ? func->GetObject() : nullptr); +} diff --git a/function.cpp b/function.cpp index 2d8db04c..879c7156 100644 --- a/function.cpp +++ b/function.cpp @@ -530,6 +530,18 @@ Confidence Function::GetStackAdjustment() const } +map> Function::GetRegisterStackAdjustments() const +{ + size_t count; + BNRegisterStackAdjustment* regStackAdjust = BNGetFunctionRegisterStackAdjustments(m_object, &count); + map> result; + for (size_t i = 0; i < count; i++) + result[regStackAdjust[i].regStack] = Confidence(regStackAdjust[i].adjustment, regStackAdjust[i].confidence); + BNFreeRegisterStackAdjustments(regStackAdjust); + return result; +} + + Confidence> Function::GetClobberedRegisters() const { BNRegisterSetWithConfidence regs = BNGetFunctionClobberedRegisters(m_object); @@ -611,6 +623,22 @@ void Function::SetAutoStackAdjustment(const Confidence& stackAdjust) } +void Function::SetAutoRegisterStackAdjustments(const map>& regStackAdjust) +{ + BNRegisterStackAdjustment* adjust = new BNRegisterStackAdjustment[regStackAdjust.size()]; + size_t i = 0; + for (auto& j : regStackAdjust) + { + adjust[i].regStack = j.first; + adjust[i].adjustment = j.second.GetValue(); + adjust[i].confidence = j.second.GetConfidence(); + i++; + } + BNSetAutoFunctionRegisterStackAdjustments(m_object, adjust, regStackAdjust.size()); + delete[] adjust; +} + + void Function::SetAutoClobberedRegisters(const Confidence>& clobbered) { BNRegisterSetWithConfidence regs; @@ -694,6 +722,22 @@ void Function::SetStackAdjustment(const Confidence& stackAdjust) } +void Function::SetRegisterStackAdjustments(const map>& regStackAdjust) +{ + BNRegisterStackAdjustment* adjust = new BNRegisterStackAdjustment[regStackAdjust.size()]; + size_t i = 0; + for (auto& j : regStackAdjust) + { + adjust[i].regStack = j.first; + adjust[i].adjustment = j.second.GetValue(); + adjust[i].confidence = j.second.GetConfidence(); + i++; + } + BNSetUserFunctionRegisterStackAdjustments(m_object, adjust, regStackAdjust.size()); + delete[] adjust; +} + + void Function::SetClobberedRegisters(const Confidence>& clobbered) { BNRegisterSetWithConfidence regs; @@ -743,7 +787,7 @@ map> Function::GetStackLayout() result[vars[i].var.storage].push_back(var); } - BNFreeVariableList(vars, count); + BNFreeVariableNameAndTypeList(vars, count); return result; } @@ -811,7 +855,7 @@ map Function::GetVariables() result[vars[i].var] = var; } - BNFreeVariableList(vars, count); + BNFreeVariableNameAndTypeList(vars, count); return result; } diff --git a/lowlevelilinstruction.cpp b/lowlevelilinstruction.cpp index 91af36b1..8259426a 100644 --- a/lowlevelilinstruction.cpp +++ b/lowlevelilinstruction.cpp @@ -74,12 +74,13 @@ unordered_map {FlagConditionLowLevelOperandUsage, FlagConditionLowLevelOperand}, {OutputSSARegistersLowLevelOperandUsage, SSARegisterListLowLevelOperand}, {OutputMemoryVersionLowLevelOperandUsage, IndexLowLevelOperand}, - {ParameterSSARegistersLowLevelOperandUsage, SSARegisterListLowLevelOperand}, + {ParameterExprsLowLevelOperandUsage, ExprListLowLevelOperand}, {SourceSSARegistersLowLevelOperandUsage, SSARegisterListLowLevelOperand}, {SourceSSARegisterStacksLowLevelOperandUsage, SSARegisterStackListLowLevelOperand}, {SourceSSAFlagsLowLevelOperandUsage, SSAFlagListLowLevelOperand}, {SourceMemoryVersionsLowLevelOperandUsage, IndexListLowLevelOperand}, - {TargetListLowLevelOperandUsage, IndexListLowLevelOperand} + {TargetListLowLevelOperandUsage, IndexListLowLevelOperand}, + {RegisterStackAdjustmentsLowLevelOperandUsage, RegisterStackAdjustmentsLowLevelOperand} }; @@ -133,7 +134,8 @@ unordered_map> {LLIL_JUMP, {DestExprLowLevelOperandUsage}}, {LLIL_JUMP_TO, {DestExprLowLevelOperandUsage, TargetListLowLevelOperandUsage}}, {LLIL_CALL, {DestExprLowLevelOperandUsage}}, - {LLIL_CALL_STACK_ADJUST, {DestExprLowLevelOperandUsage, StackAdjustmentLowLevelOperandUsage}}, + {LLIL_CALL_STACK_ADJUST, {DestExprLowLevelOperandUsage, StackAdjustmentLowLevelOperandUsage, + RegisterStackAdjustmentsLowLevelOperandUsage}}, {LLIL_RET, {DestExprLowLevelOperandUsage}}, {LLIL_IF, {ConditionExprLowLevelOperandUsage, TrueTargetLowLevelOperandUsage, FalseTargetLowLevelOperandUsage}}, @@ -142,10 +144,10 @@ unordered_map> {LLIL_TRAP, {VectorLowLevelOperandUsage}}, {LLIL_CALL_SSA, {OutputSSARegistersLowLevelOperandUsage, OutputMemoryVersionLowLevelOperandUsage, DestExprLowLevelOperandUsage, StackSSARegisterLowLevelOperandUsage, - StackMemoryVersionLowLevelOperandUsage, ParameterSSARegistersLowLevelOperandUsage}}, + StackMemoryVersionLowLevelOperandUsage, ParameterExprsLowLevelOperandUsage}}, {LLIL_SYSCALL_SSA, {OutputSSARegistersLowLevelOperandUsage, OutputMemoryVersionLowLevelOperandUsage, StackSSARegisterLowLevelOperandUsage, StackMemoryVersionLowLevelOperandUsage, - ParameterSSARegistersLowLevelOperandUsage}}, + ParameterExprsLowLevelOperandUsage}}, {LLIL_REG_PHI, {DestSSARegisterLowLevelOperandUsage, SourceSSARegistersLowLevelOperandUsage}}, {LLIL_REG_STACK_PHI, {DestSSARegisterStackLowLevelOperandUsage, SourceSSARegisterStacksLowLevelOperandUsage}}, {LLIL_FLAG_PHI, {DestSSAFlagLowLevelOperandUsage, SourceSSAFlagsLowLevelOperandUsage}}, @@ -239,7 +241,7 @@ static unordered_map() const } +const LowLevelILInstruction LowLevelILInstructionList::ListIterator::operator*() +{ + return LowLevelILInstruction(pos.GetFunction(), pos.GetFunction()->GetRawExpr((size_t)*pos), + (size_t)*pos, instructionIndex); +} + + +LowLevelILInstructionList::LowLevelILInstructionList(LowLevelILFunction* func, + const BNLowLevelILInstruction& instr, size_t count, size_t instrIndex): + m_list(func, instr, count), m_instructionIndex(instrIndex) +{ +} + + +LowLevelILInstructionList::const_iterator LowLevelILInstructionList::begin() const +{ + const_iterator result; + result.pos = m_list.begin(); + result.instructionIndex = m_instructionIndex; + return result; +} + + +LowLevelILInstructionList::const_iterator LowLevelILInstructionList::end() const +{ + const_iterator result; + result.pos = m_list.end(); + result.instructionIndex = m_instructionIndex; + return result; +} + + +size_t LowLevelILInstructionList::size() const +{ + return m_list.size(); +} + + +const LowLevelILInstruction LowLevelILInstructionList::operator[](size_t i) const +{ + if (i >= size()) + throw LowLevelILInstructionAccessException(); + auto iter = begin(); + for (size_t j = 0; j < i; j++) + ++iter; + return *iter; +} + + +LowLevelILInstructionList::operator vector() const +{ + vector result; + for (auto i : *this) + result.push_back(i); + return result; +} + + const SSARegister LowLevelILSSARegisterList::ListIterator::operator*() { LowLevelILIntegerList::const_iterator cur = pos; @@ -864,14 +925,20 @@ LowLevelILIndexList LowLevelILOperand::GetIndexList() const } +LowLevelILInstructionList LowLevelILOperand::GetExprList() const +{ + if (m_type != ExprListLowLevelOperand) + throw LowLevelILInstructionAccessException(); + return m_instr.GetRawOperandAsExpr(m_operandIndex).GetRawOperandAsExprList(0); +} + + LowLevelILSSARegisterList LowLevelILOperand::GetSSARegisterList() const { if (m_type != SSARegisterListLowLevelOperand) throw LowLevelILInstructionAccessException(); if (m_usage == OutputSSARegistersLowLevelOperandUsage) return m_instr.GetRawOperandAsExpr(m_operandIndex).GetRawOperandAsSSARegisterList(1); - if (m_usage == ParameterSSARegistersLowLevelOperandUsage) - return m_instr.GetRawOperandAsExpr(m_operandIndex).GetRawOperandAsSSARegisterList(0); return m_instr.GetRawOperandAsSSARegisterList(m_operandIndex); } @@ -892,6 +959,14 @@ LowLevelILSSAFlagList LowLevelILOperand::GetSSAFlagList() const } +map LowLevelILOperand::GetRegisterStackAdjustments() const +{ + if (m_type != RegisterStackAdjustmentsLowLevelOperand) + throw LowLevelILInstructionAccessException(); + return m_instr.GetRawOperandAsRegisterStackAdjustments(m_operandIndex); +} + + const LowLevelILOperand LowLevelILOperandList::ListIterator::operator*() { LowLevelILOperandUsage usage = *pos; @@ -1073,6 +1148,13 @@ LowLevelILIndexList LowLevelILInstructionBase::GetRawOperandAsIndexList(size_t o } +LowLevelILInstructionList LowLevelILInstructionBase::GetRawOperandAsExprList(size_t operand) const +{ + return LowLevelILInstructionList(function, function->GetRawExpr(operands[operand + 1]), operands[operand], + instructionIndex); +} + + LowLevelILSSARegisterList LowLevelILInstructionBase::GetRawOperandAsSSARegisterList(size_t operand) const { return LowLevelILSSARegisterList(function, function->GetRawExpr(operands[operand + 1]), operands[operand]); @@ -1091,6 +1173,24 @@ LowLevelILSSAFlagList LowLevelILInstructionBase::GetRawOperandAsSSAFlagList(size } +map LowLevelILInstructionBase::GetRawOperandAsRegisterStackAdjustments(size_t operand) const +{ + LowLevelILIntegerList list(function, function->GetRawExpr(operands[operand + 1]), operands[operand]); + map result; + for (auto i = list.begin(); i != list.end(); ) + { + uint32_t regStack = (uint32_t)*i; + ++i; + if (i == list.end()) + break; + int32_t adjust = (int32_t)*i; + ++i; + result[regStack] = adjust; + } + return result; +} + + void LowLevelILInstructionBase::UpdateRawOperand(size_t operandIndex, ExprId value) { operands[operandIndex] = value; @@ -1385,6 +1485,12 @@ void LowLevelILInstruction::VisitExprs(const std::function().VisitExprs(func); + for (auto& i : GetParameterExprs()) + i.VisitExprs(func); + break; + case LLIL_SYSCALL_SSA: + for (auto& i : GetParameterExprs()) + i.VisitExprs(func); break; case LLIL_RET: GetDestExpr().VisitExprs(func); @@ -1478,6 +1584,7 @@ ExprId LowLevelILInstruction::CopyTo(LowLevelILFunction* dest, const std::function& subExprHandler) const { vector labelList; + vector params; BNLowLevelILLabel* labelA; BNLowLevelILLabel* labelB; switch (operation) @@ -1576,7 +1683,7 @@ ExprId LowLevelILInstruction::CopyTo(LowLevelILFunction* dest, return dest->Call(subExprHandler(GetDestExpr()), *this); case LLIL_CALL_STACK_ADJUST: return dest->CallStackAdjust(subExprHandler(GetDestExpr()), - GetStackAdjustment(), *this); + GetStackAdjustment(), GetRegisterStackAdjustments(), *this); case LLIL_RET: return dest->Return(subExprHandler(GetDestExpr()), *this); case LLIL_JUMP_TO: @@ -1607,13 +1714,17 @@ ExprId LowLevelILInstruction::CopyTo(LowLevelILFunction* dest, case LLIL_TRAP: return dest->Trap(GetVector(), *this); case LLIL_CALL_SSA: + for (auto& i : GetParameterExprs()) + params.push_back(subExprHandler(i)); return dest->CallSSA(GetOutputSSARegisters(), subExprHandler(GetDestExpr()), - GetParameterSSARegisters(), GetStackSSARegister(), - GetDestMemoryVersion(), GetSourceMemoryVersion(), *this); + params, GetStackSSARegister(), GetDestMemoryVersion(), + GetSourceMemoryVersion(), *this); case LLIL_SYSCALL_SSA: + for (auto& i : GetParameterExprs()) + params.push_back(subExprHandler(i)); return dest->SystemCallSSA(GetOutputSSARegisters(), - GetParameterSSARegisters(), GetStackSSARegister(), - GetDestMemoryVersion(), GetSourceMemoryVersion(), *this); + params, GetStackSSARegister(), GetDestMemoryVersion(), + GetSourceMemoryVersion(), *this); case LLIL_REG_PHI: return dest->RegisterPhi(GetDestSSARegister(), GetSourceSSARegisters(), *this); case LLIL_REG_STACK_PHI: @@ -2055,11 +2166,11 @@ LowLevelILSSARegisterList LowLevelILInstruction::GetOutputSSARegisters() const } -LowLevelILSSARegisterList LowLevelILInstruction::GetParameterSSARegisters() const +LowLevelILInstructionList LowLevelILInstruction::GetParameterExprs() const { size_t operandIndex; - if (GetOperandIndexForUsage(ParameterSSARegistersLowLevelOperandUsage, operandIndex)) - return GetRawOperandAsExpr(operandIndex).GetRawOperandAsSSARegisterList(0); + if (GetOperandIndexForUsage(ParameterExprsLowLevelOperandUsage, operandIndex)) + return GetRawOperandAsExpr(operandIndex).GetRawOperandAsExprList(0); throw LowLevelILInstructionAccessException(); } @@ -2109,6 +2220,15 @@ LowLevelILIndexList LowLevelILInstruction::GetTargetList() const } +map LowLevelILInstruction::GetRegisterStackAdjustments() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(RegisterStackAdjustmentsLowLevelOperandUsage, operandIndex)) + return GetRawOperandAsRegisterStackAdjustments(operandIndex); + throw LowLevelILInstructionAccessException(); +} + + ExprId LowLevelILFunction::Nop(const ILSourceLocation& loc) { return AddExprWithLocation(LLIL_NOP, loc, 0, 0); @@ -2578,13 +2698,21 @@ ExprId LowLevelILFunction::Call(ExprId dest, const ILSourceLocation& loc) } -ExprId LowLevelILFunction::CallStackAdjust(ExprId dest, size_t adjust, const ILSourceLocation& loc) +ExprId LowLevelILFunction::CallStackAdjust(ExprId dest, size_t adjust, + const std::map& regStackAdjust, const ILSourceLocation& loc) { - return AddExprWithLocation(LLIL_CALL_STACK_ADJUST, loc, 0, 0, dest, adjust); + vector list; + for (auto& i : regStackAdjust) + { + list.push_back(i.first); + list.push_back(i.second); + } + return AddExprWithLocation(LLIL_CALL_STACK_ADJUST, loc, 0, 0, dest, adjust, list.size(), + AddIndexList(list)); } -ExprId LowLevelILFunction::CallSSA(const vector& output, ExprId dest, const vector& params, +ExprId LowLevelILFunction::CallSSA(const vector& output, ExprId dest, const vector& params, const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer, const ILSourceLocation& loc) { return AddExprWithLocation(LLIL_CALL_SSA, loc, 0, 0, @@ -2592,11 +2720,11 @@ ExprId LowLevelILFunction::CallSSA(const vector& output, ExprId des output.size() * 2, AddSSARegisterList(output)), dest, AddExprWithLocation(LLIL_CALL_STACK_SSA, loc, 0, 0, stack.reg, stack.version, prevMemoryVer), AddExprWithLocation(LLIL_CALL_PARAM_SSA, loc, 0, 0, - params.size() * 2, AddSSARegisterList(params))); + params.size(), AddOperandList(params))); } -ExprId LowLevelILFunction::SystemCallSSA(const vector& output, const vector& params, +ExprId LowLevelILFunction::SystemCallSSA(const vector& output, const vector& params, const SSARegister& stack, size_t newMemoryVer, size_t prevMemoryVer, const ILSourceLocation& loc) { return AddExprWithLocation(LLIL_SYSCALL_SSA, loc, 0, 0, @@ -2604,7 +2732,7 @@ ExprId LowLevelILFunction::SystemCallSSA(const vector& output, cons output.size() * 2, AddSSARegisterList(output)), AddExprWithLocation(LLIL_CALL_STACK_SSA, loc, 0, 0, stack.reg, stack.version, prevMemoryVer), AddExprWithLocation(LLIL_CALL_PARAM_SSA, loc, 0, 0, - params.size() * 2, AddSSARegisterList(params))); + params.size(), AddOperandList(params))); } diff --git a/lowlevelilinstruction.h b/lowlevelilinstruction.h index 4e02632e..cfc7e2d7 100644 --- a/lowlevelilinstruction.h +++ b/lowlevelilinstruction.h @@ -112,9 +112,11 @@ namespace BinaryNinja SSARegisterStackLowLevelOperand, SSAFlagLowLevelOperand, IndexListLowLevelOperand, + ExprListLowLevelOperand, SSARegisterListLowLevelOperand, SSARegisterStackListLowLevelOperand, - SSAFlagListLowLevelOperand + SSAFlagListLowLevelOperand, + RegisterStackAdjustmentsLowLevelOperand }; enum LowLevelILOperandUsage @@ -158,12 +160,13 @@ namespace BinaryNinja FlagConditionLowLevelOperandUsage, OutputSSARegistersLowLevelOperandUsage, OutputMemoryVersionLowLevelOperandUsage, - ParameterSSARegistersLowLevelOperandUsage, + ParameterExprsLowLevelOperandUsage, SourceSSARegistersLowLevelOperandUsage, SourceSSARegisterStacksLowLevelOperandUsage, SourceSSAFlagsLowLevelOperandUsage, SourceMemoryVersionsLowLevelOperandUsage, - TargetListLowLevelOperandUsage + TargetListLowLevelOperandUsage, + RegisterStackAdjustmentsLowLevelOperandUsage }; } @@ -328,6 +331,36 @@ namespace BinaryNinja operator std::vector() const; }; + class LowLevelILInstructionList + { + struct ListIterator + { + LowLevelILIntegerList::const_iterator pos; + size_t instructionIndex; + bool operator==(const ListIterator& a) const { return pos == a.pos; } + bool operator!=(const ListIterator& a) const { return pos != a.pos; } + bool operator<(const ListIterator& a) const { return pos < a.pos; } + ListIterator& operator++() { ++pos; return *this; } + const LowLevelILInstruction operator*(); + }; + + LowLevelILIntegerList m_list; + size_t m_instructionIndex; + + public: + typedef ListIterator const_iterator; + + LowLevelILInstructionList(LowLevelILFunction* func, const BNLowLevelILInstruction& instr, + size_t count, size_t instrIndex); + + const_iterator begin() const; + const_iterator end() const; + size_t size() const; + const LowLevelILInstruction operator[](size_t i) const; + + operator std::vector() const; + }; + class LowLevelILSSARegisterList { struct ListIterator @@ -436,9 +469,11 @@ namespace BinaryNinja SSARegisterStack GetRawOperandAsPartialSSARegisterStackSource(size_t operand) const; SSAFlag GetRawOperandAsSSAFlag(size_t operand) const; LowLevelILIndexList GetRawOperandAsIndexList(size_t operand) const; + LowLevelILInstructionList GetRawOperandAsExprList(size_t operand) const; LowLevelILSSARegisterList GetRawOperandAsSSARegisterList(size_t operand) const; LowLevelILSSARegisterStackList GetRawOperandAsSSARegisterStackList(size_t operand) const; LowLevelILSSAFlagList GetRawOperandAsSSAFlagList(size_t operand) const; + std::map GetRawOperandAsRegisterStackAdjustments(size_t operand) const; void UpdateRawOperand(size_t operandIndex, ExprId value); void UpdateRawOperandAsSSARegisterList(size_t operandIndex, const std::vector& regs); @@ -574,12 +609,13 @@ namespace BinaryNinja template size_t GetDestMemoryVersion() const { return As().GetDestMemoryVersion(); } template BNLowLevelILFlagCondition GetFlagCondition() const { return As().GetFlagCondition(); } template LowLevelILSSARegisterList GetOutputSSARegisters() const { return As().GetOutputSSARegisters(); } - template LowLevelILSSARegisterList GetParameterSSARegisters() const { return As().GetParameterSSARegisters(); } + template LowLevelILInstructionList GetParameterExprs() const { return As().GetParameterExprs(); } template LowLevelILSSARegisterList GetSourceSSARegisters() const { return As().GetSourceSSARegisters(); } template LowLevelILSSARegisterStackList GetSourceSSARegisterStacks() const { return As().GetSourceSSARegisterStacks(); } template LowLevelILSSAFlagList GetSourceSSAFlags() const { return As().GetSourceSSAFlags(); } template LowLevelILIndexList GetSourceMemoryVersions() const { return As().GetSourceMemoryVersions(); } template LowLevelILIndexList GetTargetList() const { return As().GetTargetList(); } + template std::map GetRegisterStackAdjustments() const { return As().GetRegisterStackAdjustments(); } template void SetDestSSAVersion(size_t version) { As().SetDestSSAVersion(version); } template void SetSourceSSAVersion(size_t version) { As().SetSourceSSAVersion(version); } @@ -590,7 +626,6 @@ namespace BinaryNinja template void SetDestMemoryVersion(size_t version) { As().SetDestMemoryVersion(version); } template void SetSourceMemoryVersion(size_t version) { As().SetSourceMemoryVersion(version); } template void SetOutputSSARegisters(const std::vector& regs) { As().SetOutputSSARegisters(regs); } - template void SetParameterSSARegisters(const std::vector& regs) { As().SetParameterSSARegisters(regs); } bool GetOperandIndexForUsage(LowLevelILOperandUsage usage, size_t& operandIndex) const; @@ -632,12 +667,13 @@ namespace BinaryNinja size_t GetDestMemoryVersion() const; BNLowLevelILFlagCondition GetFlagCondition() const; LowLevelILSSARegisterList GetOutputSSARegisters() const; - LowLevelILSSARegisterList GetParameterSSARegisters() const; + LowLevelILInstructionList GetParameterExprs() const; LowLevelILSSARegisterList GetSourceSSARegisters() const; LowLevelILSSARegisterStackList GetSourceSSARegisterStacks() const; LowLevelILSSAFlagList GetSourceSSAFlags() const; LowLevelILIndexList GetSourceMemoryVersions() const; LowLevelILIndexList GetTargetList() const; + std::map GetRegisterStackAdjustments() const; }; class LowLevelILOperand @@ -665,9 +701,11 @@ namespace BinaryNinja SSARegisterStack GetSSARegisterStack() const; SSAFlag GetSSAFlag() const; LowLevelILIndexList GetIndexList() const; + LowLevelILInstructionList GetExprList() const; LowLevelILSSARegisterList GetSSARegisterList() const; LowLevelILSSARegisterStackList GetSSARegisterStackList() const; LowLevelILSSAFlagList GetSSAFlagList() const; + std::map GetRegisterStackAdjustments() const; }; class LowLevelILOperandList @@ -915,6 +953,7 @@ namespace BinaryNinja { LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } size_t GetStackAdjustment() const { return (size_t)GetRawOperandAsInteger(1); } + std::map GetRegisterStackAdjustments() const { return GetRawOperandAsRegisterStackAdjustments(2); } }; template <> struct LowLevelILInstructionAccessor: public LowLevelILInstructionBase { @@ -949,12 +988,11 @@ namespace BinaryNinja LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(1); } SSARegister GetStackSSARegister() const { return GetRawOperandAsExpr(2).GetRawOperandAsSSARegister(0); } size_t GetSourceMemoryVersion() const { return GetRawOperandAsExpr(2).GetRawOperandAsIndex(2); } - LowLevelILSSARegisterList GetParameterSSARegisters() const { return GetRawOperandAsExpr(3).GetRawOperandAsSSARegisterList(0); } + LowLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExpr(3).GetRawOperandAsExprList(0); } void SetDestMemoryVersion(size_t version) { GetRawOperandAsExpr(0).UpdateRawOperand(0, version); } void SetSourceMemoryVersion(size_t version) { GetRawOperandAsExpr(2).UpdateRawOperand(2, version); } void SetStackSSAVersion(size_t version) { GetRawOperandAsExpr(2).UpdateRawOperand(1, version); } void SetOutputSSARegisters(const std::vector& regs) { GetRawOperandAsExpr(0).UpdateRawOperandAsSSARegisterList(1, regs); } - void SetParameterSSARegisters(const std::vector& regs) { GetRawOperandAsExpr(3).UpdateRawOperandAsSSARegisterList(0, regs); } }; template <> struct LowLevelILInstructionAccessor: public LowLevelILInstructionBase { @@ -962,12 +1000,11 @@ namespace BinaryNinja size_t GetDestMemoryVersion() const { return GetRawOperandAsExpr(0).GetRawOperandAsIndex(0); } SSARegister GetStackSSARegister() const { return GetRawOperandAsExpr(1).GetRawOperandAsSSARegister(0); } size_t GetSourceMemoryVersion() const { return GetRawOperandAsExpr(1).GetRawOperandAsIndex(2); } - LowLevelILSSARegisterList GetParameterSSARegisters() const { return GetRawOperandAsExpr(2).GetRawOperandAsSSARegisterList(0); } + LowLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExpr(2).GetRawOperandAsExprList(0); } void SetDestMemoryVersion(size_t version) { GetRawOperandAsExpr(0).UpdateRawOperand(0, version); } void SetSourceMemoryVersion(size_t version) { GetRawOperandAsExpr(1).UpdateRawOperand(2, version); } void SetStackSSAVersion(size_t version) { GetRawOperandAsExpr(1).UpdateRawOperand(1, version); } void SetOutputSSARegisters(const std::vector& regs) { GetRawOperandAsExpr(0).UpdateRawOperandAsSSARegisterList(1, regs); } - void SetParameterSSARegisters(const std::vector& regs) { GetRawOperandAsExpr(2).UpdateRawOperandAsSSARegisterList(0, regs); } }; template <> struct LowLevelILInstructionAccessor: public LowLevelILInstructionBase diff --git a/python/architecture.py b/python/architecture.py index 04179e7f..c4179b00 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -231,7 +231,7 @@ class Architecture(object): for j in xrange(0, info.topRelativeCount): top_rel.append(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j)) top = core.BNGetArchitectureRegisterName(self.handle, info.stackTopReg) - self.reg_stacks[name] = function.RegisterStackInfo(storage, top_rel, top) + self.reg_stacks[name] = function.RegisterStackInfo(storage, top_rel, top, regs[i]) core.BNFreeRegisterList(regs) else: startup._init_plugins() diff --git a/python/callingconvention.py b/python/callingconvention.py index 18662fc5..5aad3317 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -28,6 +28,7 @@ import log import types import function import binaryview +from enums import VariableSourceType class CallingConvention(object): @@ -68,6 +69,8 @@ class CallingConvention(object): self._cb.getImplicitlyDefinedRegisters = self._cb.getImplicitlyDefinedRegisters.__class__(self._get_implicitly_defined_regs) self._cb.getIncomingRegisterValue = self._cb.getIncomingRegisterValue.__class__(self._get_incoming_reg_value) self._cb.getIncomingFlagValue = self._cb.getIncomingFlagValue.__class__(self._get_incoming_flag_value) + self._cb.getIncomingVariableForParameterVariable = self._cb.getIncomingVariableForParameterVariable.__class__(self._get_incoming_var_for_parameter_var) + self._cb.getParameterVariableForIncomingVariable = self._cb.getParameterVariableForIncomingVariable.__class__(self._get_parameter_var_for_incoming_var) self.handle = core.BNCreateCallingConvention(arch.handle, name, self._cb) self.__class__._registered_calling_conventions.append(self) else: @@ -301,6 +304,42 @@ class CallingConvention(object): result[0].state = api_obj.state result[0].value = api_obj.value + def _get_incoming_var_for_parameter_var(self, ctxt, in_var, func, result): + try: + if func is None: + func_obj = None + else: + func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), + core.BNNewFunctionReference(func)) + in_var_obj = function.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage) + out_var = self.perform_get_incoming_var_for_parameter_var(in_var_obj, func_obj) + result[0].type = out_var.source_type + result[0].index = out_var.index + result[0].storage = out_var.storage + except: + log.log_error(traceback.format_exc()) + result[0].type = in_var[0].type + result[0].index = in_var[0].index + result[0].storage = in_var[0].storage + + def _get_parameter_var_for_incoming_var(self, ctxt, in_var, func, result): + try: + if func is None: + func_obj = None + else: + func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), + core.BNNewFunctionReference(func)) + in_var_obj = function.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage) + out_var = self.perform_get_parameter_var_for_incoming_var(in_var_obj, func_obj) + result[0].type = out_var.source_type + result[0].index = out_var.index + result[0].storage = out_var.storage + except: + log.log_error(traceback.format_exc()) + result[0].type = in_var[0].type + result[0].index = in_var[0].index + result[0].storage = in_var[0].storage + def __repr__(self): return "" % (self.arch.name, self.name) @@ -317,6 +356,25 @@ class CallingConvention(object): def perform_get_incoming_flag_value(self, reg, func): return function.RegisterValue() + def perform_get_incoming_var_for_parameter_var(self, in_var, func): + in_buf = core.BNVariable() + in_buf.type = in_var.source_type + in_buf.index = in_var.index + in_buf.storage = in_var.storage + out_var = core.BNGetDefaultIncomingVariableForParameterVariable(self.handle, in_buf) + name = None + if (func is not None) and (out_var.type == VariableSourceType.RegisterVariableSourceType): + name = func.arch.get_reg_name(out_var.storage) + return function.Variable(func, out_var.type, out_var.index, out_var.storage, name) + + def perform_get_parameter_var_for_incoming_var(self, in_var, func): + in_buf = core.BNVariable() + in_buf.type = in_var.source_type + in_buf.index = in_var.index + in_buf.storage = in_var.storage + out_var = core.BNGetDefaultParameterVariableForIncomingVariable(self.handle, in_buf) + return function.Variable(func, out_var.type, out_var.index, out_var.storage) + def with_confidence(self, confidence): return CallingConvention(self.arch, handle = core.BNNewCallingConventionReference(self.handle), confidence = confidence) @@ -334,3 +392,30 @@ class CallingConvention(object): if func is not None: func_handle = func.handle return function.RegisterValue(self.arch, core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle)) + + def get_incoming_var_for_parameter_var(self, in_var, func): + in_buf = core.BNVariable() + in_buf.type = in_var.source_type + in_buf.index = in_var.index + in_buf.storage = in_var.storage + if func is None: + func_obj = None + else: + func_obj = func.handle + out_var = core.BNGetIncomingVariableForParameterVariable(self.handle, in_buf, func_obj) + name = None + if (func is not None) and (out_var.type == VariableSourceType.RegisterVariableSourceType): + name = func.arch.get_reg_name(out_var.storage) + return function.Variable(func, out_var.type, out_var.index, out_var.storage, name) + + def get_parameter_var_for_incoming_var(self, in_var, func): + in_buf = core.BNVariable() + in_buf.type = in_var.source_type + in_buf.index = in_var.index + in_buf.storage = in_var.storage + if func is None: + func_obj = None + else: + func_obj = func.handle + out_var = core.BNGetParameterVariableForIncomingVariable(self.handle, in_buf, func_obj) + return function.Variable(func, out_var.type, out_var.index, out_var.storage) diff --git a/python/function.py b/python/function.py index ba00147e..eabf86b3 100644 --- a/python/function.py +++ b/python/function.py @@ -263,14 +263,15 @@ class Variable(object): var.storage = storage self.identifier = core.BNToVariableIdentifier(var) - if name is None: - name = core.BNGetVariableName(func.handle, var) - if var_type is None: - var_type_conf = core.BNGetVariableType(func.handle, var) - if var_type_conf.type: - var_type = types.Type(var_type_conf.type, platform = func.platform, confidence = var_type_conf.confidence) - else: - var_type = None + if func is not None: + if name is None: + name = core.BNGetVariableName(func.handle, var) + if var_type is None: + var_type_conf = core.BNGetVariableType(func.handle, var) + if var_type_conf.type: + var_type = types.Type(var_type_conf.type, platform = func.platform, confidence = var_type_conf.confidence) + else: + var_type = None self.name = name self.type = var_type @@ -519,7 +520,7 @@ class Function(object): result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name, types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence))) result.sort(key = lambda x: x.identifier) - core.BNFreeVariableList(v, count.value) + core.BNFreeVariableNameAndTypeList(v, count.value) return result @property @@ -532,7 +533,7 @@ class Function(object): result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name, types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence))) result.sort(key = lambda x: x.identifier) - core.BNFreeVariableList(v, count.value) + core.BNFreeVariableNameAndTypeList(v, count.value) return result @property @@ -674,6 +675,35 @@ class Function(object): sc.confidence = types.max_confidence core.BNSetUserFunctionStackAdjustment(self.handle, sc) + @property + def reg_stack_adjustments(self): + """Number of entries removed from each register stack after return""" + count = ctypes.c_ulonglong() + adjust = core.BNGetFunctionRegisterStackAdjustments(self.handle, count) + result = {} + for i in xrange(0, count.value): + name = self.arch.get_reg_stack_name(adjust[i].regStack) + value = types.RegisterStackAdjustmentWithConfidence(adjust[i].adjustment, + confidence = adjust[i].confidence) + result[name] = value + core.BNFreeRegisterStackAdjustments(adjust) + return result + + @reg_stack_adjustments.setter + def reg_stack_adjustments(self, value): + adjust = (core.BNRegisterStackAdjustment * len(value))() + i = 0 + for reg_stack in value.keys(): + adjust[i].regStack = self.arch.get_reg_stack_index(reg_stack) + if isinstance(value[reg_stack], types.RegisterStackAdjustmentWithConfidence): + adjust[i].adjustment = value[reg_stack].value + adjust[i].confidence = value[reg_stack].confidence + else: + adjust[i].adjustment = value[reg_stack] + adjust[i].confidence = types.max_confidence + i += 1 + core.BNSetUserFunctionRegisterStackAdjustments(self.handle, adjust, len(value)) + @property def clobbered_regs(self): """Registers that are modified by this function""" @@ -1099,6 +1129,20 @@ class Function(object): sc.confidence = types.max_confidence core.BNSetAutoFunctionStackAdjustment(self.handle, sc) + def set_auto_reg_stack_adjustments(self, value): + adjust = (core.BNRegisterStackAdjustment * len(value))() + i = 0 + for reg_stack in value.keys(): + adjust[i].regStack = self.arch.get_reg_stack_index(reg_stack) + if isinstance(value[reg_stack], types.RegisterStackAdjustmentWithConfidence): + adjust[i].adjustment = value[reg_stack].value + adjust[i].confidence = value[reg_stack].confidence + else: + adjust[i].adjustment = value[reg_stack] + adjust[i].confidence = types.max_confidence + i += 1 + core.BNSetAutoFunctionRegisterStackAdjustments(self.handle, adjust, len(value)) + def set_auto_clobbered_regs(self, value): regs = core.BNRegisterSetWithConfidence() regs.regs = (ctypes.c_uint * len(value))() @@ -1727,10 +1771,11 @@ class RegisterInfo(object): class RegisterStackInfo(object): - def __init__(self, storage_regs, top_relative_regs, stack_top_reg): + def __init__(self, storage_regs, top_relative_regs, stack_top_reg, index=None): self.storage_regs = storage_regs self.top_relative_regs = top_relative_regs self.stack_top_reg = stack_top_reg + self.index = index def __repr__(self): return "" % (len(self.storage_regs), self.stack_top_reg) diff --git a/python/lowlevelil.py b/python/lowlevelil.py index f5a39b7e..3810e742 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -197,7 +197,7 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_JUMP: [("dest", "expr")], LowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")], LowLevelILOperation.LLIL_CALL: [("dest", "expr")], - LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int")], + LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int"), ("reg_stack_adjustments", "reg_stack_adjust")], LowLevelILOperation.LLIL_RET: [("dest", "expr")], LowLevelILOperation.LLIL_NORET: [], LowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")], @@ -258,7 +258,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_ssa"), ("src_memory", "int")], - LowLevelILOperation.LLIL_CALL_PARAM_SSA: [("src", "reg_ssa_list")], + LowLevelILOperation.LLIL_CALL_PARAM_SSA: [("src", "expr_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_ssa"), ("src", "reg_ssa_list")], @@ -334,6 +334,14 @@ class LowLevelILInstruction(object): for i in xrange(count.value): value.append(operand_list[i]) core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "expr_list": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = [] + for i in xrange(count.value): + value.append(LowLevelILInstruction(func, operand_list[i])) + core.BNLowLevelILFreeOperandList(operand_list) elif operand_type == "reg_ssa_list": count = ctypes.c_ulonglong() operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) @@ -364,6 +372,18 @@ class LowLevelILInstruction(object): flag_version = operand_list[(i * 2) + 1] value.append(SSAFlag(ILFlag(func.arch, flag), flag_version)) core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "reg_stack_adjust": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = {} + for i in xrange(count.value / 2): + reg_stack = operand_list[i * 2] + adjust = operand_list[(i * 2) + 1] + if adjust & 0x80000000: + adjust |= ~0x80000000 + value[func.arch.get_reg_stack_name(reg_stack)] = adjust + core.BNLowLevelILFreeOperandList(operand_list) self.operands.append(value) self.__dict__[name] = value i += 1 diff --git a/python/types.py b/python/types.py index 2557db2c..d44cc736 100644 --- a/python/types.py +++ b/python/types.py @@ -680,6 +680,21 @@ class SizeWithConfidence(object): return self.value +class RegisterStackAdjustmentWithConfidence(object): + def __init__(self, value, confidence = max_confidence): + self.value = value + self.confidence = confidence + + def __str__(self): + return str(self.value) + + def __repr__(self): + return repr(self.value) + + def __int__(self): + return self.value + + class RegisterSet(object): def __init__(self, reg_list, confidence = max_confidence): self.regs = reg_list -- cgit v1.3.1 From 06b97009b2a09dc7816f6ace2d6a4bff66cb3f26 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 26 Dec 2017 17:10:07 -0500 Subject: Adding return value registers to function type --- binaryninjaapi.h | 3 +++ binaryninjacore.h | 5 ++++- function.cpp | 40 +++++++++++++++++++++++++++++++++++++++- python/function.py | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 83 insertions(+), 3 deletions(-) (limited to 'python/function.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index af067ae9..d4624ca5 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2204,6 +2204,7 @@ namespace BinaryNinja Ref GetType() const; Confidence> GetReturnType() const; + Confidence> GetReturnRegisters() const; Confidence> GetCallingConvention() const; Confidence> GetParameterVariables() const; Confidence HasVariableArguments() const; @@ -2213,6 +2214,7 @@ namespace BinaryNinja void SetAutoType(Type* type); void SetAutoReturnType(const Confidence>& type); + void SetAutoReturnRegisters(const Confidence>& returnRegs); void SetAutoCallingConvention(const Confidence>& convention); void SetAutoParameterVariables(const Confidence>& vars); void SetAutoHasVariableArguments(const Confidence& varArgs); @@ -2223,6 +2225,7 @@ namespace BinaryNinja void SetUserType(Type* type); void SetReturnType(const Confidence>& type); + void SetReturnRegisters(const Confidence>& returnRegs); void SetCallingConvention(const Confidence>& convention); void SetParameterVariables(const Confidence>& vars); void SetHasVariableArguments(const Confidence& varArgs); diff --git a/binaryninjacore.h b/binaryninjacore.h index 278299bc..7f107c60 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -2180,6 +2180,7 @@ extern "C" BINARYNINJACOREAPI BNType* BNGetFunctionType(BNFunction* func); BINARYNINJACOREAPI BNTypeWithConfidence BNGetFunctionReturnType(BNFunction* func); + BINARYNINJACOREAPI BNRegisterSetWithConfidence BNGetFunctionReturnRegisters(BNFunction* func); BINARYNINJACOREAPI BNCallingConventionWithConfidence BNGetFunctionCallingConvention(BNFunction* func); BINARYNINJACOREAPI BNParameterVariablesWithConfidence BNGetFunctionParameterVariables(BNFunction* func); BINARYNINJACOREAPI void BNFreeParameterVariables(BNParameterVariablesWithConfidence* vars); @@ -2188,9 +2189,10 @@ extern "C" BINARYNINJACOREAPI BNRegisterStackAdjustment* BNGetFunctionRegisterStackAdjustments(BNFunction* func, size_t* count); BINARYNINJACOREAPI void BNFreeRegisterStackAdjustments(BNRegisterStackAdjustment* adjustments); BINARYNINJACOREAPI BNRegisterSetWithConfidence BNGetFunctionClobberedRegisters(BNFunction* func); - BINARYNINJACOREAPI void BNFreeClobberedRegisters(BNRegisterSetWithConfidence* regs); + BINARYNINJACOREAPI void BNFreeRegisterSet(BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNSetAutoFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type); + BINARYNINJACOREAPI void BNSetAutoFunctionReturnRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNSetAutoFunctionCallingConvention(BNFunction* func, BNCallingConventionWithConfidence* convention); BINARYNINJACOREAPI void BNSetAutoFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI void BNSetAutoFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); @@ -2201,6 +2203,7 @@ extern "C" BINARYNINJACOREAPI void BNSetAutoFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNSetUserFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type); + BINARYNINJACOREAPI void BNSetUserFunctionReturnRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); BINARYNINJACOREAPI void BNSetUserFunctionCallingConvention(BNFunction* func, BNCallingConventionWithConfidence* convention); BINARYNINJACOREAPI void BNSetUserFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI void BNSetUserFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); diff --git a/function.cpp b/function.cpp index 879c7156..ba2b419e 100644 --- a/function.cpp +++ b/function.cpp @@ -490,6 +490,18 @@ Confidence> Function::GetReturnType() const } +Confidence> Function::GetReturnRegisters() const +{ + BNRegisterSetWithConfidence regs = BNGetFunctionReturnRegisters(m_object); + vector regList; + for (size_t i = 0; i < regs.count; i++) + regList.push_back(regs.regs[i]); + Confidence> result(regList, regs.confidence); + BNFreeRegisterSet(®s); + return result; +} + + Confidence> Function::GetCallingConvention() const { BNCallingConventionWithConfidence cc = BNGetFunctionCallingConvention(m_object); @@ -549,7 +561,7 @@ Confidence> Function::GetClobberedRegisters() const for (size_t i = 0; i < regs.count; i++) regSet.insert(regs.regs[i]); Confidence> result(regSet, regs.confidence); - BNFreeClobberedRegisters(®s); + BNFreeRegisterSet(®s); return result; } @@ -569,6 +581,19 @@ void Function::SetAutoReturnType(const Confidence>& type) } +void Function::SetAutoReturnRegisters(const Confidence>& returnRegs) +{ + BNRegisterSetWithConfidence regs; + regs.regs = new uint32_t[returnRegs.GetValue().size()]; + regs.count = returnRegs.GetValue().size(); + for (size_t i = 0; i < regs.count; i++) + regs.regs[i] = returnRegs.GetValue()[i]; + regs.confidence = returnRegs.GetConfidence(); + BNSetAutoFunctionReturnRegisters(m_object, ®s); + delete[] regs.regs; +} + + void Function::SetAutoCallingConvention(const Confidence>& convention) { BNCallingConventionWithConfidence cc; @@ -668,6 +693,19 @@ void Function::SetReturnType(const Confidence>& type) } +void Function::SetReturnRegisters(const Confidence>& returnRegs) +{ + BNRegisterSetWithConfidence regs; + regs.regs = new uint32_t[returnRegs.GetValue().size()]; + regs.count = returnRegs.GetValue().size(); + for (size_t i = 0; i < regs.count; i++) + regs.regs[i] = returnRegs.GetValue()[i]; + regs.confidence = returnRegs.GetConfidence(); + BNSetUserFunctionReturnRegisters(m_object, ®s); + delete[] regs.regs; +} + + void Function::SetCallingConvention(const Confidence>& convention) { BNCallingConventionWithConfidence cc; diff --git a/python/function.py b/python/function.py index eabf86b3..db4ca0f5 100644 --- a/python/function.py +++ b/python/function.py @@ -592,6 +592,30 @@ class Function(object): type_conf.confidence = value.confidence core.BNSetUserFunctionReturnType(self.handle, type_conf) + @property + def return_regs(self): + """Registers that are used for the return value""" + result = core.BNGetFunctionReturnRegisters(self.handle) + reg_set = [] + for i in xrange(0, result.count): + reg_set.append(self.arch.get_reg_name(result.regs[i])) + regs = types.RegisterSet(reg_set, confidence = result.confidence) + core.BNFreeRegisterSet(result) + return regs + + @return_regs.setter + def return_regs(self, value): + regs = core.BNRegisterSetWithConfidence() + regs.regs = (ctypes.c_uint * len(value))() + regs.count = len(value) + for i in xrange(0, len(value)): + regs.regs[i] = self.arch.get_reg_index(value[i]) + if hasattr(value, 'confidence'): + regs.confidence = value.confidence + else: + regs.confidence = types.max_confidence + core.BNSetUserFunctionReturnRegisters(self.handle, regs) + @property def calling_convention(self): """Calling convention used by the function""" @@ -712,7 +736,7 @@ class Function(object): for i in xrange(0, result.count): reg_set.append(self.arch.get_reg_name(result.regs[i])) regs = types.RegisterSet(reg_set, confidence = result.confidence) - core.BNFreeClobberedRegisters(result) + core.BNFreeRegisterSet(result) return regs @clobbered_regs.setter @@ -1072,6 +1096,18 @@ class Function(object): type_conf.confidence = value.confidence core.BNSetAutoFunctionReturnType(self.handle, type_conf) + def set_auto_return_regs(self, value): + regs = core.BNRegisterSetWithConfidence() + regs.regs = (ctypes.c_uint * len(value))() + regs.count = len(value) + for i in xrange(0, len(value)): + regs.regs[i] = self.arch.get_reg_index(value[i]) + if hasattr(value, 'confidence'): + regs.confidence = value.confidence + else: + regs.confidence = types.max_confidence + core.BNSetAutoFunctionReturnRegisters(self.handle, regs) + def set_auto_calling_convention(self, value): conv_conf = core.BNCallingConventionWithConfidence() if value is None: -- cgit v1.3.1 From 2f3873928078e8c21911ffeb5476781b31886514 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 31 Jan 2018 20:24:16 -0500 Subject: Adding CPU intrinsics support --- architecture.cpp | 159 +++++++++++++++++++ binaryninjaapi.h | 39 +++++ binaryninjacore.h | 40 ++++- lowlevelil.cpp | 25 +++ lowlevelilinstruction.cpp | 355 ++++++++++++++++++++++++++++++++++++++++++- lowlevelilinstruction.h | 129 ++++++++++++++++ mediumlevelilinstruction.cpp | 71 ++++++++- mediumlevelilinstruction.h | 20 +++ python/architecture.py | 154 +++++++++++++++++++ python/function.py | 23 ++- python/lowlevelil.py | 109 ++++++++++--- python/mediumlevelil.py | 4 + 12 files changed, 1095 insertions(+), 33 deletions(-) (limited to 'python/function.py') diff --git a/architecture.cpp b/architecture.cpp index 78a67105..223af13d 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -491,6 +491,79 @@ void Architecture::GetRegisterStackInfoCallback(void* ctxt, uint32_t regStack, B } +char* Architecture::GetIntrinsicNameCallback(void* ctxt, uint32_t intrinsic) +{ + Architecture* arch = (Architecture*)ctxt; + string result = arch->GetIntrinsicName(intrinsic); + return BNAllocString(result.c_str()); +} + + +uint32_t* Architecture::GetAllIntrinsicsCallback(void* ctxt, size_t* count) +{ + Architecture* arch = (Architecture*)ctxt; + vector regs = arch->GetAllIntrinsics(); + *count = regs.size(); + + uint32_t* result = new uint32_t[regs.size()]; + for (size_t i = 0; i < regs.size(); i++) + result[i] = regs[i]; + return result; +} + + +BNNameAndType* Architecture::GetIntrinsicInputsCallback(void* ctxt, uint32_t intrinsic, size_t* count) +{ + Architecture* arch = (Architecture*)ctxt; + vector inputs = arch->GetIntrinsicInputs(intrinsic); + *count = inputs.size(); + + BNNameAndType* result = new BNNameAndType[inputs.size()]; + for (size_t i = 0; i < inputs.size(); i++) + { + result[i].name = BNAllocString(inputs[i].name.c_str()); + result[i].type = BNNewTypeReference(inputs[i].type.GetValue()->GetObject()); + result[i].typeConfidence = inputs[i].type.GetConfidence(); + } + return result; +} + + +void Architecture::FreeNameAndTypeListCallback(void*, BNNameAndType* nt, size_t count) +{ + for (size_t i = 0; i < count; i++) + { + BNFreeString(nt[i].name); + BNFreeType(nt[i].type); + } + delete[] nt; +} + + +BNTypeWithConfidence* Architecture::GetIntrinsicOutputsCallback(void* ctxt, uint32_t intrinsic, size_t* count) +{ + Architecture* arch = (Architecture*)ctxt; + vector>> outputs = arch->GetIntrinsicOutputs(intrinsic); + *count = outputs.size(); + + BNTypeWithConfidence* result = new BNTypeWithConfidence[outputs.size()]; + for (size_t i = 0; i < outputs.size(); i++) + { + result[i].type = BNNewTypeReference(outputs[i].GetValue()->GetObject()); + result[i].confidence = outputs[i].GetConfidence(); + } + return result; +} + + +void Architecture::FreeTypeListCallback(void*, BNTypeWithConfidence* types, size_t count) +{ + for (size_t i = 0; i < count; i++) + BNFreeType(types[i].type); + delete[] types; +} + + bool Architecture::AssembleCallback(void* ctxt, const char* code, uint64_t addr, BNDataBuffer* result, char** errors) { Architecture* arch = (Architecture*)ctxt; @@ -612,6 +685,12 @@ void Architecture::Register(Architecture* arch) callbacks.getRegisterStackName = GetRegisterStackNameCallback; callbacks.getAllRegisterStacks = GetAllRegisterStacksCallback; callbacks.getRegisterStackInfo = GetRegisterStackInfoCallback; + callbacks.getIntrinsicName = GetIntrinsicNameCallback; + callbacks.getAllIntrinsics = GetAllIntrinsicsCallback; + callbacks.getIntrinsicInputs = GetIntrinsicInputsCallback; + callbacks.freeNameAndTypeList = FreeNameAndTypeListCallback; + callbacks.getIntrinsicOutputs = GetIntrinsicOutputsCallback; + callbacks.freeTypeList = FreeTypeListCallback; callbacks.assemble = AssembleCallback; callbacks.isNeverBranchPatchAvailable = IsNeverBranchPatchAvailableCallback; callbacks.isAlwaysBranchPatchAvailable = IsAlwaysBranchPatchAvailableCallback; @@ -920,6 +999,32 @@ uint32_t Architecture::GetRegisterStackForRegister(uint32_t reg) } +string Architecture::GetIntrinsicName(uint32_t intrinsic) +{ + char intrinsicStr[32]; + sprintf(intrinsicStr, "intrinsic_%" PRIu32, intrinsic); + return intrinsicStr; +} + + +vector Architecture::GetAllIntrinsics() +{ + return vector(); +} + + +vector Architecture::GetIntrinsicInputs(uint32_t) +{ + return vector(); +} + + +vector>> Architecture::GetIntrinsicOutputs(uint32_t) +{ + return vector>>(); +} + + vector Architecture::GetModifiedRegistersOnWrite(uint32_t reg) { size_t count; @@ -1477,6 +1582,60 @@ BNRegisterStackInfo CoreArchitecture::GetRegisterStackInfo(uint32_t regStack) } +string CoreArchitecture::GetIntrinsicName(uint32_t intrinsic) +{ + char* name = BNGetArchitectureIntrinsicName(m_object, intrinsic); + string result = name; + BNFreeString(name); + return result; +} + + +vector CoreArchitecture::GetAllIntrinsics() +{ + size_t count; + uint32_t* regs = BNGetAllArchitectureIntrinsics(m_object, &count); + + vector result; + for (size_t i = 0; i < count; i++) + result.push_back(regs[i]); + + BNFreeRegisterList(regs); + return result; +} + + +vector CoreArchitecture::GetIntrinsicInputs(uint32_t intrinsic) +{ + size_t count; + BNNameAndType* inputs = BNGetArchitectureIntrinsicInputs(m_object, intrinsic, &count); + + vector result; + for (size_t i = 0; i < count; i++) + { + result.push_back(NameAndType(inputs[i].name, Confidence>( + new Type(BNNewTypeReference(inputs[i].type)), inputs[i].typeConfidence))); + } + + BNFreeNameAndTypeList(inputs, count); + return result; +} + + +vector>> CoreArchitecture::GetIntrinsicOutputs(uint32_t intrinsic) +{ + size_t count; + BNTypeWithConfidence* outputs = BNGetArchitectureIntrinsicOutputs(m_object, intrinsic, &count); + + vector>> result; + for (size_t i = 0; i < count; i++) + result.push_back(Confidence>(new Type(BNNewTypeReference(outputs[i].type)), outputs[i].confidence)); + + BNFreeOutputTypeList(outputs, count); + return result; +} + + bool CoreArchitecture::Assemble(const string& code, uint64_t addr, DataBuffer& result, string& errors) { char* errorStr = nullptr; diff --git a/binaryninjaapi.h b/binaryninjaapi.h index b74fa971..d1ca9cdb 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1566,6 +1566,16 @@ namespace BinaryNinja void AddBranch(BNBranchType type, uint64_t target = 0, Architecture* arch = nullptr, bool hasDelaySlot = false); }; + struct NameAndType + { + std::string name; + Confidence> type; + + NameAndType() {} + NameAndType(const Confidence>& t): type(t) {} + NameAndType(const std::string& n, const Confidence>& t): name(n), type(t) {} + }; + class LowLevelILFunction; class FunctionRecognizer; class CallingConvention; @@ -1633,6 +1643,13 @@ namespace BinaryNinja static uint32_t* GetAllRegisterStacksCallback(void* ctxt, size_t* count); static void GetRegisterStackInfoCallback(void* ctxt, uint32_t regStack, BNRegisterStackInfo* result); + static char* GetIntrinsicNameCallback(void* ctxt, uint32_t intrinsic); + static uint32_t* GetAllIntrinsicsCallback(void* ctxt, size_t* count); + static BNNameAndType* GetIntrinsicInputsCallback(void* ctxt, uint32_t intrinsic, size_t* count); + static void FreeNameAndTypeListCallback(void* ctxt, BNNameAndType* nt, size_t count); + static BNTypeWithConfidence* GetIntrinsicOutputsCallback(void* ctxt, uint32_t intrinsic, size_t* count); + static void FreeTypeListCallback(void* ctxt, BNTypeWithConfidence* types, size_t count); + static bool AssembleCallback(void* ctxt, const char* code, uint64_t addr, BNDataBuffer* result, char** errors); static bool IsNeverBranchPatchAvailableCallback(void* ctxt, const uint8_t* data, uint64_t addr, size_t len); static bool IsAlwaysBranchPatchAvailableCallback(void* ctxt, const uint8_t* data, uint64_t addr, size_t len); @@ -1714,6 +1731,11 @@ namespace BinaryNinja virtual BNRegisterStackInfo GetRegisterStackInfo(uint32_t regStack); uint32_t GetRegisterStackForRegister(uint32_t reg); + virtual std::string GetIntrinsicName(uint32_t intrinsic); + virtual std::vector GetAllIntrinsics(); + virtual std::vector GetIntrinsicInputs(uint32_t intrinsic); + virtual std::vector>> GetIntrinsicOutputs(uint32_t intrinsic); + virtual bool Assemble(const std::string& code, uint64_t addr, DataBuffer& result, std::string& errors); /*! IsNeverBranchPatchAvailable returns true if the instruction at addr can be patched to never branch. @@ -1853,6 +1875,11 @@ namespace BinaryNinja virtual std::vector GetAllRegisterStacks() override; virtual BNRegisterStackInfo GetRegisterStackInfo(uint32_t regStack) override; + virtual std::string GetIntrinsicName(uint32_t intrinsic) override; + virtual std::vector GetAllIntrinsics() override; + virtual std::vector GetIntrinsicInputs(uint32_t intrinsic) override; + virtual std::vector>> GetIntrinsicOutputs(uint32_t intrinsic) override; + virtual bool Assemble(const std::string& code, uint64_t addr, DataBuffer& result, std::string& errors) override; virtual bool IsNeverBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override; @@ -2452,9 +2479,11 @@ namespace BinaryNinja }; struct LowLevelILInstruction; + struct RegisterOrFlag; struct SSARegister; struct SSARegisterStack; struct SSAFlag; + struct SSARegisterOrFlag; class LowLevelILFunction: public CoreRefCountObject @@ -2641,6 +2670,10 @@ namespace BinaryNinja ExprId TestBit(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation()); ExprId BoolToInt(size_t size, ExprId a, const ILSourceLocation& loc = ILSourceLocation()); ExprId SystemCall(const ILSourceLocation& loc = ILSourceLocation()); + ExprId Intrinsic(const std::vector& outputs, uint32_t intrinsic, + const std::vector& params, const ILSourceLocation& loc = ILSourceLocation()); + ExprId IntrinsicSSA(const std::vector& outputs, uint32_t intrinsic, + const std::vector& params, const ILSourceLocation& loc = ILSourceLocation()); ExprId Breakpoint(const ILSourceLocation& loc = ILSourceLocation()); ExprId Trap(uint32_t num, const ILSourceLocation& loc = ILSourceLocation()); ExprId Undefined(const ILSourceLocation& loc = ILSourceLocation()); @@ -2686,9 +2719,11 @@ namespace BinaryNinja ExprId AddLabelList(const std::vector& labels); ExprId AddOperandList(const std::vector operands); ExprId AddIndexList(const std::vector operands); + ExprId AddRegisterOrFlagList(const std::vector& regs); ExprId AddSSARegisterList(const std::vector& regs); ExprId AddSSARegisterStackList(const std::vector& regStacks); ExprId AddSSAFlagList(const std::vector& flags); + ExprId AddSSARegisterOrFlagList(const std::vector& regs); ExprId GetExprForRegisterOrConstant(const BNRegisterOrConstant& operand, size_t size); ExprId GetNegExprForRegisterOrConstant(const BNRegisterOrConstant& operand, size_t size); @@ -2954,6 +2989,10 @@ namespace BinaryNinja const ILSourceLocation& loc = ILSourceLocation()); ExprId Breakpoint(const ILSourceLocation& loc = ILSourceLocation()); ExprId Trap(int64_t vector, const ILSourceLocation& loc = ILSourceLocation()); + ExprId Intrinsic(const std::vector& outputs, uint32_t intrinsic, + const std::vector& params, const ILSourceLocation& loc = ILSourceLocation()); + ExprId IntrinsicSSA(const std::vector& outputs, uint32_t intrinsic, + const std::vector& params, const ILSourceLocation& loc = ILSourceLocation()); ExprId Undefined(const ILSourceLocation& loc = ILSourceLocation()); ExprId Unimplemented(const ILSourceLocation& loc = ILSourceLocation()); ExprId UnimplementedMemoryRef(size_t size, ExprId target, diff --git a/binaryninjacore.h b/binaryninjacore.h index bc58092d..a946df31 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -352,6 +352,7 @@ extern "C" LLIL_SYSCALL, LLIL_BP, LLIL_TRAP, + LLIL_INTRINSIC, LLIL_UNDEF, LLIL_UNIMPL, LLIL_UNIMPL_MEM, @@ -394,11 +395,12 @@ extern "C" LLIL_FLAG_BIT_SSA, LLIL_CALL_SSA, LLIL_SYSCALL_SSA, - LLIL_CALL_PARAM_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions + LLIL_CALL_PARAM, // Only valid within the LLIL_CALL_SSA, LLIL_SYSCALL_SSA, LLIL_INTRINSIC, LLIL_INTRINSIC_SSA instructions LLIL_CALL_STACK_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions LLIL_CALL_OUTPUT_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions LLIL_LOAD_SSA, LLIL_STORE_SSA, + LLIL_INTRINSIC_SSA, LLIL_REG_PHI, LLIL_REG_STACK_PHI, LLIL_FLAG_PHI, @@ -858,6 +860,7 @@ extern "C" MLIL_ADD_OVERFLOW, MLIL_SYSCALL, // Not valid in SSA form (see MLIL_SYSCALL_SSA) MLIL_SYSCALL_UNTYPED, // Not valid in SSA form (see MLIL_SYSCALL_UNTYPED_SSA) + MLIL_INTRINSIC, // Not valid in SSA form (see MLIL_INTRINSIC_SSA) MLIL_BP, MLIL_TRAP, MLIL_UNDEF, @@ -905,6 +908,7 @@ extern "C" MLIL_LOAD_STRUCT_SSA, MLIL_STORE_SSA, MLIL_STORE_STRUCT_SSA, + MLIL_INTRINSIC_SSA, MLIL_VAR_PHI, MLIL_MEM_PHI }; @@ -1077,6 +1081,19 @@ extern "C" BNLowLevelILFlagCondition condition; }; + struct BNNameAndType + { + char* name; + BNType* type; + uint8_t typeConfidence; + }; + + struct BNTypeWithConfidence + { + BNType* type; + uint8_t confidence; + }; + struct BNCustomArchitecture { void* context; @@ -1127,6 +1144,13 @@ extern "C" uint32_t* (*getAllRegisterStacks)(void* ctxt, size_t* count); void (*getRegisterStackInfo)(void* ctxt, uint32_t regStack, BNRegisterStackInfo* result); + char* (*getIntrinsicName)(void* ctxt, uint32_t intrinsic); + uint32_t* (*getAllIntrinsics)(void* ctxt, size_t* count); + BNNameAndType* (*getIntrinsicInputs)(void* ctxt, uint32_t intrinsic, size_t* count); + void (*freeNameAndTypeList)(void* ctxt, BNNameAndType* nt, size_t count); + BNTypeWithConfidence* (*getIntrinsicOutputs)(void* ctxt, uint32_t intrinsic, size_t* count); + void (*freeTypeList)(void* ctxt, BNTypeWithConfidence* types, size_t count); + bool (*assemble)(void* ctxt, const char* code, uint64_t addr, BNDataBuffer* result, char** errors); bool (*isNeverBranchPatchAvailable)(void* ctxt, const uint8_t* data, uint64_t addr, size_t len); @@ -1203,12 +1227,6 @@ extern "C" char* (*serialize)(void* ctxt); }; - struct BNTypeWithConfidence - { - BNType* type; - uint8_t confidence; - }; - struct BNCallingConventionWithConfidence { BNCallingConvention* convention; @@ -2116,6 +2134,14 @@ extern "C" BINARYNINJACOREAPI BNRegisterStackInfo BNGetArchitectureRegisterStackInfo(BNArchitecture* arch, uint32_t regStack); BINARYNINJACOREAPI uint32_t BNGetArchitectureRegisterStackForRegister(BNArchitecture* arch, uint32_t reg); + BINARYNINJACOREAPI char* BNGetArchitectureIntrinsicName(BNArchitecture* arch, uint32_t intrinsic); + BINARYNINJACOREAPI uint32_t* BNGetAllArchitectureIntrinsics(BNArchitecture* arch, size_t* count); + BINARYNINJACOREAPI BNNameAndType* BNGetArchitectureIntrinsicInputs(BNArchitecture* arch, uint32_t intrinsic, size_t* count); + BINARYNINJACOREAPI void BNFreeNameAndTypeList(BNNameAndType* nt, size_t count); + BINARYNINJACOREAPI BNTypeWithConfidence* BNGetArchitectureIntrinsicOutputs(BNArchitecture* arch, uint32_t intrinsic, + size_t* count); + BINARYNINJACOREAPI void BNFreeOutputTypeList(BNTypeWithConfidence* types, size_t count); + BINARYNINJACOREAPI bool BNAssemble(BNArchitecture* arch, const char* code, uint64_t addr, BNDataBuffer* result, char** errors); BINARYNINJACOREAPI bool BNIsArchitectureNeverBranchPatchAvailable(BNArchitecture* arch, const uint8_t* data, diff --git a/lowlevelil.cpp b/lowlevelil.cpp index c72d4b68..0f2b29be 100644 --- a/lowlevelil.cpp +++ b/lowlevelil.cpp @@ -216,6 +216,17 @@ ExprId LowLevelILFunction::AddIndexList(const vector operands) } +ExprId LowLevelILFunction::AddRegisterOrFlagList(const vector& regs) +{ + uint64_t* operandList = new uint64_t[regs.size()]; + for (size_t i = 0; i < regs.size(); i++) + operandList[i] = regs[i].ToIdentifier(); + ExprId result = (ExprId)BNLowLevelILAddOperandList(m_object, operandList, regs.size()); + delete[] operandList; + return result; +} + + ExprId LowLevelILFunction::AddSSARegisterList(const vector& regs) { uint64_t* operandList = new uint64_t[regs.size() * 2]; @@ -258,6 +269,20 @@ ExprId LowLevelILFunction::AddSSAFlagList(const vector& flags) } +ExprId LowLevelILFunction::AddSSARegisterOrFlagList(const vector& regs) +{ + uint64_t* operandList = new uint64_t[regs.size() * 2]; + for (size_t i = 0; i < regs.size(); i++) + { + operandList[i * 2] = regs[i].regOrFlag.ToIdentifier(); + operandList[(i * 2) + 1] = regs[i].version; + } + ExprId result = (ExprId)BNLowLevelILAddOperandList(m_object, operandList, regs.size() * 2); + delete[] operandList; + return result; +} + + ExprId LowLevelILFunction::GetExprForRegisterOrConstant(const BNRegisterOrConstant& operand, size_t size) { if (operand.constant) diff --git a/lowlevelilinstruction.cpp b/lowlevelilinstruction.cpp index 9909e8ee..2c00db68 100644 --- a/lowlevelilinstruction.cpp +++ b/lowlevelilinstruction.cpp @@ -64,6 +64,7 @@ unordered_map {HighSSARegisterLowLevelOperandUsage, SSARegisterLowLevelOperand}, {LowRegisterLowLevelOperandUsage, RegisterLowLevelOperand}, {LowSSARegisterLowLevelOperandUsage, SSARegisterLowLevelOperand}, + {IntrinsicLowLevelOperandUsage, IntrinsicLowLevelOperand}, {ConstantLowLevelOperandUsage, IntegerLowLevelOperand}, {VectorLowLevelOperandUsage, IntegerLowLevelOperand}, {StackAdjustmentLowLevelOperandUsage, IntegerLowLevelOperand}, @@ -80,6 +81,8 @@ unordered_map {SourceSSARegistersLowLevelOperandUsage, SSARegisterListLowLevelOperand}, {SourceSSARegisterStacksLowLevelOperandUsage, SSARegisterStackListLowLevelOperand}, {SourceSSAFlagsLowLevelOperandUsage, SSAFlagListLowLevelOperand}, + {OutputRegisterOrFlagListLowLevelOperandUsage, RegisterOrFlagListLowLevelOperand}, + {OutputSSARegisterOrFlagListLowLevelOperandUsage, SSARegisterOrFlagListLowLevelOperand}, {SourceMemoryVersionsLowLevelOperandUsage, IndexListLowLevelOperand}, {TargetListLowLevelOperandUsage, IndexListLowLevelOperand}, {RegisterStackAdjustmentsLowLevelOperandUsage, RegisterStackAdjustmentsLowLevelOperand} @@ -202,6 +205,10 @@ unordered_map> {LLIL_ZX, {SourceExprLowLevelOperandUsage}}, {LLIL_LOW_PART, {SourceExprLowLevelOperandUsage}}, {LLIL_BOOL_TO_INT, {SourceExprLowLevelOperandUsage}}, + {LLIL_INTRINSIC, {OutputRegisterOrFlagListLowLevelOperandUsage, IntrinsicLowLevelOperandUsage, + ParameterExprsLowLevelOperandUsage}}, + {LLIL_INTRINSIC_SSA, {OutputSSARegisterOrFlagListLowLevelOperandUsage, IntrinsicLowLevelOperandUsage, + ParameterExprsLowLevelOperandUsage}}, {LLIL_UNIMPL_MEM, {SourceExprLowLevelOperandUsage}}, {LLIL_FADD, {LeftExprLowLevelOperandUsage, RightExprLowLevelOperandUsage}}, {LLIL_FSUB, {LeftExprLowLevelOperandUsage, RightExprLowLevelOperandUsage}}, @@ -268,6 +275,8 @@ static unordered_map() const } +const RegisterOrFlag LowLevelILRegisterOrFlagList::ListIterator::operator*() +{ + return RegisterOrFlag::FromIdentifier(*pos); +} + + +LowLevelILRegisterOrFlagList::LowLevelILRegisterOrFlagList(LowLevelILFunction* func, + const BNLowLevelILInstruction& instr, size_t count): m_list(func, instr, count) +{ +} + + +LowLevelILRegisterOrFlagList::const_iterator LowLevelILRegisterOrFlagList::begin() const +{ + const_iterator result; + result.pos = m_list.begin(); + return result; +} + + +LowLevelILRegisterOrFlagList::const_iterator LowLevelILRegisterOrFlagList::end() const +{ + const_iterator result; + result.pos = m_list.end(); + return result; +} + + +size_t LowLevelILRegisterOrFlagList::size() const +{ + return m_list.size(); +} + + +const RegisterOrFlag LowLevelILRegisterOrFlagList::operator[](size_t i) const +{ + if (i >= size()) + throw LowLevelILInstructionAccessException(); + auto iter = begin(); + for (size_t j = 0; j < i; j++) + ++iter; + return *iter; +} + + +LowLevelILRegisterOrFlagList::operator vector() const +{ + vector result; + for (auto& i : *this) + result.push_back(i); + return result; +} + + const SSARegister LowLevelILSSARegisterList::ListIterator::operator*() { LowLevelILIntegerList::const_iterator cur = pos; @@ -818,6 +1004,64 @@ LowLevelILSSAFlagList::operator vector() const } +const SSARegisterOrFlag LowLevelILSSARegisterOrFlagList::ListIterator::operator*() +{ + LowLevelILIntegerList::const_iterator cur = pos; + RegisterOrFlag rf = RegisterOrFlag::FromIdentifier(*cur); + ++cur; + size_t version = (size_t)*cur; + return SSARegisterOrFlag(rf, version); +} + + +LowLevelILSSARegisterOrFlagList::LowLevelILSSARegisterOrFlagList(LowLevelILFunction* func, + const BNLowLevelILInstruction& instr, size_t count): m_list(func, instr, count & (~1)) +{ +} + + +LowLevelILSSARegisterOrFlagList::const_iterator LowLevelILSSARegisterOrFlagList::begin() const +{ + const_iterator result; + result.pos = m_list.begin(); + return result; +} + + +LowLevelILSSARegisterOrFlagList::const_iterator LowLevelILSSARegisterOrFlagList::end() const +{ + const_iterator result; + result.pos = m_list.end(); + return result; +} + + +size_t LowLevelILSSARegisterOrFlagList::size() const +{ + return m_list.size() / 2; +} + + +const SSARegisterOrFlag LowLevelILSSARegisterOrFlagList::operator[](size_t i) const +{ + if (i >= size()) + throw LowLevelILInstructionAccessException(); + auto iter = begin(); + for (size_t j = 0; j < i; j++) + ++iter; + return *iter; +} + + +LowLevelILSSARegisterOrFlagList::operator vector() const +{ + vector result; + for (auto& i : *this) + result.push_back(i); + return result; +} + + LowLevelILOperand::LowLevelILOperand(const LowLevelILInstruction& instr, LowLevelILOperandUsage usage, size_t operandIndex): m_instr(instr), m_usage(usage), m_operandIndex(operandIndex) @@ -905,6 +1149,14 @@ uint32_t LowLevelILOperand::GetSemanticFlagGroup() const } +uint32_t LowLevelILOperand::GetIntrinsic() const +{ + if (m_type != IntrinsicLowLevelOperand) + throw LowLevelILInstructionAccessException(); + return m_instr.GetRawOperandAsRegister(m_operandIndex); +} + + SSARegister LowLevelILOperand::GetSSARegister() const { if (m_type != SSARegisterLowLevelOperand) @@ -952,6 +1204,14 @@ LowLevelILInstructionList LowLevelILOperand::GetExprList() const } +LowLevelILRegisterOrFlagList LowLevelILOperand::GetRegisterOrFlagList() const +{ + if (m_type != RegisterOrFlagListLowLevelOperand) + throw LowLevelILInstructionAccessException(); + return m_instr.GetRawOperandAsRegisterOrFlagList(m_operandIndex); +} + + LowLevelILSSARegisterList LowLevelILOperand::GetSSARegisterList() const { if (m_type != SSARegisterListLowLevelOperand) @@ -978,6 +1238,14 @@ LowLevelILSSAFlagList LowLevelILOperand::GetSSAFlagList() const } +LowLevelILSSARegisterOrFlagList LowLevelILOperand::GetSSARegisterOrFlagList() const +{ + if (m_type != SSARegisterOrFlagListLowLevelOperand) + throw LowLevelILInstructionAccessException(); + return m_instr.GetRawOperandAsSSARegisterOrFlagList(m_operandIndex); +} + + map LowLevelILOperand::GetRegisterStackAdjustments() const { if (m_type != RegisterStackAdjustmentsLowLevelOperand) @@ -1174,6 +1442,12 @@ LowLevelILInstructionList LowLevelILInstructionBase::GetRawOperandAsExprList(siz } +LowLevelILRegisterOrFlagList LowLevelILInstructionBase::GetRawOperandAsRegisterOrFlagList(size_t operand) const +{ + return LowLevelILRegisterOrFlagList(function, function->GetRawExpr(operands[operand + 1]), operands[operand]); +} + + LowLevelILSSARegisterList LowLevelILInstructionBase::GetRawOperandAsSSARegisterList(size_t operand) const { return LowLevelILSSARegisterList(function, function->GetRawExpr(operands[operand + 1]), operands[operand]); @@ -1192,6 +1466,12 @@ LowLevelILSSAFlagList LowLevelILInstructionBase::GetRawOperandAsSSAFlagList(size } +LowLevelILSSARegisterOrFlagList LowLevelILInstructionBase::GetRawOperandAsSSARegisterOrFlagList(size_t operand) const +{ + return LowLevelILSSARegisterOrFlagList(function, function->GetRawExpr(operands[operand + 1]), operands[operand]); +} + + map LowLevelILInstructionBase::GetRawOperandAsRegisterStackAdjustments(size_t operand) const { LowLevelILIntegerList list(function, function->GetRawExpr(operands[operand + 1]), operands[operand]); @@ -1224,6 +1504,14 @@ void LowLevelILInstructionBase::UpdateRawOperandAsSSARegisterList(size_t operand } +void LowLevelILInstructionBase::UpdateRawOperandAsSSARegisterOrFlagList(size_t operandIndex, + const vector& outputs) +{ + UpdateRawOperand(operandIndex, outputs.size() * 2); + UpdateRawOperand(operandIndex + 1, function->AddSSARegisterOrFlagList(outputs)); +} + + RegisterValue LowLevelILInstructionBase::GetValue() const { return function->GetExprValue(*(const LowLevelILInstruction*)this); @@ -1585,6 +1873,14 @@ void LowLevelILInstruction::VisitExprs(const std::function()) + i.VisitExprs(func); + break; + case LLIL_INTRINSIC_SSA: + for (auto& i : GetParameterExprs()) + i.VisitExprs(func); + break; default: break; } @@ -1839,6 +2135,16 @@ ExprId LowLevelILInstruction::CopyTo(LowLevelILFunction* dest, subExprHandler(AsTwoOperandWithCarry().GetLeftExpr()), subExprHandler(AsTwoOperandWithCarry().GetRightExpr()), subExprHandler(AsTwoOperandWithCarry().GetCarryExpr())); + case LLIL_INTRINSIC: + for (auto& i : GetParameterExprs()) + params.push_back(subExprHandler(i)); + return dest->Intrinsic(GetOutputRegisterOrFlagList(), GetIntrinsic(), + params, *this); + case LLIL_INTRINSIC_SSA: + for (auto& i : GetParameterExprs()) + params.push_back(subExprHandler(i)); + return dest->IntrinsicSSA(GetOutputSSARegisterOrFlagList(), GetIntrinsic(), + params, *this); default: throw LowLevelILInstructionAccessException(); } @@ -2103,6 +2409,15 @@ SSARegister LowLevelILInstruction::GetLowSSARegister() const } +uint32_t LowLevelILInstruction::GetIntrinsic() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(IntrinsicLowLevelOperandUsage, operandIndex)) + return GetRawOperandAsRegister(operandIndex); + throw LowLevelILInstructionAccessException(); +} + + int64_t LowLevelILInstruction::GetConstant() const { size_t operandIndex; @@ -2242,6 +2557,24 @@ LowLevelILSSAFlagList LowLevelILInstruction::GetSourceSSAFlags() const } +LowLevelILRegisterOrFlagList LowLevelILInstruction::GetOutputRegisterOrFlagList() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(OutputRegisterOrFlagListLowLevelOperandUsage, operandIndex)) + return GetRawOperandAsRegisterOrFlagList(operandIndex); + throw LowLevelILInstructionAccessException(); +} + + +LowLevelILSSARegisterOrFlagList LowLevelILInstruction::GetOutputSSARegisterOrFlagList() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(OutputSSARegisterOrFlagListLowLevelOperandUsage, operandIndex)) + return GetRawOperandAsSSARegisterOrFlagList(operandIndex); + throw LowLevelILInstructionAccessException(); +} + + LowLevelILIndexList LowLevelILInstruction::GetSourceMemoryVersions() const { size_t operandIndex; @@ -2759,7 +3092,7 @@ ExprId LowLevelILFunction::CallSSA(const vector& output, ExprId des AddExprWithLocation(LLIL_CALL_OUTPUT_SSA, loc, 0, 0, newMemoryVer, output.size() * 2, AddSSARegisterList(output)), dest, AddExprWithLocation(LLIL_CALL_STACK_SSA, loc, 0, 0, stack.reg, stack.version, prevMemoryVer), - AddExprWithLocation(LLIL_CALL_PARAM_SSA, loc, 0, 0, + AddExprWithLocation(LLIL_CALL_PARAM, loc, 0, 0, params.size(), AddOperandList(params))); } @@ -2771,7 +3104,7 @@ ExprId LowLevelILFunction::SystemCallSSA(const vector& output, cons AddExprWithLocation(LLIL_CALL_OUTPUT_SSA, loc, 0, 0, newMemoryVer, output.size() * 2, AddSSARegisterList(output)), AddExprWithLocation(LLIL_CALL_STACK_SSA, loc, 0, 0, stack.reg, stack.version, prevMemoryVer), - AddExprWithLocation(LLIL_CALL_PARAM_SSA, loc, 0, 0, + AddExprWithLocation(LLIL_CALL_PARAM, loc, 0, 0, params.size(), AddOperandList(params))); } @@ -2878,6 +3211,24 @@ ExprId LowLevelILFunction::SystemCall(const ILSourceLocation& loc) } +ExprId LowLevelILFunction::Intrinsic(const vector& outputs, uint32_t intrinsic, + const vector& params, const ILSourceLocation& loc) +{ + return AddExprWithLocation(LLIL_INTRINSIC, loc, 0, 0, + outputs.size(), AddRegisterOrFlagList(outputs), intrinsic, + AddExprWithLocation(LLIL_CALL_PARAM, loc, 0, 0, params.size(), AddOperandList(params))); +} + + +ExprId LowLevelILFunction::IntrinsicSSA(const vector& outputs, uint32_t intrinsic, + const vector& params, const ILSourceLocation& loc) +{ + return AddExprWithLocation(LLIL_INTRINSIC_SSA, loc, 0, 0, + outputs.size() * 2, AddSSARegisterOrFlagList(outputs), intrinsic, + AddExprWithLocation(LLIL_CALL_PARAM, loc, 0, 0, params.size(), AddOperandList(params))); +} + + ExprId LowLevelILFunction::Breakpoint(const ILSourceLocation& loc) { return AddExprWithLocation(LLIL_BP, loc, 0, 0); diff --git a/lowlevelilinstruction.h b/lowlevelilinstruction.h index bb5041a6..4679f556 100644 --- a/lowlevelilinstruction.h +++ b/lowlevelilinstruction.h @@ -54,6 +54,31 @@ namespace BinaryNinja class LowLevelILOperand; class LowLevelILOperandList; + struct RegisterOrFlag + { + bool isFlag; + uint32_t index; + + RegisterOrFlag(); + RegisterOrFlag(bool flag, uint32_t i); + + bool IsRegister() const { return !isFlag; } + bool IsFlag() const { return isFlag; } + uint32_t GetRegister() const; + uint32_t GetFlag() const; + + RegisterOrFlag& operator=(const RegisterOrFlag& v); + bool operator==(const RegisterOrFlag& v) const; + bool operator!=(const RegisterOrFlag& v) const; + bool operator<(const RegisterOrFlag& v) const; + + uint64_t ToIdentifier() const; + static RegisterOrFlag FromIdentifier(uint64_t id); + + static RegisterOrFlag Register(uint32_t reg) { return RegisterOrFlag(false, reg); } + static RegisterOrFlag Flag(uint32_t flag) { return RegisterOrFlag(true, flag); } + }; + struct SSARegister { uint32_t reg; @@ -99,6 +124,23 @@ namespace BinaryNinja bool operator<(const SSAFlag& v) const; }; + struct SSARegisterOrFlag + { + RegisterOrFlag regOrFlag; + size_t version; + + SSARegisterOrFlag(); + SSARegisterOrFlag(const RegisterOrFlag& rf, size_t i); + SSARegisterOrFlag(const SSARegister& v); + SSARegisterOrFlag(const SSAFlag& v); + SSARegisterOrFlag(const SSARegisterOrFlag& v); + + SSARegisterOrFlag& operator=(const SSARegisterOrFlag& v); + bool operator==(const SSARegisterOrFlag& v) const; + bool operator!=(const SSARegisterOrFlag& v) const; + bool operator<(const SSARegisterOrFlag& v) const; + }; + enum LowLevelILOperandType { IntegerLowLevelOperand, @@ -108,6 +150,7 @@ namespace BinaryNinja RegisterStackLowLevelOperand, FlagLowLevelOperand, FlagConditionLowLevelOperand, + IntrinsicLowLevelOperand, SemanticFlagClassLowLevelOperand, SemanticFlagGroupLowLevelOperand, SSARegisterLowLevelOperand, @@ -115,9 +158,11 @@ namespace BinaryNinja SSAFlagLowLevelOperand, IndexListLowLevelOperand, ExprListLowLevelOperand, + RegisterOrFlagListLowLevelOperand, SSARegisterListLowLevelOperand, SSARegisterStackListLowLevelOperand, SSAFlagListLowLevelOperand, + SSARegisterOrFlagListLowLevelOperand, RegisterStackAdjustmentsLowLevelOperand }; @@ -152,6 +197,7 @@ namespace BinaryNinja HighSSARegisterLowLevelOperandUsage, LowRegisterLowLevelOperandUsage, LowSSARegisterLowLevelOperandUsage, + IntrinsicLowLevelOperandUsage, ConstantLowLevelOperandUsage, VectorLowLevelOperandUsage, StackAdjustmentLowLevelOperandUsage, @@ -168,6 +214,8 @@ namespace BinaryNinja SourceSSARegistersLowLevelOperandUsage, SourceSSARegisterStacksLowLevelOperandUsage, SourceSSAFlagsLowLevelOperandUsage, + OutputRegisterOrFlagListLowLevelOperandUsage, + OutputSSARegisterOrFlagListLowLevelOperandUsage, SourceMemoryVersionsLowLevelOperandUsage, TargetListLowLevelOperandUsage, RegisterStackAdjustmentsLowLevelOperandUsage @@ -365,6 +413,33 @@ namespace BinaryNinja operator std::vector() const; }; + class LowLevelILRegisterOrFlagList + { + struct ListIterator + { + LowLevelILIntegerList::const_iterator pos; + bool operator==(const ListIterator& a) const { return pos == a.pos; } + bool operator!=(const ListIterator& a) const { return pos != a.pos; } + bool operator<(const ListIterator& a) const { return pos < a.pos; } + ListIterator& operator++() { ++pos; return *this; } + const RegisterOrFlag operator*(); + }; + + LowLevelILIntegerList m_list; + + public: + typedef ListIterator const_iterator; + + LowLevelILRegisterOrFlagList(LowLevelILFunction* func, const BNLowLevelILInstruction& instr, size_t count); + + const_iterator begin() const; + const_iterator end() const; + size_t size() const; + const RegisterOrFlag operator[](size_t i) const; + + operator std::vector() const; + }; + class LowLevelILSSARegisterList { struct ListIterator @@ -446,6 +521,33 @@ namespace BinaryNinja operator std::vector() const; }; + class LowLevelILSSARegisterOrFlagList + { + struct ListIterator + { + LowLevelILIntegerList::const_iterator pos; + bool operator==(const ListIterator& a) const { return pos == a.pos; } + bool operator!=(const ListIterator& a) const { return pos != a.pos; } + bool operator<(const ListIterator& a) const { return pos < a.pos; } + ListIterator& operator++() { ++pos; ++pos; return *this; } + const SSARegisterOrFlag operator*(); + }; + + LowLevelILIntegerList m_list; + + public: + typedef ListIterator const_iterator; + + LowLevelILSSARegisterOrFlagList(LowLevelILFunction* func, const BNLowLevelILInstruction& instr, size_t count); + + const_iterator begin() const; + const_iterator end() const; + size_t size() const; + const SSARegisterOrFlag operator[](size_t i) const; + + operator std::vector() const; + }; + struct LowLevelILInstructionBase: public BNLowLevelILInstruction { #ifdef BINARYNINJACORE_LIBRARY @@ -474,13 +576,16 @@ namespace BinaryNinja SSAFlag GetRawOperandAsSSAFlag(size_t operand) const; LowLevelILIndexList GetRawOperandAsIndexList(size_t operand) const; LowLevelILInstructionList GetRawOperandAsExprList(size_t operand) const; + LowLevelILRegisterOrFlagList GetRawOperandAsRegisterOrFlagList(size_t operand) const; LowLevelILSSARegisterList GetRawOperandAsSSARegisterList(size_t operand) const; LowLevelILSSARegisterStackList GetRawOperandAsSSARegisterStackList(size_t operand) const; LowLevelILSSAFlagList GetRawOperandAsSSAFlagList(size_t operand) const; + LowLevelILSSARegisterOrFlagList GetRawOperandAsSSARegisterOrFlagList(size_t operand) const; std::map GetRawOperandAsRegisterStackAdjustments(size_t operand) const; void UpdateRawOperand(size_t operandIndex, ExprId value); void UpdateRawOperandAsSSARegisterList(size_t operandIndex, const std::vector& regs); + void UpdateRawOperandAsSSARegisterOrFlagList(size_t operandIndex, const std::vector& outputs); RegisterValue GetValue() const; PossibleValueSet GetPossibleValues() const; @@ -604,6 +709,7 @@ namespace BinaryNinja template SSARegister GetHighSSARegister() const { return As().GetHighSSARegister(); } template uint32_t GetLowRegister() const { return As().GetLowRegister(); } template SSARegister GetLowSSARegister() const { return As().GetLowSSARegister(); } + template uint32_t GetIntrinsic() const { return As().GetIntrinsic(); } template int64_t GetConstant() const { return As().GetConstant(); } template int64_t GetVector() const { return As().GetVector(); } template size_t GetStackAdjustment() const { return As().GetStackAdjustment(); } @@ -619,6 +725,8 @@ namespace BinaryNinja template LowLevelILSSARegisterList GetSourceSSARegisters() const { return As().GetSourceSSARegisters(); } template LowLevelILSSARegisterStackList GetSourceSSARegisterStacks() const { return As().GetSourceSSARegisterStacks(); } template LowLevelILSSAFlagList GetSourceSSAFlags() const { return As().GetSourceSSAFlags(); } + template LowLevelILRegisterOrFlagList GetOutputRegisterOrFlagList() const { return As().GetOutputRegisterOrFlagList(); } + template LowLevelILSSARegisterOrFlagList GetOutputSSARegisterOrFlagList() const { return As().GetOutputSSARegisterOrFlagList(); } template LowLevelILIndexList GetSourceMemoryVersions() const { return As().GetSourceMemoryVersions(); } template LowLevelILIndexList GetTargetList() const { return As().GetTargetList(); } template std::map GetRegisterStackAdjustments() const { return As().GetRegisterStackAdjustments(); } @@ -632,6 +740,7 @@ namespace BinaryNinja template void SetDestMemoryVersion(size_t version) { As().SetDestMemoryVersion(version); } template void SetSourceMemoryVersion(size_t version) { As().SetSourceMemoryVersion(version); } template void SetOutputSSARegisters(const std::vector& regs) { As().SetOutputSSARegisters(regs); } + template void SetOutputSSARegisterOrFlagList(const std::vector& outputs) { As().SetOutputSSARegisterOrFlagList(outputs); } bool GetOperandIndexForUsage(LowLevelILOperandUsage usage, size_t& operandIndex) const; @@ -664,6 +773,7 @@ namespace BinaryNinja SSARegister GetHighSSARegister() const; uint32_t GetLowRegister() const; SSARegister GetLowSSARegister() const; + uint32_t GetIntrinsic() const; int64_t GetConstant() const; int64_t GetVector() const; size_t GetStackAdjustment() const; @@ -679,6 +789,8 @@ namespace BinaryNinja LowLevelILSSARegisterList GetSourceSSARegisters() const; LowLevelILSSARegisterStackList GetSourceSSARegisterStacks() const; LowLevelILSSAFlagList GetSourceSSAFlags() const; + LowLevelILRegisterOrFlagList GetOutputRegisterOrFlagList() const; + LowLevelILSSARegisterOrFlagList GetOutputSSARegisterOrFlagList() const; LowLevelILIndexList GetSourceMemoryVersions() const; LowLevelILIndexList GetTargetList() const; std::map GetRegisterStackAdjustments() const; @@ -706,6 +818,7 @@ namespace BinaryNinja uint32_t GetFlag() const; uint32_t GetSemanticFlagClass() const; uint32_t GetSemanticFlagGroup() const; + uint32_t GetIntrinsic() const; BNLowLevelILFlagCondition GetFlagCondition() const; SSARegister GetSSARegister() const; SSARegisterStack GetSSARegisterStack() const; @@ -715,6 +828,8 @@ namespace BinaryNinja LowLevelILSSARegisterList GetSSARegisterList() const; LowLevelILSSARegisterStackList GetSSARegisterStackList() const; LowLevelILSSAFlagList GetSSAFlagList() const; + LowLevelILRegisterOrFlagList GetRegisterOrFlagList() const; + LowLevelILSSARegisterOrFlagList GetSSARegisterOrFlagList() const; std::map GetRegisterStackAdjustments() const; }; @@ -1022,6 +1137,20 @@ namespace BinaryNinja void SetOutputSSARegisters(const std::vector& regs) { GetRawOperandAsExpr(0).UpdateRawOperandAsSSARegisterList(1, regs); } }; + template <> struct LowLevelILInstructionAccessor: public LowLevelILInstructionBase + { + LowLevelILRegisterOrFlagList GetOutputRegisterOrFlagList() const { return GetRawOperandAsRegisterOrFlagList(0); } + uint32_t GetIntrinsic() const { return GetRawOperandAsRegister(2); } + LowLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExpr(3).GetRawOperandAsExprList(0); } + }; + template <> struct LowLevelILInstructionAccessor: public LowLevelILInstructionBase + { + LowLevelILSSARegisterOrFlagList GetOutputSSARegisterOrFlagList() const { return GetRawOperandAsSSARegisterOrFlagList(0); } + uint32_t GetIntrinsic() const { return GetRawOperandAsRegister(2); } + LowLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExpr(3).GetRawOperandAsExprList(0); } + void SetOutputSSARegisterOrFlagList(const std::vector& outputs) { UpdateRawOperandAsSSARegisterOrFlagList(0, outputs); } + }; + template <> struct LowLevelILInstructionAccessor: public LowLevelILInstructionBase { SSARegister GetDestSSARegister() const { return GetRawOperandAsSSARegister(0); } diff --git a/mediumlevelilinstruction.cpp b/mediumlevelilinstruction.cpp index e911c298..7e1e663f 100644 --- a/mediumlevelilinstruction.cpp +++ b/mediumlevelilinstruction.cpp @@ -54,6 +54,7 @@ unordered_map {OffsetMediumLevelOperandUsage, IntegerMediumLevelOperand}, {ConstantMediumLevelOperandUsage, IntegerMediumLevelOperand}, {VectorMediumLevelOperandUsage, IntegerMediumLevelOperand}, + {IntrinsicMediumLevelOperandUsage, IntrinsicMediumLevelOperand}, {TargetMediumLevelOperandUsage, IndexMediumLevelOperand}, {TrueTargetMediumLevelOperandUsage, IndexMediumLevelOperand}, {FalseTargetMediumLevelOperandUsage, IndexMediumLevelOperand}, @@ -64,6 +65,7 @@ unordered_map {OutputVariablesMediumLevelOperandUsage, VariableListMediumLevelOperand}, {OutputVariablesSubExprMediumLevelOperandUsage, VariableListMediumLevelOperand}, {OutputSSAVariablesMediumLevelOperandUsage, SSAVariableListMediumLevelOperand}, + {OutputSSAVariablesSubExprMediumLevelOperandUsage, SSAVariableListMediumLevelOperand}, {OutputSSAMemoryVersionMediumLevelOperandUsage, IndexMediumLevelOperand}, {ParameterExprsMediumLevelOperandUsage, ExprListMediumLevelOperand}, {SourceExprsMediumLevelOperandUsage, ExprListMediumLevelOperand}, @@ -127,23 +129,27 @@ unordered_map> {MLIL_SYSCALL, {OutputVariablesMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage}}, {MLIL_SYSCALL_UNTYPED, {OutputVariablesSubExprMediumLevelOperandUsage, ParameterVariablesMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}}, - {MLIL_CALL_SSA, {OutputSSAVariablesMediumLevelOperandUsage, + {MLIL_CALL_SSA, {OutputSSAVariablesSubExprMediumLevelOperandUsage, OutputSSAMemoryVersionMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}}, - {MLIL_CALL_UNTYPED_SSA, {OutputSSAVariablesMediumLevelOperandUsage, + {MLIL_CALL_UNTYPED_SSA, {OutputSSAVariablesSubExprMediumLevelOperandUsage, OutputSSAMemoryVersionMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, ParameterSSAVariablesMediumLevelOperandUsage, ParameterSSAMemoryVersionMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}}, - {MLIL_SYSCALL_SSA, {OutputSSAVariablesMediumLevelOperandUsage, + {MLIL_SYSCALL_SSA, {OutputSSAVariablesSubExprMediumLevelOperandUsage, OutputSSAMemoryVersionMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}}, - {MLIL_SYSCALL_UNTYPED_SSA, {OutputSSAVariablesMediumLevelOperandUsage, + {MLIL_SYSCALL_UNTYPED_SSA, {OutputSSAVariablesSubExprMediumLevelOperandUsage, OutputSSAMemoryVersionMediumLevelOperandUsage, ParameterSSAVariablesMediumLevelOperandUsage, ParameterSSAMemoryVersionMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}}, {MLIL_RET, {SourceExprsMediumLevelOperandUsage}}, {MLIL_IF, {ConditionExprMediumLevelOperandUsage, TrueTargetMediumLevelOperandUsage, FalseTargetMediumLevelOperandUsage}}, {MLIL_GOTO, {TargetMediumLevelOperandUsage}}, + {MLIL_INTRINSIC, {OutputVariablesMediumLevelOperandUsage, IntrinsicMediumLevelOperandUsage, + ParameterExprsMediumLevelOperandUsage}}, + {MLIL_INTRINSIC_SSA, {OutputSSAVariablesMediumLevelOperandUsage, IntrinsicMediumLevelOperandUsage, + ParameterExprsMediumLevelOperandUsage}}, {MLIL_TRAP, {VectorMediumLevelOperandUsage}}, {MLIL_VAR_PHI, {DestSSAVariableMediumLevelOperandUsage, SourceSSAVariablesMediumLevelOperandUsages}}, {MLIL_MEM_PHI, {DestMemoryVersionMediumLevelOperandUsage, SourceMemoryVersionsMediumLevelOperandUsage}}, @@ -243,7 +249,7 @@ static unordered_map()) + i.VisitExprs(func); + break; + case MLIL_INTRINSIC_SSA: + for (auto& i : GetParameterExprs()) + i.VisitExprs(func); + break; default: break; } @@ -1609,6 +1631,16 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest, return dest->Breakpoint(*this); case MLIL_TRAP: return dest->Trap(GetVector(), *this); + case MLIL_INTRINSIC: + for (auto& i : GetParameterExprs()) + params.push_back(subExprHandler(i)); + return dest->Intrinsic(GetOutputVariables(), + GetIntrinsic(), params, *this); + case MLIL_INTRINSIC_SSA: + for (auto& i : GetParameterExprs()) + params.push_back(subExprHandler(i)); + return dest->IntrinsicSSA(GetOutputSSAVariables(), + GetIntrinsic(), params, *this); case MLIL_UNDEF: return dest->Undefined(*this); case MLIL_UNIMPL: @@ -1796,6 +1828,15 @@ int64_t MediumLevelILInstruction::GetVector() const } +uint32_t MediumLevelILInstruction::GetIntrinsic() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(IntrinsicMediumLevelOperandUsage, operandIndex)) + return (uint32_t)GetRawOperandAsInteger(operandIndex); + throw MediumLevelILInstructionAccessException(); +} + + size_t MediumLevelILInstruction::GetTarget() const { size_t operandIndex; @@ -1878,6 +1919,8 @@ MediumLevelILSSAVariableList MediumLevelILInstruction::GetOutputSSAVariables() c { size_t operandIndex; if (GetOperandIndexForUsage(OutputSSAVariablesMediumLevelOperandUsage, operandIndex)) + return GetRawOperandAsSSAVariableList(operandIndex); + if (GetOperandIndexForUsage(OutputSSAVariablesSubExprMediumLevelOperandUsage, operandIndex)) return GetRawOperandAsExpr(operandIndex).GetRawOperandAsSSAVariableList(1); throw MediumLevelILInstructionAccessException(); } @@ -2577,6 +2620,22 @@ ExprId MediumLevelILFunction::Trap(int64_t vector, const ILSourceLocation& loc) } +ExprId MediumLevelILFunction::Intrinsic(const vector& outputs, uint32_t intrinsic, + const vector& params, const ILSourceLocation& loc) +{ + return AddExprWithLocation(MLIL_INTRINSIC, loc, 0, outputs.size(), AddVariableList(outputs), + intrinsic, params.size(), AddOperandList(params)); +} + + +ExprId MediumLevelILFunction::IntrinsicSSA(const vector& outputs, uint32_t intrinsic, + const vector& params, const ILSourceLocation& loc) +{ + return AddExprWithLocation(MLIL_INTRINSIC_SSA, loc, 0, outputs.size() * 2, AddSSAVariableList(outputs), + intrinsic, params.size(), AddOperandList(params)); +} + + ExprId MediumLevelILFunction::Undefined(const ILSourceLocation& loc) { return AddExprWithLocation(MLIL_UNDEF, loc, 0); diff --git a/mediumlevelilinstruction.h b/mediumlevelilinstruction.h index 8e671aaf..de92764d 100644 --- a/mediumlevelilinstruction.h +++ b/mediumlevelilinstruction.h @@ -70,6 +70,7 @@ namespace BinaryNinja { IntegerMediumLevelOperand, IndexMediumLevelOperand, + IntrinsicMediumLevelOperand, ExprMediumLevelOperand, VariableMediumLevelOperand, SSAVariableMediumLevelOperand, @@ -100,6 +101,7 @@ namespace BinaryNinja OffsetMediumLevelOperandUsage, ConstantMediumLevelOperandUsage, VectorMediumLevelOperandUsage, + IntrinsicMediumLevelOperandUsage, TargetMediumLevelOperandUsage, TrueTargetMediumLevelOperandUsage, FalseTargetMediumLevelOperandUsage, @@ -110,6 +112,7 @@ namespace BinaryNinja OutputVariablesMediumLevelOperandUsage, OutputVariablesSubExprMediumLevelOperandUsage, OutputSSAVariablesMediumLevelOperandUsage, + OutputSSAVariablesSubExprMediumLevelOperandUsage, OutputSSAMemoryVersionMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage, SourceExprsMediumLevelOperandUsage, @@ -485,6 +488,7 @@ namespace BinaryNinja template uint64_t GetOffset() const { return As().GetOffset(); } template int64_t GetConstant() const { return As().GetConstant(); } template int64_t GetVector() const { return As().GetVector(); } + template uint32_t GetIntrinsic() const { return As().GetIntrinsic(); } template size_t GetTarget() const { return As().GetTarget(); } template size_t GetTrueTarget() const { return As().GetTrueTarget(); } template size_t GetFalseTarget() const { return As().GetFalseTarget(); } @@ -535,6 +539,7 @@ namespace BinaryNinja uint64_t GetOffset() const; int64_t GetConstant() const; int64_t GetVector() const; + uint32_t GetIntrinsic() const; size_t GetTarget() const; size_t GetTrueTarget() const; size_t GetFalseTarget() const; @@ -567,6 +572,7 @@ namespace BinaryNinja uint64_t GetInteger() const; size_t GetIndex() const; + uint32_t GetIntrinsic() const; MediumLevelILInstruction GetExpr() const; Variable GetVariable() const; SSAVariable GetSSAVariable() const; @@ -902,6 +908,20 @@ namespace BinaryNinja size_t GetTarget() const { return GetRawOperandAsIndex(0); } }; + template <> struct MediumLevelILInstructionAccessor: public MediumLevelILInstructionBase + { + MediumLevelILVariableList GetOutputVariables() const { return GetRawOperandAsVariableList(0); } + uint32_t GetIntrinsic() const { return (uint32_t)GetRawOperandAsInteger(2); } + MediumLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(3); } + }; + template <> struct MediumLevelILInstructionAccessor: public MediumLevelILInstructionBase + { + MediumLevelILSSAVariableList GetOutputSSAVariables() const { return GetRawOperandAsSSAVariableList(0); } + uint32_t GetIntrinsic() const { return (uint32_t)GetRawOperandAsInteger(2); } + MediumLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(3); } + void SetOutputSSAVariables(const std::vector& vars) { UpdateRawOperandAsSSAVariableList(0, vars); } + }; + template <> struct MediumLevelILInstructionAccessor: public MediumLevelILInstructionBase { int64_t GetVector() const { return GetRawOperandAsInteger(0); } diff --git a/python/architecture.py b/python/architecture.py index 2b422962..3ccd2b11 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -33,6 +33,7 @@ import callingconvention import platform import log import databuffer +import types class _ArchitectureMetaClass(type): @@ -128,6 +129,7 @@ class Architecture(object): flags_written_by_flag_write_type = {} semantic_class_for_flag_write_type = {} reg_stacks = {} + intrinsics = {} __metaclass__ = _ArchitectureMetaClass next_address = 0 @@ -304,6 +306,27 @@ class Architecture(object): top = core.BNGetArchitectureRegisterName(self.handle, info.stackTopReg) self.reg_stacks[name] = function.RegisterStackInfo(storage, top_rel, top, regs[i]) core.BNFreeRegisterList(regs) + + count = ctypes.c_ulonglong() + intrinsics = core.BNGetAllArchitectureIntrinsics(self.handle, count) + self.__dict__["intrinsics"] = {} + for i in xrange(0, count.value): + name = core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i]) + input_count = ctypes.c_ulonglong() + inputs = core.BNGetArchitectureIntrinsicInputs(self.handle, intrinsics[i], input_count) + input_list = [] + for j in xrange(0, input_count.value): + input_name = inputs[j].name + type_obj = types.Type(core.BNNewTypeReference(inputs[j].type), confidence = inputs[j].typeConfidence) + input_list.append(function.IntrinsicInput(type_obj, input_name)) + core.BNFreeNameAndTypeList(inputs, input_count.value) + output_count = ctypes.c_ulonglong() + outputs = core.BNGetArchitectureIntrinsicOutputs(self.handle, intrinsics[i], output_count) + output_list = [] + for j in xrange(0, output_count.value): + output_list.append(types.Type(core.BNNewTypeReference(outputs[j].type), confidence = outputs[j].confidence)) + core.BNFreeOutputTypeList(outputs, output_count.value) + self.intrinsics[name] = function.IntrinsicInfo(input_list, output_list) else: startup._init_plugins() @@ -365,6 +388,12 @@ class Architecture(object): self._cb.getRegisterStackName = self._cb.getRegisterStackName.__class__(self._get_register_stack_name) self._cb.getAllRegisterStacks = self._cb.getAllRegisterStacks.__class__(self._get_all_register_stacks) self._cb.getRegisterStackInfo = self._cb.getRegisterStackInfo.__class__(self._get_register_stack_info) + self._cb.getIntrinsicName = self._cb.getIntrinsicName.__class__(self._get_intrinsic_name) + self._cb.getAllIntrinsics = self._cb.getAllIntrinsics.__class__(self._get_all_intrinsics) + self._cb.getIntrinsicInputs = self._cb.getIntrinsicInputs.__class__(self._get_intrinsic_inputs) + self._cb.freeNameAndTypeList = self._cb.freeNameAndTypeList.__class__(self._free_name_and_type_list) + self._cb.getIntrinsicOutputs = self._cb.getIntrinsicOutputs.__class__(self._get_intrinsic_outputs) + self._cb.freeTypeList = self._cb.freeTypeList.__class__(self._free_type_list) self._cb.assemble = self._cb.assemble.__class__(self._assemble) self._cb.isNeverBranchPatchAvailable = self._cb.isNeverBranchPatchAvailable.__class__( self._is_never_branch_patch_available) @@ -514,9 +543,28 @@ class Architecture(object): self.__dict__["global_regs"] = self.__class__.global_regs + self._intrinsics = {} + self._intrinsics_by_index = {} + self.__dict__["intrinsics"] = self.__class__.intrinsics + intrinsic_index = 0 + for intrinsic in self.__class__.intrinsics.keys(): + if intrinsic not in self._intrinsics: + info = self.__class__.intrinsics[intrinsic] + for i in xrange(0, len(info.inputs)): + if isinstance(info.inputs[i], types.Type): + info.inputs[i] = function.IntrinsicInput(info.inputs[i]) + elif isinstance(info.inputs[i], tuple): + info.inputs[i] = function.IntrinsicInput(info.inputs[i][0], info.inputs[i][1]) + info.index = intrinsic_index + self._intrinsics[intrinsic] = intrinsic_index + self._intrinsics_by_index[intrinsic_index] = (intrinsic, info) + intrinsic_index += 1 + self._pending_reg_lists = {} self._pending_token_lists = {} self._pending_condition_lists = {} + self._pending_name_and_type_lists = {} + self._pending_type_lists = {} def __eq__(self, value): if not isinstance(value, Architecture): @@ -1116,6 +1164,95 @@ class Architecture(object): result[0].topRelativeCount = 0 result[0].stackTopReg = 0 + def _get_intrinsic_name(self, ctxt, intrinsic): + try: + if intrinsic in self._intrinsics_by_index: + return core.BNAllocString(self._intrinsics_by_index[intrinsic][0]) + return core.BNAllocString("") + except (KeyError, OSError): + log.log_error(traceback.format_exc()) + return core.BNAllocString("") + + def _get_all_intrinsics(self, ctxt, count): + try: + regs = self._intrinsics_by_index.keys() + count[0] = len(regs) + reg_buf = (ctypes.c_uint * len(regs))() + for i in xrange(0, len(regs)): + reg_buf[i] = regs[i] + result = ctypes.cast(reg_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, reg_buf) + return result.value + except KeyError: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _get_intrinsic_inputs(self, ctxt, intrinsic, count): + try: + if intrinsic in self._intrinsics_by_index: + inputs = self._intrinsics_by_index[intrinsic][1].inputs + count[0] = len(inputs) + input_buf = (core.BNNameAndType * len(inputs))() + for i in xrange(0, len(inputs)): + input_buf[i].name = inputs[i].name + input_buf[i].type = core.BNNewTypeReference(inputs[i].type.handle) + input_buf[i].typeConfidence = inputs[i].type.confidence + result = ctypes.cast(input_buf, ctypes.c_void_p) + self._pending_name_and_type_lists[result.value] = (result, input_buf, len(inputs)) + return result.value + count[0] = 0 + return None + except: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _free_name_and_type_list(self, ctxt, buf_raw): + try: + buf = ctypes.cast(buf_raw, ctypes.c_void_p) + if buf.value not in self._pending_name_and_type_lists: + raise ValueError("freeing name and type list that wasn't allocated") + name_and_types = self._pending_name_and_type_lists[buf.value][1] + count = self._pending_name_and_type_lists[buf.value][2] + for i in xrange(0, count): + core.BNFreeType(name_and_types[i].type) + del self._pending_name_and_type_lists[buf.value] + except (ValueError, KeyError): + log.log_error(traceback.format_exc()) + + def _get_intrinsic_outputs(self, ctxt, intrinsic, count): + try: + if intrinsic in self._intrinsics_by_index: + outputs = self._intrinsics_by_index[intrinsic][1].outputs + count[0] = len(outputs) + output_buf = (core.BNTypeWithConfidence * len(outputs))() + for i in xrange(0, len(outputs)): + output_buf[i].type = core.BNNewTypeReference(outputs[i].handle) + output_buf[i].confidence = outputs[i].confidence + result = ctypes.cast(output_buf, ctypes.c_void_p) + self._pending_type_lists[result.value] = (result, output_buf, len(outputs)) + return result.value + count[0] = 0 + return None + except: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _free_type_list(self, ctxt, buf_raw): + try: + buf = ctypes.cast(buf_raw, ctypes.c_void_p) + if buf.value not in self._pending_type_lists: + raise ValueError("freeing type list that wasn't allocated") + types = self._pending_type_lists[buf.value][1] + count = self._pending_type_lists[buf.value][2] + for i in xrange(0, count): + core.BNFreeType(types[i].type) + del self._pending_type_lists[buf.value] + except (ValueError, KeyError): + log.log_error(traceback.format_exc()) + def _assemble(self, ctxt, code, addr, result, errors): try: data, error_str = self.perform_assemble(code, addr) @@ -1701,6 +1838,23 @@ class Architecture(object): return sem_group.index return sem_group + def get_intrinsic_name(self, intrinsic): + """ + ``get_intrinsic_name`` gets an intrinsic name from an intrinsic number. + + :param int intrinsic: intrinsic number + :return: the corresponding intrinsic string + :rtype: str + """ + return core.BNGetArchitectureIntrinsicName(self.handle, intrinsic) + + def get_intrinsic_index(self, intrinsic): + if isinstance(intrinsic, str): + return self._intrinsics[intrinsic] + elif isinstance(intrinsic, lowlevelil.ILIntrinsic): + return intrinsic.index + return intrinsic + def get_flag_write_type_name(self, write_type): """ ``get_flag_write_type_name`` gets the flag write type name for the given flag. diff --git a/python/function.py b/python/function.py index 10583b58..7607657f 100644 --- a/python/function.py +++ b/python/function.py @@ -427,7 +427,7 @@ class Function(object): """Function platform (read-only)""" if self._platform: return self._platform - else: + else: plat = core.BNGetFunctionPlatform(self.handle) if plat is None: return None @@ -1878,6 +1878,27 @@ class RegisterStackInfo(object): return "" % (len(self.storage_regs), self.stack_top_reg) +class IntrinsicInput(object): + def __init__(self, type_obj, name=""): + self.name = name + self.type = type_obj + + def __repr__(self): + if len(self.name) == 0: + return "" % str(self.type) + return "" % (str(self.type), self.name) + + +class IntrinsicInfo(object): + def __init__(self, inputs, outputs, index=None): + self.inputs = inputs + self.outputs = outputs + self.index = index + + def __repr__(self): + return " %s>" % (repr(self.inputs), repr(self.outputs)) + + class InstructionBranch(object): def __init__(self, branch_type, target = 0, arch = None): self.type = branch_type diff --git a/python/lowlevelil.py b/python/lowlevelil.py index a2d77c9f..33296ce8 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -131,6 +131,25 @@ class ILSemanticFlagGroup(object): return self.index == other.index +class ILIntrinsic(object): + def __init__(self, arch, intrinsic): + self.arch = arch + self.index = intrinsic + self.name = self.arch.get_intrinsic_name(self.index) + if self.name in self.arch.intrinsics: + self.inputs = self.arch.intrinsics[self.name].inputs + self.outputs = self.arch.intrinsics[self.name].outputs + + def __str__(self): + return self.name + + def __repr__(self): + return self.name + + def __eq__(self, other): + return self.index == other.index + + class SSARegister(object): def __init__(self, reg, version): self.reg = reg @@ -158,6 +177,15 @@ class SSAFlag(object): return "" % (repr(self.flag), self.version) +class SSARegisterOrFlag(object): + def __init__(self, reg_or_flag, version): + self.reg_or_flag = reg_or_flag + self.version = version + + def __repr__(self): + return "" % (repr(self.reg_or_flag), self.version) + + class LowLevelILOperationAndSize(object): def __init__(self, operation, size): self.operation = operation @@ -250,6 +278,8 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_BOOL_TO_INT: [("src", "expr")], LowLevelILOperation.LLIL_ADD_OVERFLOW: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_SYSCALL: [], + LowLevelILOperation.LLIL_INTRINSIC: [("output", "reg_or_flag_list"), ("intrinsic", "intrinsic"), ("param", "expr")], + LowLevelILOperation.LLIL_INTRINSIC_SSA: [("output", "reg_or_flag_ssa_list"), ("intrinsic", "intrinsic"), ("param", "expr")], LowLevelILOperation.LLIL_BP: [], LowLevelILOperation.LLIL_TRAP: [("vector", "int")], LowLevelILOperation.LLIL_UNDEF: [], @@ -292,7 +322,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_ssa"), ("src_memory", "int")], - LowLevelILOperation.LLIL_CALL_PARAM_SSA: [("src", "expr_list")], + LowLevelILOperation.LLIL_CALL_PARAM: [("src", "expr_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_ssa"), ("src", "reg_ssa_list")], @@ -336,6 +366,8 @@ class LowLevelILInstruction(object): value = ILRegister(func.arch, instr.operands[i]) elif operand_type == "reg_stack": value = ILRegisterStack(func.arch, instr.operands[i]) + elif operand_type == "intrinsic": + value = ILIntrinsic(func.arch, instr.operands[i]) elif operand_type == "reg_ssa": reg = ILRegister(func.arch, instr.operands[i]) i += 1 @@ -369,25 +401,36 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for i in xrange(count.value): - value.append(operand_list[i]) + for j in xrange(count.value): + value.append(operand_list[j]) core.BNLowLevelILFreeOperandList(operand_list) elif operand_type == "expr_list": count = ctypes.c_ulonglong() operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for i in xrange(count.value): - value.append(LowLevelILInstruction(func, operand_list[i])) + for j in xrange(count.value): + value.append(LowLevelILInstruction(func, operand_list[j])) + core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "reg_or_flag_list": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = [] + for j in xrange(count.value): + if (operand_list[j] & (1 << 32)) != 0: + value.append(ILFlag(func.arch, operand_list[j] & 0xffffffff)) + else: + value.append(ILRegister(func.arch, operand_list[j] & 0xffffffff)) core.BNLowLevelILFreeOperandList(operand_list) elif operand_type == "reg_ssa_list": count = ctypes.c_ulonglong() operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for i in xrange(count.value / 2): - reg = operand_list[i * 2] - reg_version = operand_list[(i * 2) + 1] + for j in xrange(count.value / 2): + reg = operand_list[j * 2] + reg_version = operand_list[(j * 2) + 1] value.append(SSARegister(ILRegister(func.arch, reg), reg_version)) core.BNLowLevelILFreeOperandList(operand_list) elif operand_type == "reg_stack_ssa_list": @@ -395,9 +438,9 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for i in xrange(count.value / 2): - reg_stack = operand_list[i * 2] - reg_version = operand_list[(i * 2) + 1] + for j in xrange(count.value / 2): + reg_stack = operand_list[j * 2] + reg_version = operand_list[(j * 2) + 1] value.append(SSARegisterStack(ILRegisterStack(func.arch, reg_stack), reg_version)) core.BNLowLevelILFreeOperandList(operand_list) elif operand_type == "flag_ssa_list": @@ -405,19 +448,32 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for i in xrange(count.value / 2): - flag = operand_list[i * 2] - flag_version = operand_list[(i * 2) + 1] + for j in xrange(count.value / 2): + flag = operand_list[j * 2] + flag_version = operand_list[(j * 2) + 1] value.append(SSAFlag(ILFlag(func.arch, flag), flag_version)) core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "reg_or_flag_ssa_list": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = [] + for j in xrange(count.value / 2): + if (operand_list[j * 2] & (1 << 32)) != 0: + reg_or_flag = ILFlag(func.arch, operand_list[j * 2] & 0xffffffff) + else: + reg_or_flag = ILRegister(func.arch, operand_list[j * 2] & 0xffffffff) + reg_version = operand_list[(j * 2) + 1] + value.append(SSARegisterOrFlag(reg_or_flag, reg_version)) + core.BNLowLevelILFreeOperandList(operand_list) elif operand_type == "reg_stack_adjust": count = ctypes.c_ulonglong() operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = {} - for i in xrange(count.value / 2): - reg_stack = operand_list[i * 2] - adjust = operand_list[(i * 2) + 1] + for j in xrange(count.value / 2): + reg_stack = operand_list[j * 2] + adjust = operand_list[(j * 2) + 1] if adjust & 0x80000000: adjust |= ~0x80000000 value[func.arch.get_reg_stack_name(reg_stack)] = adjust @@ -1714,6 +1770,25 @@ class LowLevelILFunction(object): """ return self.expr(LowLevelILOperation.LLIL_SYSCALL) + def intrinsic(self, outputs, intrinsic, params): + """ + ``intrinsic`` return an intrinsic expression. + + :return: an intrinsic expression. + :rtype: LowLevelILExpr + """ + output_list = [] + for output in outputs: + if isinstance(output, ILFlag): + output_list.append((1 << 32) | output.index) + else: + output_list.append(output.index) + param_list = [] + for param in params: + param_list.append(param.index) + return self.expr(LowLevelILOperation.LLIL_INTRINSIC, len(outputs), self.add_operand_list(output_list), + self.arch.get_intrinsic_index(intrinsic), len(params), self.add_operand_list(param_list)) + def breakpoint(self): """ ``breakpoint`` returns a processor breakpoint expression. diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 8594ea36..3c4ba3fd 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -150,6 +150,8 @@ class MediumLevelILInstruction(object): MediumLevelILOperation.MLIL_SYSCALL_UNTYPED: [("output", "expr"), ("params", "expr"), ("stack", "expr")], MediumLevelILOperation.MLIL_BP: [], MediumLevelILOperation.MLIL_TRAP: [("vector", "int")], + MediumLevelILOperation.MLIL_INTRINSIC: [("output", "var_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], + MediumLevelILOperation.MLIL_INTRINSIC_SSA: [("output", "var_ssa_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], MediumLevelILOperation.MLIL_UNDEF: [], MediumLevelILOperation.MLIL_UNIMPL: [], MediumLevelILOperation.MLIL_UNIMPL_MEM: [("src", "expr")], @@ -223,6 +225,8 @@ class MediumLevelILInstruction(object): value = instr.operands[i] elif operand_type == "expr": value = MediumLevelILInstruction(func, instr.operands[i]) + elif operand_type == "intrinsic": + value = lowlevelil.ILIntrinsic(func.arch, instr.operands[i]) elif operand_type == "var": value = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) elif operand_type == "var_ssa": -- cgit v1.3.1 From 83c9c2bceeb354dcf53e338e9411c6636f418123 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 7 Feb 2018 17:18:27 -0500 Subject: Add APIs for overriding stack adjustments on calls --- binaryninjaapi.h | 15 +++++++++ binaryninjacore.h | 19 ++++++++++++ function.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ python/function.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+) (limited to 'python/function.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 650299ed..d7535184 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2329,6 +2329,21 @@ namespace BinaryNinja std::vector GetIndirectBranches(); std::vector GetIndirectBranchesAt(Architecture* arch, uint64_t addr); + void SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence& adjust); + void SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, + const std::map>& adjust); + void SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack, + const Confidence& adjust); + void SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence& adjust); + void SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, + const std::map>& adjust); + void SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack, + const Confidence& adjust); + + Confidence GetCallStackAdjustment(Architecture* arch, uint64_t addr); + std::map> GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr); + Confidence GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack); + std::vector> GetBlockAnnotations(Architecture* arch, uint64_t addr); BNIntegerDisplayType GetIntegerConstantDisplayType(Architecture* arch, uint64_t instrAddr, uint64_t value, diff --git a/binaryninjacore.h b/binaryninjacore.h index 945badce..a9c38ed6 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -2383,6 +2383,25 @@ extern "C" uint64_t addr, size_t* count); BINARYNINJACOREAPI void BNFreeIndirectBranchList(BNIndirectBranchInfo* branches); + BINARYNINJACOREAPI void BNSetAutoCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, + size_t adjust, uint8_t confidence); + BINARYNINJACOREAPI void BNSetUserCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, + size_t adjust, uint8_t confidence); + BINARYNINJACOREAPI void BNSetAutoCallRegisterStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, + BNRegisterStackAdjustment* adjust, size_t count); + BINARYNINJACOREAPI void BNSetUserCallRegisterStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, + BNRegisterStackAdjustment* adjust, size_t count); + BINARYNINJACOREAPI void BNSetAutoCallRegisterStackAdjustmentForRegisterStack(BNFunction* func, + BNArchitecture* arch, uint64_t addr, uint32_t regStack, int32_t adjust, uint8_t confidence); + BINARYNINJACOREAPI void BNSetUserCallRegisterStackAdjustmentForRegisterStack(BNFunction* func, + BNArchitecture* arch, uint64_t addr, uint32_t regStack, int32_t adjust, uint8_t confidence); + + BINARYNINJACOREAPI BNSizeWithConfidence BNGetCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr); + BINARYNINJACOREAPI BNRegisterStackAdjustment* BNGetCallRegisterStackAdjustment(BNFunction* func, + BNArchitecture* arch, uint64_t addr, size_t* count); + BINARYNINJACOREAPI BNRegisterStackAdjustment BNGetCallRegisterStackAdjustmentForRegisterStack(BNFunction* func, + BNArchitecture* arch, uint64_t addr, uint32_t regStack); + BINARYNINJACOREAPI BNInstructionTextLine* BNGetFunctionBlockAnnotations(BNFunction* func, BNArchitecture* arch, uint64_t addr, size_t* count); BINARYNINJACOREAPI void BNFreeInstructionTextLines(BNInstructionTextLine* lines, size_t count); diff --git a/function.cpp b/function.cpp index ba2b419e..cd9be4d5 100644 --- a/function.cpp +++ b/function.cpp @@ -1018,6 +1018,96 @@ vector Function::GetIndirectBranchesAt(Architecture* arch, u } +void Function::SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence& adjust) +{ + BNSetAutoCallStackAdjustment(m_object, arch->GetObject(), addr, adjust.GetValue(), adjust.GetConfidence()); +} + + +void Function::SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, + const map>& adjust) +{ + BNRegisterStackAdjustment* values = new BNRegisterStackAdjustment[adjust.size()]; + size_t i = 0; + for (auto& j : adjust) + { + values[i].regStack = j.first; + values[i].adjustment = j.second.GetValue(); + values[i].confidence = j.second.GetConfidence(); + i++; + } + BNSetAutoCallRegisterStackAdjustment(m_object, arch->GetObject(), addr, values, adjust.size()); + delete[] values; +} + + +void Function::SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack, + const Confidence& adjust) +{ + BNSetAutoCallRegisterStackAdjustmentForRegisterStack(m_object, arch->GetObject(), addr, regStack, + adjust.GetValue(), adjust.GetConfidence()); +} + + +void Function::SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence& adjust) +{ + BNSetUserCallStackAdjustment(m_object, arch->GetObject(), addr, adjust.GetValue(), adjust.GetConfidence()); +} + + +void Function::SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, + const map>& adjust) +{ + BNRegisterStackAdjustment* values = new BNRegisterStackAdjustment[adjust.size()]; + size_t i = 0; + for (auto& j : adjust) + { + values[i].regStack = j.first; + values[i].adjustment = j.second.GetValue(); + values[i].confidence = j.second.GetConfidence(); + i++; + } + BNSetUserCallRegisterStackAdjustment(m_object, arch->GetObject(), addr, values, adjust.size()); + delete[] values; +} + + +void Function::SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack, + const Confidence& adjust) +{ + BNSetUserCallRegisterStackAdjustmentForRegisterStack(m_object, arch->GetObject(), addr, regStack, + adjust.GetValue(), adjust.GetConfidence()); +} + + +Confidence Function::GetCallStackAdjustment(Architecture* arch, uint64_t addr) +{ + BNSizeWithConfidence result = BNGetCallStackAdjustment(m_object, arch->GetObject(), addr); + return Confidence(result.value, result.confidence); +} + + +map> Function::GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr) +{ + size_t count; + BNRegisterStackAdjustment* adjust = BNGetCallRegisterStackAdjustment(m_object, arch->GetObject(), addr, &count); + + map> result; + for (size_t i = 0; i < count; i++) + result[adjust[i].regStack] = Confidence(adjust[i].adjustment, adjust[i].confidence); + BNFreeRegisterStackAdjustments(adjust); + return result; +} + + +Confidence Function::GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack) +{ + BNRegisterStackAdjustment result = BNGetCallRegisterStackAdjustmentForRegisterStack(m_object, + arch->GetObject(), addr, regStack); + return Confidence(result.adjustment, result.confidence); +} + + vector> Function::GetBlockAnnotations(Architecture* arch, uint64_t addr) { size_t count; diff --git a/python/function.py b/python/function.py index 7607657f..664afcd0 100644 --- a/python/function.py +++ b/python/function.py @@ -1453,6 +1453,94 @@ class Function(object): result = core.BNGetFunctionRegisterValueAtExit(self.handle, self.arch.get_reg_index(reg)) return RegisterValue(self.arch, result.value, confidence = result.confidence) + def set_auto_call_stack_adjustment(self, addr, adjust, arch=None): + if arch is None: + arch = self.arch + if not isinstance(adjust, types.SizeWithConfidence): + adjust = types.SizeWithConfidence(adjust) + core.BNSetAutoCallStackAdjustment(self.handle, arch.handle, addr, adjust.value, adjust.confidence) + + def set_auto_call_reg_stack_adjustment(self, addr, adjust, arch=None): + if arch is None: + arch = self.arch + adjust_buf = (core.BNRegisterStackAdjustment * len(adjust))() + i = 0 + for reg_stack in adjust.keys(): + adjust_buf[i].regStack = arch.get_reg_stack_index(reg_stack) + value = adjust[reg_stack] + if not isinstance(value, types.RegisterStackAdjustmentWithConfidence): + value = types.RegisterStackAdjustmentWithConfidence(value) + adjust_buf[i].adjustment = value.value + adjust_buf[i].confidence = value.confidence + i += 1 + core.BNSetAutoCallRegisterStackAdjustment(self.handle, arch.handle, addr, adjust_buf, len(adjust)) + + def set_auto_call_reg_stack_adjustment_for_reg_stack(self, addr, reg_stack, adjust, arch=None): + if arch is None: + arch = self.arch + reg_stack = arch.get_reg_stack_index(reg_stack) + if not isinstance(adjust, types.RegisterStackAdjustmentWithConfidence): + adjust = types.RegisterStackAdjustmentWithConfidence(adjust) + core.BNSetAutoCallRegisterStackAdjustmentForRegisterStack(self.handle, arch.handle, addr, reg_stack, + adjust.value, adjust.confidence) + + def set_call_stack_adjustment(self, addr, adjust, arch=None): + if arch is None: + arch = self.arch + if not isinstance(adjust, types.SizeWithConfidence): + adjust = types.SizeWithConfidence(adjust) + core.BNSetUserCallStackAdjustment(self.handle, arch.handle, addr, adjust.value, adjust.confidence) + + def set_call_reg_stack_adjustment(self, addr, adjust, arch=None): + if arch is None: + arch = self.arch + adjust_buf = (core.BNRegisterStackAdjustment * len(adjust))() + i = 0 + for reg_stack in adjust.keys(): + adjust_buf[i].regStack = arch.get_reg_stack_index(reg_stack) + value = adjust[reg_stack] + if not isinstance(value, types.RegisterStackAdjustmentWithConfidence): + value = types.RegisterStackAdjustmentWithConfidence(value) + adjust_buf[i].adjustment = value.value + adjust_buf[i].confidence = value.confidence + i += 1 + core.BNSetUserCallRegisterStackAdjustment(self.handle, arch.handle, addr, adjust_buf, len(adjust)) + + def set_call_reg_stack_adjustment_for_reg_stack(self, addr, reg_stack, adjust, arch=None): + if arch is None: + arch = self.arch + reg_stack = arch.get_reg_stack_index(reg_stack) + if not isinstance(adjust, types.RegisterStackAdjustmentWithConfidence): + adjust = types.RegisterStackAdjustmentWithConfidence(adjust) + core.BNSetUserCallRegisterStackAdjustmentForRegisterStack(self.handle, arch.handle, addr, reg_stack, + adjust.value, adjust.confidence) + + def get_call_stack_adjustment(self, addr, arch=None): + if arch is None: + arch = self.arch + result = core.BNGetCallStackAdjustment(self.handle, arch.handle, addr) + return types.SizeWithConfidence(result.value, confidence = result.confidence) + + def get_call_reg_stack_adjustment(self, addr, arch=None): + if arch is None: + arch = self.arch + count = ctypes.c_ulonglong() + adjust = core.BNGetCallRegisterStackAdjustment(self.handle, arch.handle, addr, count) + result = {} + for i in xrange(0, count.value): + result[arch.get_reg_stack_name(adjust[i].regStack)] = types.RegisterStackAdjustmentWithConfidence( + adjust[i].adjustment, confidence = adjust[i].confidence) + core.BNFreeRegisterStackAdjustments(adjust) + return result + + def get_call_reg_stack_adjustment_for_reg_stack(self, addr, reg_stack, arch=None): + if arch is None: + arch = self.arch + reg_stack = arch.get_reg_stack_index(reg_stack) + adjust = core.BNGetCallRegisterStackAdjustmentForRegisterStack(self.handle, arch.handle, addr, reg_stack) + result = types.RegisterStackAdjustmentWithConfidence(adjust.adjustment, confidence = adjust.confidence) + return result + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): -- cgit v1.3.1 From f5d8f94993452815fe68e1da9cb398bf4b7e5917 Mon Sep 17 00:00:00 2001 From: Brian Potchik Date: Sat, 17 Feb 2018 02:26:45 -0500 Subject: For Python, display set of values in hex format. --- python/function.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'python/function.py') diff --git a/python/function.py b/python/function.py index 664afcd0..39ace7c6 100644 --- a/python/function.py +++ b/python/function.py @@ -225,9 +225,9 @@ class PossibleValueSet(object): if self.type == RegisterValueType.LookupTableValue: return "" % ', '.join([repr(i) for i in self.table]) if self.type == RegisterValueType.InSetOfValues: - return "" % repr(self.values) + return "" % '[{}]'.format(', '.join(hex(i) for i in self.values)) if self.type == RegisterValueType.NotInSetOfValues: - return "" % repr(self.values) + return "" % '[{}]'.format(', '.join(hex(i) for i in self.values)) if self.type == RegisterValueType.ReturnAddressValue: return "" return "" -- cgit v1.3.1 From 105fb2549bd8fc0e19907fefff1168322dee3bb3 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 26 Feb 2018 22:37:19 -0500 Subject: Architecture plugins no longer need to override the perform_* methods (you can now override get_instruction_info, not perform_get_instruction_info). The perform_* methods are now deprecated but will still function as expected. Added architecture hooks to Python API using this new style. --- python/architecture.py | 1763 +++++++++++++++++++++++++----------------- python/basicblock.py | 2 +- python/binaryview.py | 6 +- python/callingconvention.py | 2 +- python/examples/arch_hook.py | 16 + python/examples/nes.py | 28 +- python/function.py | 8 +- python/platform.py | 2 +- 8 files changed, 1091 insertions(+), 736 deletions(-) create mode 100644 python/examples/arch_hook.py (limited to 'python/function.py') diff --git a/python/architecture.py b/python/architecture.py index 2b52ea35..781edcfd 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -44,7 +44,7 @@ class _ArchitectureMetaClass(type): archs = core.BNGetArchitectureList(count) result = [] for i in xrange(0, count.value): - result.append(Architecture(archs[i])) + result.append(CoreArchitecture(archs[i])) core.BNFreeArchitectureList(archs) return result @@ -54,7 +54,7 @@ class _ArchitectureMetaClass(type): archs = core.BNGetArchitectureList(count) try: for i in xrange(0, count.value): - yield Architecture(archs[i]) + yield CoreArchitecture(archs[i]) finally: core.BNFreeArchitectureList(archs) @@ -63,7 +63,7 @@ class _ArchitectureMetaClass(type): arch = core.BNGetArchitectureByName(name) if arch is None: raise KeyError("'%s' is not a valid architecture" % str(name)) - return Architecture(arch) + return CoreArchitecture(arch) def register(cls): startup._init_plugins() @@ -133,438 +133,253 @@ class Architecture(object): __metaclass__ = _ArchitectureMetaClass next_address = 0 - def __init__(self, handle=None): - if handle is not None: - self.handle = core.handle_of_type(handle, core.BNArchitecture) - self.__dict__["name"] = core.BNGetArchitectureName(self.handle) - self.__dict__["endianness"] = Endianness(core.BNGetArchitectureEndianness(self.handle)) - self.__dict__["address_size"] = core.BNGetArchitectureAddressSize(self.handle) - self.__dict__["default_int_size"] = core.BNGetArchitectureDefaultIntegerSize(self.handle) - self.__dict__["instr_alignment"] = core.BNGetArchitectureInstructionAlignment(self.handle) - self.__dict__["max_instr_length"] = core.BNGetArchitectureMaxInstructionLength(self.handle) - self.__dict__["opcode_display_length"] = core.BNGetArchitectureOpcodeDisplayLength(self.handle) - self.__dict__["stack_pointer"] = core.BNGetArchitectureRegisterName(self.handle, - core.BNGetArchitectureStackPointerRegister(self.handle)) - self.__dict__["link_reg"] = core.BNGetArchitectureRegisterName(self.handle, - core.BNGetArchitectureLinkRegister(self.handle)) - - count = ctypes.c_ulonglong() - regs = core.BNGetAllArchitectureRegisters(self.handle, count) - self.__dict__["regs"] = {} - for i in xrange(0, count.value): - name = core.BNGetArchitectureRegisterName(self.handle, regs[i]) - info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) - full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister) - self.regs[name] = function.RegisterInfo(full_width_reg, info.size, info.offset, - ImplicitRegisterExtend(info.extend), regs[i]) - core.BNFreeRegisterList(regs) - - count = ctypes.c_ulonglong() - flags = core.BNGetAllArchitectureFlags(self.handle, count) - self._flags = {} - self._flags_by_index = {} - self.__dict__["flags"] = [] - for i in xrange(0, count.value): - name = core.BNGetArchitectureFlagName(self.handle, flags[i]) - self._flags[name] = flags[i] - self._flags_by_index[flags[i]] = name - self.flags.append(name) - core.BNFreeRegisterList(flags) - - count = ctypes.c_ulonglong() - write_types = core.BNGetAllArchitectureFlagWriteTypes(self.handle, count) - self._flag_write_types = {} - self._flag_write_types_by_index = {} - self.__dict__["flag_write_types"] = [] - for i in xrange(0, count.value): - name = core.BNGetArchitectureFlagWriteTypeName(self.handle, write_types[i]) - self._flag_write_types[name] = write_types[i] - self._flag_write_types_by_index[write_types[i]] = name - self.flag_write_types.append(name) - core.BNFreeRegisterList(write_types) - - count = ctypes.c_ulonglong() - sem_classes = core.BNGetAllArchitectureSemanticFlagClasses(self.handle, count) - self._semantic_flag_classes = {} - self._semantic_flag_classes_by_index = {} - self.__dict__["semantic_flag_classes"] = [] - for i in xrange(0, count.value): - name = core.BNGetArchitectureSemanticFlagClassName(self.handle, sem_classes[i]) - self._semantic_flag_classes[name] = sem_classes[i] - self._semantic_flag_classes_by_index[sem_classes[i]] = name - self.semantic_flag_classes.append(name) - core.BNFreeRegisterList(sem_classes) + def __init__(self): + startup._init_plugins() - count = ctypes.c_ulonglong() - sem_groups = core.BNGetAllArchitectureSemanticFlagGroups(self.handle, count) - self._semantic_flag_groups = {} - self._semantic_flag_groups_by_index = {} - self.__dict__["semantic_flag_groups"] = [] - for i in xrange(0, count.value): - name = core.BNGetArchitectureSemanticFlagGroupName(self.handle, sem_groups[i]) - self._semantic_flag_groups[name] = sem_groups[i] - self._semantic_flag_groups_by_index[sem_groups[i]] = name - self.semantic_flag_groups.append(name) - core.BNFreeRegisterList(sem_groups) - - self._flag_roles = {} - self.__dict__["flag_roles"] = {} - for flag in self.__dict__["flags"]: - role = FlagRole(core.BNGetArchitectureFlagRole(self.handle, self._flags[flag], 0)) - self.__dict__["flag_roles"][flag] = role - self._flag_roles[self._flags[flag]] = role - - self.__dict__["flags_required_for_flag_condition"] = {} - for cond in LowLevelILFlagCondition: - count = ctypes.c_ulonglong() - flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, 0, count) - flag_names = [] - for i in xrange(0, count.value): - flag_names.append(self._flags_by_index[flags[i]]) - core.BNFreeRegisterList(flags) - self.__dict__["flags_required_for_flag_condition"][cond] = flag_names - - self._flags_required_by_semantic_flag_group = {} - self.__dict__["flags_required_for_semantic_flag_group"] = {} - for group in self.semantic_flag_groups: - count = ctypes.c_ulonglong() - flags = core.BNGetArchitectureFlagsRequiredForSemanticFlagGroup(self.handle, - self._semantic_flag_groups[group], count) - flag_indexes = [] - flag_names = [] - for i in xrange(0, count.value): - flag_indexes.append(flags[i]) - flag_names.append(self._flags_by_index[flags[i]]) - core.BNFreeRegisterList(flags) - self._flags_required_by_semantic_flag_group[self._semantic_flag_groups[group]] = flag_indexes - self.__dict__["flags_required_for_semantic_flag_group"][cond] = flag_names - - self._flag_conditions_for_semantic_flag_group = {} - self.__dict__["flag_conditions_for_semantic_flag_group"] = {} - for group in self.semantic_flag_groups: - count = ctypes.c_ulonglong() - conditions = core.BNGetArchitectureFlagConditionsForSemanticFlagGroup(self.handle, - self._semantic_flag_groups[group], count) - class_index_cond = {} - class_cond = {} - for i in xrange(0, count.value): - class_index_cond[conditions[i].semanticClass] = conditions[i].condition - if conditions[i].semanticClass == 0: - class_cond[None] = conditions[i].condition - elif conditions[i].semanticClass in self._semantic_flag_classes_by_index: - class_cond[self._semantic_flag_classes_by_index[conditions[i].semanticClass]] = conditions[i].condition - core.BNFreeFlagConditionsForSemanticFlagGroup(conditions) - self._flag_conditions_for_semantic_flag_group[self._semantic_flag_groups[group]] = class_index_cond - self.__dict__["flag_conditions_for_semantic_flag_group"][group] = class_cond - - self._flags_written_by_flag_write_type = {} - self.__dict__["flags_written_by_flag_write_type"] = {} - for write_type in self.flag_write_types: - count = ctypes.c_ulonglong() - flags = core.BNGetArchitectureFlagsWrittenByFlagWriteType(self.handle, - self._flag_write_types[write_type], count) - flag_indexes = [] - flag_names = [] - for i in xrange(0, count.value): - flag_indexes.append(flags[i]) - flag_names.append(self._flags_by_index[flags[i]]) - core.BNFreeRegisterList(flags) - self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flag_indexes - self.__dict__["flags_written_by_flag_write_type"][write_type] = flag_names - - self._semantic_class_for_flag_write_type = {} - self.__dict__["semantic_class_for_flag_write_type"] = {} - for write_type in self.flag_write_types: - sem_class = core.BNGetArchitectureSemanticClassForFlagWriteType(self.handle, - self._flag_write_types[write_type]) - if sem_class == 0: - sem_class_name = None + if self.__class__.opcode_display_length > self.__class__.max_instr_length: + self.__class__.opcode_display_length = self.__class__.max_instr_length + + self._cb = core.BNCustomArchitecture() + self._cb.context = 0 + self._cb.init = self._cb.init.__class__(self._init) + self._cb.getEndianness = self._cb.getEndianness.__class__(self._get_endianness) + self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) + self._cb.getDefaultIntegerSize = self._cb.getDefaultIntegerSize.__class__(self._get_default_integer_size) + self._cb.getInstructionAlignment = self._cb.getInstructionAlignment.__class__(self._get_instruction_alignment) + self._cb.getMaxInstructionLength = self._cb.getMaxInstructionLength.__class__(self._get_max_instruction_length) + self._cb.getOpcodeDisplayLength = self._cb.getOpcodeDisplayLength.__class__(self._get_opcode_display_length) + self._cb.getAssociatedArchitectureByAddress = \ + self._cb.getAssociatedArchitectureByAddress.__class__(self._get_associated_arch_by_address) + self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__(self._get_instruction_info) + self._cb.getInstructionText = self._cb.getInstructionText.__class__(self._get_instruction_text) + self._cb.freeInstructionText = self._cb.freeInstructionText.__class__(self._free_instruction_text) + self._cb.getInstructionLowLevelIL = self._cb.getInstructionLowLevelIL.__class__( + self._get_instruction_low_level_il) + self._cb.getRegisterName = self._cb.getRegisterName.__class__(self._get_register_name) + self._cb.getFlagName = self._cb.getFlagName.__class__(self._get_flag_name) + self._cb.getFlagWriteTypeName = self._cb.getFlagWriteTypeName.__class__(self._get_flag_write_type_name) + self._cb.getSemanticFlagClassName = self._cb.getSemanticFlagClassName.__class__(self._get_semantic_flag_class_name) + self._cb.getSemanticFlagGroupName = self._cb.getSemanticFlagGroupName.__class__(self._get_semantic_flag_group_name) + self._cb.getFullWidthRegisters = self._cb.getFullWidthRegisters.__class__(self._get_full_width_registers) + self._cb.getAllRegisters = self._cb.getAllRegisters.__class__(self._get_all_registers) + self._cb.getAllFlags = self._cb.getAllRegisters.__class__(self._get_all_flags) + self._cb.getAllFlagWriteTypes = self._cb.getAllRegisters.__class__(self._get_all_flag_write_types) + self._cb.getAllSemanticFlagClasses = self._cb.getAllSemanticFlagClasses.__class__(self._get_all_semantic_flag_classes) + self._cb.getAllSemanticFlagGroups = self._cb.getAllSemanticFlagGroups.__class__(self._get_all_semantic_flag_groups) + self._cb.getFlagRole = self._cb.getFlagRole.__class__(self._get_flag_role) + self._cb.getFlagsRequiredForFlagCondition = self._cb.getFlagsRequiredForFlagCondition.__class__( + self._get_flags_required_for_flag_condition) + self._cb.getFlagsRequiredForSemanticFlagGroup = self._cb.getFlagsRequiredForSemanticFlagGroup.__class__( + self._get_flags_required_for_semantic_flag_group) + self._cb.getFlagConditionsForSemanticFlagGroup = self._cb.getFlagConditionsForSemanticFlagGroup.__class__( + self._get_flag_conditions_for_semantic_flag_group) + self._cb.freeFlagConditionsForSemanticFlagGroup = self._cb.freeFlagConditionsForSemanticFlagGroup.__class__( + self._free_flag_conditions_for_semantic_flag_group) + self._cb.getFlagsWrittenByFlagWriteType = self._cb.getFlagsWrittenByFlagWriteType.__class__( + self._get_flags_written_by_flag_write_type) + self._cb.getSemanticClassForFlagWriteType = self._cb.getSemanticClassForFlagWriteType.__class__( + self._get_semantic_class_for_flag_write_type) + self._cb.getFlagWriteLowLevelIL = self._cb.getFlagWriteLowLevelIL.__class__( + self._get_flag_write_low_level_il) + self._cb.getFlagConditionLowLevelIL = self._cb.getFlagConditionLowLevelIL.__class__( + self._get_flag_condition_low_level_il) + self._cb.getSemanticFlagGroupLowLevelIL = self._cb.getSemanticFlagGroupLowLevelIL.__class__( + self._get_semantic_flag_group_low_level_il) + self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) + self._cb.getRegisterInfo = self._cb.getRegisterInfo.__class__(self._get_register_info) + self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__( + self._get_stack_pointer_register) + self._cb.getLinkRegister = self._cb.getLinkRegister.__class__(self._get_link_register) + self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_registers) + self._cb.getRegisterStackName = self._cb.getRegisterStackName.__class__(self._get_register_stack_name) + self._cb.getAllRegisterStacks = self._cb.getAllRegisterStacks.__class__(self._get_all_register_stacks) + self._cb.getRegisterStackInfo = self._cb.getRegisterStackInfo.__class__(self._get_register_stack_info) + self._cb.getIntrinsicName = self._cb.getIntrinsicName.__class__(self._get_intrinsic_name) + self._cb.getAllIntrinsics = self._cb.getAllIntrinsics.__class__(self._get_all_intrinsics) + self._cb.getIntrinsicInputs = self._cb.getIntrinsicInputs.__class__(self._get_intrinsic_inputs) + self._cb.freeNameAndTypeList = self._cb.freeNameAndTypeList.__class__(self._free_name_and_type_list) + self._cb.getIntrinsicOutputs = self._cb.getIntrinsicOutputs.__class__(self._get_intrinsic_outputs) + self._cb.freeTypeList = self._cb.freeTypeList.__class__(self._free_type_list) + self._cb.assemble = self._cb.assemble.__class__(self._assemble) + self._cb.isNeverBranchPatchAvailable = self._cb.isNeverBranchPatchAvailable.__class__( + self._is_never_branch_patch_available) + self._cb.isAlwaysBranchPatchAvailable = self._cb.isAlwaysBranchPatchAvailable.__class__( + self._is_always_branch_patch_available) + self._cb.isInvertBranchPatchAvailable = self._cb.isInvertBranchPatchAvailable.__class__( + self._is_invert_branch_patch_available) + self._cb.isSkipAndReturnZeroPatchAvailable = self._cb.isSkipAndReturnZeroPatchAvailable.__class__( + self._is_skip_and_return_zero_patch_available) + self._cb.isSkipAndReturnValuePatchAvailable = self._cb.isSkipAndReturnValuePatchAvailable.__class__( + self._is_skip_and_return_value_patch_available) + self._cb.convertToNop = self._cb.convertToNop.__class__(self._convert_to_nop) + self._cb.alwaysBranch = self._cb.alwaysBranch.__class__(self._always_branch) + self._cb.invertBranch = self._cb.invertBranch.__class__(self._invert_branch) + self._cb.skipAndReturnValue = self._cb.skipAndReturnValue.__class__(self._skip_and_return_value) + + self.__dict__["endianness"] = self.__class__.endianness + self.__dict__["address_size"] = self.__class__.address_size + self.__dict__["default_int_size"] = self.__class__.default_int_size + self.__dict__["instr_alignment"] = self.__class__.instr_alignment + self.__dict__["max_instr_length"] = self.__class__.max_instr_length + self.__dict__["opcode_display_length"] = self.__class__.opcode_display_length + self.__dict__["stack_pointer"] = self.__class__.stack_pointer + self.__dict__["link_reg"] = self.__class__.link_reg + + self._all_regs = {} + self._full_width_regs = {} + self._regs_by_index = {} + self.__dict__["regs"] = self.__class__.regs + reg_index = 0 + + # Registers used for storage in register stacks must be sequential, so allocate these in order first + self._all_reg_stacks = {} + self._reg_stacks_by_index = {} + self.__dict__["reg_stacks"] = self.__class__.reg_stacks + reg_stack_index = 0 + for reg_stack in self.reg_stacks: + info = self.reg_stacks[reg_stack] + for reg in info.storage_regs: + self._all_regs[reg] = reg_index + self._regs_by_index[reg_index] = reg + self.regs[reg].index = reg_index + reg_index += 1 + for reg in info.top_relative_regs: + self._all_regs[reg] = reg_index + self._regs_by_index[reg_index] = reg + self.regs[reg].index = reg_index + reg_index += 1 + if reg_stack not in self._all_reg_stacks: + self._all_reg_stacks[reg_stack] = reg_stack_index + self._reg_stacks_by_index[reg_stack_index] = reg_stack + self.reg_stacks[reg_stack].index = reg_stack_index + reg_stack_index += 1 + + for reg in self.regs: + info = self.regs[reg] + if reg not in self._all_regs: + self._all_regs[reg] = reg_index + self._regs_by_index[reg_index] = reg + self.regs[reg].index = reg_index + reg_index += 1 + if info.full_width_reg not in self._all_regs: + self._all_regs[info.full_width_reg] = reg_index + self._regs_by_index[reg_index] = info.full_width_reg + self.regs[info.full_width_reg].index = reg_index + reg_index += 1 + if info.full_width_reg not in self._full_width_regs: + self._full_width_regs[info.full_width_reg] = self._all_regs[info.full_width_reg] + + self._flags = {} + self._flags_by_index = {} + self.__dict__["flags"] = self.__class__.flags + flag_index = 0 + for flag in self.__class__.flags: + if flag not in self._flags: + self._flags[flag] = flag_index + self._flags_by_index[flag_index] = flag + flag_index += 1 + + self._flag_write_types = {} + self._flag_write_types_by_index = {} + self.__dict__["flag_write_types"] = self.__class__.flag_write_types + write_type_index = 0 + for write_type in self.__class__.flag_write_types: + if write_type not in self._flag_write_types: + self._flag_write_types[write_type] = write_type_index + self._flag_write_types_by_index[write_type_index] = write_type + write_type_index += 1 + + self._semantic_flag_classes = {} + self._semantic_flag_classes_by_index = {} + self.__dict__["semantic_flag_classes"] = self.__class__.semantic_flag_classes + semantic_class_index = 1 + for sem_class in self.__class__.semantic_flag_classes: + if sem_class not in self._semantic_flag_classes: + self._semantic_flag_classes[sem_class] = semantic_class_index + self._semantic_flag_classes_by_index[semantic_class_index] = sem_class + semantic_class_index += 1 + + self._semantic_flag_groups = {} + self._semantic_flag_groups_by_index = {} + self.__dict__["semantic_flag_groups"] = self.__class__.semantic_flag_groups + semantic_group_index = 0 + for sem_group in self.__class__.semantic_flag_groups: + if sem_group not in self._semantic_flag_groups: + self._semantic_flag_groups[sem_group] = semantic_group_index + self._semantic_flag_groups_by_index[semantic_group_index] = sem_group + semantic_group_index += 1 + + self._flag_roles = {} + self.__dict__["flag_roles"] = self.__class__.flag_roles + for flag in self.__class__.flag_roles: + role = self.__class__.flag_roles[flag] + if isinstance(role, str): + role = FlagRole[role] + self._flag_roles[self._flags[flag]] = role + + self.__dict__["flags_required_for_flag_condition"] = self.__class__.flags_required_for_flag_condition + + self._flags_required_by_semantic_flag_group = {} + self.__dict__["flags_required_for_semantic_flag_group"] = self.__class__.flags_required_for_semantic_flag_group + for group in self.__class__.flags_required_for_semantic_flag_group: + flags = [] + for flag in self.__class__.flags_required_for_semantic_flag_group[group]: + flags.append(self._flags[flag]) + self._flags_required_by_semantic_flag_group[self._semantic_flag_groups[group]] = flags + + self._flag_conditions_for_semantic_flag_group = {} + self.__dict__["flag_conditions_for_semantic_flag_group"] = self.__class__.flag_conditions_for_semantic_flag_group + for group in self.__class__.flag_conditions_for_semantic_flag_group: + class_cond = {} + for sem_class in self.__class__.flag_conditions_for_semantic_flag_group[group]: + if sem_class is None: + class_cond[0] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] else: - sem_class_name = self._semantic_flag_classes_by_index[sem_class] - self._semantic_class_for_flag_write_type[self._flag_write_types[write_type]] = sem_class - self.__dict__["semantic_class_for_flag_write_type"][write_type] = sem_class_name - - count = ctypes.c_ulonglong() - regs = core.BNGetArchitectureGlobalRegisters(self.handle, count) - self.__dict__["global_regs"] = [] - for i in xrange(0, count.value): - self.global_regs.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) - core.BNFreeRegisterList(regs) - - count = ctypes.c_ulonglong() - regs = core.BNGetAllArchitectureRegisterStacks(self.handle, count) - self.__dict__["reg_stacks"] = {} - for i in xrange(0, count.value): - name = core.BNGetArchitectureRegisterStackName(self.handle, regs[i]) - info = core.BNGetArchitectureRegisterStackInfo(self.handle, regs[i]) - storage = [] - for j in xrange(0, info.storageCount): - storage.append(core.BNGetArchitectureRegisterName(self.handle, info.firstStorageReg + j)) - top_rel = [] - for j in xrange(0, info.topRelativeCount): - top_rel.append(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j)) - top = core.BNGetArchitectureRegisterName(self.handle, info.stackTopReg) - self.reg_stacks[name] = function.RegisterStackInfo(storage, top_rel, top, regs[i]) - core.BNFreeRegisterList(regs) + class_cond[self._semantic_flag_classes[sem_class]] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] + self._flag_conditions_for_semantic_flag_group[self._semantic_flag_groups[group]] = class_cond - count = ctypes.c_ulonglong() - intrinsics = core.BNGetAllArchitectureIntrinsics(self.handle, count) - self.__dict__["intrinsics"] = {} - for i in xrange(0, count.value): - name = core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i]) - input_count = ctypes.c_ulonglong() - inputs = core.BNGetArchitectureIntrinsicInputs(self.handle, intrinsics[i], input_count) - input_list = [] - for j in xrange(0, input_count.value): - input_name = inputs[j].name - type_obj = types.Type(core.BNNewTypeReference(inputs[j].type), confidence = inputs[j].typeConfidence) - input_list.append(function.IntrinsicInput(type_obj, input_name)) - core.BNFreeNameAndTypeList(inputs, input_count.value) - output_count = ctypes.c_ulonglong() - outputs = core.BNGetArchitectureIntrinsicOutputs(self.handle, intrinsics[i], output_count) - output_list = [] - for j in xrange(0, output_count.value): - output_list.append(types.Type(core.BNNewTypeReference(outputs[j].type), confidence = outputs[j].confidence)) - core.BNFreeOutputTypeList(outputs, output_count.value) - self.intrinsics[name] = function.IntrinsicInfo(input_list, output_list) - else: - startup._init_plugins() - - if self.__class__.opcode_display_length > self.__class__.max_instr_length: - self.__class__.opcode_display_length = self.__class__.max_instr_length - - self._cb = core.BNCustomArchitecture() - self._cb.context = 0 - self._cb.init = self._cb.init.__class__(self._init) - self._cb.getEndianness = self._cb.getEndianness.__class__(self._get_endianness) - self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) - self._cb.getDefaultIntegerSize = self._cb.getDefaultIntegerSize.__class__(self._get_default_integer_size) - self._cb.getInstructionAlignment = self._cb.getInstructionAlignment.__class__(self._get_instruction_alignment) - self._cb.getMaxInstructionLength = self._cb.getMaxInstructionLength.__class__(self._get_max_instruction_length) - self._cb.getOpcodeDisplayLength = self._cb.getOpcodeDisplayLength.__class__(self._get_opcode_display_length) - self._cb.getAssociatedArchitectureByAddress = \ - self._cb.getAssociatedArchitectureByAddress.__class__(self._get_associated_arch_by_address) - self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__(self._get_instruction_info) - self._cb.getInstructionText = self._cb.getInstructionText.__class__(self._get_instruction_text) - self._cb.freeInstructionText = self._cb.freeInstructionText.__class__(self._free_instruction_text) - self._cb.getInstructionLowLevelIL = self._cb.getInstructionLowLevelIL.__class__( - self._get_instruction_low_level_il) - self._cb.getRegisterName = self._cb.getRegisterName.__class__(self._get_register_name) - self._cb.getFlagName = self._cb.getFlagName.__class__(self._get_flag_name) - self._cb.getFlagWriteTypeName = self._cb.getFlagWriteTypeName.__class__(self._get_flag_write_type_name) - self._cb.getSemanticFlagClassName = self._cb.getSemanticFlagClassName.__class__(self._get_semantic_flag_class_name) - self._cb.getSemanticFlagGroupName = self._cb.getSemanticFlagGroupName.__class__(self._get_semantic_flag_group_name) - self._cb.getFullWidthRegisters = self._cb.getFullWidthRegisters.__class__(self._get_full_width_registers) - self._cb.getAllRegisters = self._cb.getAllRegisters.__class__(self._get_all_registers) - self._cb.getAllFlags = self._cb.getAllRegisters.__class__(self._get_all_flags) - self._cb.getAllFlagWriteTypes = self._cb.getAllRegisters.__class__(self._get_all_flag_write_types) - self._cb.getAllSemanticFlagClasses = self._cb.getAllSemanticFlagClasses.__class__(self._get_all_semantic_flag_classes) - self._cb.getAllSemanticFlagGroups = self._cb.getAllSemanticFlagGroups.__class__(self._get_all_semantic_flag_groups) - self._cb.getFlagRole = self._cb.getFlagRole.__class__(self._get_flag_role) - self._cb.getFlagsRequiredForFlagCondition = self._cb.getFlagsRequiredForFlagCondition.__class__( - self._get_flags_required_for_flag_condition) - self._cb.getFlagsRequiredForSemanticFlagGroup = self._cb.getFlagsRequiredForSemanticFlagGroup.__class__( - self._get_flags_required_for_semantic_flag_group) - self._cb.getFlagConditionsForSemanticFlagGroup = self._cb.getFlagConditionsForSemanticFlagGroup.__class__( - self._get_flag_conditions_for_semantic_flag_group) - self._cb.freeFlagConditionsForSemanticFlagGroup = self._cb.freeFlagConditionsForSemanticFlagGroup.__class__( - self._free_flag_conditions_for_semantic_flag_group) - self._cb.getFlagsWrittenByFlagWriteType = self._cb.getFlagsWrittenByFlagWriteType.__class__( - self._get_flags_written_by_flag_write_type) - self._cb.getSemanticClassForFlagWriteType = self._cb.getSemanticClassForFlagWriteType.__class__( - self._get_semantic_class_for_flag_write_type) - self._cb.getFlagWriteLowLevelIL = self._cb.getFlagWriteLowLevelIL.__class__( - self._get_flag_write_low_level_il) - self._cb.getFlagConditionLowLevelIL = self._cb.getFlagConditionLowLevelIL.__class__( - self._get_flag_condition_low_level_il) - self._cb.getSemanticFlagGroupLowLevelIL = self._cb.getSemanticFlagGroupLowLevelIL.__class__( - self._get_semantic_flag_group_low_level_il) - self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) - self._cb.getRegisterInfo = self._cb.getRegisterInfo.__class__(self._get_register_info) - self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__( - self._get_stack_pointer_register) - self._cb.getLinkRegister = self._cb.getLinkRegister.__class__(self._get_link_register) - self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_registers) - self._cb.getRegisterStackName = self._cb.getRegisterStackName.__class__(self._get_register_stack_name) - self._cb.getAllRegisterStacks = self._cb.getAllRegisterStacks.__class__(self._get_all_register_stacks) - self._cb.getRegisterStackInfo = self._cb.getRegisterStackInfo.__class__(self._get_register_stack_info) - self._cb.getIntrinsicName = self._cb.getIntrinsicName.__class__(self._get_intrinsic_name) - self._cb.getAllIntrinsics = self._cb.getAllIntrinsics.__class__(self._get_all_intrinsics) - self._cb.getIntrinsicInputs = self._cb.getIntrinsicInputs.__class__(self._get_intrinsic_inputs) - self._cb.freeNameAndTypeList = self._cb.freeNameAndTypeList.__class__(self._free_name_and_type_list) - self._cb.getIntrinsicOutputs = self._cb.getIntrinsicOutputs.__class__(self._get_intrinsic_outputs) - self._cb.freeTypeList = self._cb.freeTypeList.__class__(self._free_type_list) - self._cb.assemble = self._cb.assemble.__class__(self._assemble) - self._cb.isNeverBranchPatchAvailable = self._cb.isNeverBranchPatchAvailable.__class__( - self._is_never_branch_patch_available) - self._cb.isAlwaysBranchPatchAvailable = self._cb.isAlwaysBranchPatchAvailable.__class__( - self._is_always_branch_patch_available) - self._cb.isInvertBranchPatchAvailable = self._cb.isInvertBranchPatchAvailable.__class__( - self._is_invert_branch_patch_available) - self._cb.isSkipAndReturnZeroPatchAvailable = self._cb.isSkipAndReturnZeroPatchAvailable.__class__( - self._is_skip_and_return_zero_patch_available) - self._cb.isSkipAndReturnValuePatchAvailable = self._cb.isSkipAndReturnValuePatchAvailable.__class__( - self._is_skip_and_return_value_patch_available) - self._cb.convertToNop = self._cb.convertToNop.__class__(self._convert_to_nop) - self._cb.alwaysBranch = self._cb.alwaysBranch.__class__(self._always_branch) - self._cb.invertBranch = self._cb.invertBranch.__class__(self._invert_branch) - self._cb.skipAndReturnValue = self._cb.skipAndReturnValue.__class__(self._skip_and_return_value) - - self._all_regs = {} - self._full_width_regs = {} - self._regs_by_index = {} - self.__dict__["regs"] = self.__class__.regs - reg_index = 0 - - # Registers used for storage in register stacks must be sequential, so allocate these in order first - self._all_reg_stacks = {} - self._reg_stacks_by_index = {} - self.__dict__["reg_stacks"] = self.__class__.reg_stacks - reg_stack_index = 0 - for reg_stack in self.reg_stacks: - info = self.reg_stacks[reg_stack] - for reg in info.storage_regs: - self._all_regs[reg] = reg_index - self._regs_by_index[reg_index] = reg - self.regs[reg].index = reg_index - reg_index += 1 - for reg in info.top_relative_regs: - self._all_regs[reg] = reg_index - self._regs_by_index[reg_index] = reg - self.regs[reg].index = reg_index - reg_index += 1 - if reg_stack not in self._all_reg_stacks: - self._all_reg_stacks[reg_stack] = reg_stack_index - self._reg_stacks_by_index[reg_stack_index] = reg_stack - self.reg_stacks[reg_stack].index = reg_stack_index - reg_stack_index += 1 - - for reg in self.regs: - info = self.regs[reg] - if reg not in self._all_regs: - self._all_regs[reg] = reg_index - self._regs_by_index[reg_index] = reg - self.regs[reg].index = reg_index - reg_index += 1 - if info.full_width_reg not in self._all_regs: - self._all_regs[info.full_width_reg] = reg_index - self._regs_by_index[reg_index] = info.full_width_reg - self.regs[info.full_width_reg].index = reg_index - reg_index += 1 - if info.full_width_reg not in self._full_width_regs: - self._full_width_regs[info.full_width_reg] = self._all_regs[info.full_width_reg] - - self._flags = {} - self._flags_by_index = {} - self.__dict__["flags"] = self.__class__.flags - flag_index = 0 - for flag in self.__class__.flags: - if flag not in self._flags: - self._flags[flag] = flag_index - self._flags_by_index[flag_index] = flag - flag_index += 1 - - self._flag_write_types = {} - self._flag_write_types_by_index = {} - self.__dict__["flag_write_types"] = self.__class__.flag_write_types - write_type_index = 0 - for write_type in self.__class__.flag_write_types: - if write_type not in self._flag_write_types: - self._flag_write_types[write_type] = write_type_index - self._flag_write_types_by_index[write_type_index] = write_type - write_type_index += 1 - - self._semantic_flag_classes = {} - self._semantic_flag_classes_by_index = {} - self.__dict__["semantic_flag_classes"] = self.__class__.semantic_flag_classes - semantic_class_index = 1 - for sem_class in self.__class__.semantic_flag_classes: - if sem_class not in self._semantic_flag_classes: - self._semantic_flag_classes[sem_class] = semantic_class_index - self._semantic_flag_classes_by_index[semantic_class_index] = sem_class - semantic_class_index += 1 - - self._semantic_flag_groups = {} - self._semantic_flag_groups_by_index = {} - self.__dict__["semantic_flag_groups"] = self.__class__.semantic_flag_groups - semantic_group_index = 0 - for sem_group in self.__class__.semantic_flag_groups: - if sem_group not in self._semantic_flag_groups: - self._semantic_flag_groups[sem_group] = semantic_group_index - self._semantic_flag_groups_by_index[semantic_group_index] = sem_group - semantic_group_index += 1 - - self._flag_roles = {} - self.__dict__["flag_roles"] = self.__class__.flag_roles - for flag in self.__class__.flag_roles: - role = self.__class__.flag_roles[flag] - if isinstance(role, str): - role = FlagRole[role] - self._flag_roles[self._flags[flag]] = role - - self.__dict__["flags_required_for_flag_condition"] = self.__class__.flags_required_for_flag_condition - - self._flags_required_by_semantic_flag_group = {} - self.__dict__["flags_required_for_semantic_flag_group"] = self.__class__.flags_required_for_semantic_flag_group - for group in self.__class__.flags_required_for_semantic_flag_group: - flags = [] - for flag in self.__class__.flags_required_for_semantic_flag_group[group]: - flags.append(self._flags[flag]) - self._flags_required_by_semantic_flag_group[self._semantic_flag_groups[group]] = flags - - self._flag_conditions_for_semantic_flag_group = {} - self.__dict__["flag_conditions_for_semantic_flag_group"] = self.__class__.flag_conditions_for_semantic_flag_group - for group in self.__class__.flag_conditions_for_semantic_flag_group: - class_cond = {} - for sem_class in self.__class__.flag_conditions_for_semantic_flag_group[group]: - if sem_class is None: - class_cond[0] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] - else: - class_cond[self._semantic_flag_classes[sem_class]] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] - self._flag_conditions_for_semantic_flag_group[self._semantic_flag_groups[group]] = class_cond - - self._flags_written_by_flag_write_type = {} - self.__dict__["flags_written_by_flag_write_type"] = self.__class__.flags_written_by_flag_write_type - for write_type in self.__class__.flags_written_by_flag_write_type: - flags = [] - for flag in self.__class__.flags_written_by_flag_write_type[write_type]: - flags.append(self._flags[flag]) - self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flags - - self._semantic_class_for_flag_write_type = {} - self.__dict__["semantic_class_for_flag_write_type"] = self.__class__.semantic_class_for_flag_write_type - for write_type in self.__class__.semantic_class_for_flag_write_type: - sem_class = self.__class__.semantic_class_for_flag_write_type[write_type] - if sem_class in self._semantic_flag_classes: - sem_class_index = self._semantic_flag_classes[sem_class] - else: - sem_class_index = 0 - self._semantic_class_for_flag_write_type[self._flag_write_types[write_type]] = sem_class_index - - self.__dict__["global_regs"] = self.__class__.global_regs - - self._intrinsics = {} - self._intrinsics_by_index = {} - self.__dict__["intrinsics"] = self.__class__.intrinsics - intrinsic_index = 0 - for intrinsic in self.__class__.intrinsics.keys(): - if intrinsic not in self._intrinsics: - info = self.__class__.intrinsics[intrinsic] - for i in xrange(0, len(info.inputs)): - if isinstance(info.inputs[i], types.Type): - info.inputs[i] = function.IntrinsicInput(info.inputs[i]) - elif isinstance(info.inputs[i], tuple): - info.inputs[i] = function.IntrinsicInput(info.inputs[i][0], info.inputs[i][1]) - info.index = intrinsic_index - self._intrinsics[intrinsic] = intrinsic_index - self._intrinsics_by_index[intrinsic_index] = (intrinsic, info) - intrinsic_index += 1 - - self._pending_reg_lists = {} - self._pending_token_lists = {} - self._pending_condition_lists = {} - self._pending_name_and_type_lists = {} - self._pending_type_lists = {} + self._flags_written_by_flag_write_type = {} + self.__dict__["flags_written_by_flag_write_type"] = self.__class__.flags_written_by_flag_write_type + for write_type in self.__class__.flags_written_by_flag_write_type: + flags = [] + for flag in self.__class__.flags_written_by_flag_write_type[write_type]: + flags.append(self._flags[flag]) + self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flags + + self._semantic_class_for_flag_write_type = {} + self.__dict__["semantic_class_for_flag_write_type"] = self.__class__.semantic_class_for_flag_write_type + for write_type in self.__class__.semantic_class_for_flag_write_type: + sem_class = self.__class__.semantic_class_for_flag_write_type[write_type] + if sem_class in self._semantic_flag_classes: + sem_class_index = self._semantic_flag_classes[sem_class] + else: + sem_class_index = 0 + self._semantic_class_for_flag_write_type[self._flag_write_types[write_type]] = sem_class_index + + self.__dict__["global_regs"] = self.__class__.global_regs + + self._intrinsics = {} + self._intrinsics_by_index = {} + self.__dict__["intrinsics"] = self.__class__.intrinsics + intrinsic_index = 0 + for intrinsic in self.__class__.intrinsics.keys(): + if intrinsic not in self._intrinsics: + info = self.__class__.intrinsics[intrinsic] + for i in xrange(0, len(info.inputs)): + if isinstance(info.inputs[i], types.Type): + info.inputs[i] = function.IntrinsicInput(info.inputs[i]) + elif isinstance(info.inputs[i], tuple): + info.inputs[i] = function.IntrinsicInput(info.inputs[i][0], info.inputs[i][1]) + info.index = intrinsic_index + self._intrinsics[intrinsic] = intrinsic_index + self._intrinsics_by_index[intrinsic_index] = (intrinsic, info) + intrinsic_index += 1 + + self._pending_reg_lists = {} + self._pending_token_lists = {} + self._pending_condition_lists = {} + self._pending_name_and_type_lists = {} + self._pending_type_lists = {} def __eq__(self, value): if not isinstance(value, Architecture): @@ -624,49 +439,49 @@ class Architecture(object): def _get_endianness(self, ctxt): try: - return self.__class__.endianness + return self.endianness except: log.log_error(traceback.format_exc()) return Endianness.LittleEndian def _get_address_size(self, ctxt): try: - return self.__class__.address_size + return self.address_size except: log.log_error(traceback.format_exc()) return 8 def _get_default_integer_size(self, ctxt): try: - return self.__class__.default_int_size + return self.default_int_size except: log.log_error(traceback.format_exc()) return 4 def _get_instruction_alignment(self, ctxt): try: - return self.__class__.instr_alignment + return self.instr_alignment except: log.log_error(traceback.format_exc()) return 1 def _get_max_instruction_length(self, ctxt): try: - return self.__class__.max_instr_length + return self.max_instr_length except: log.log_error(traceback.format_exc()) return 16 def _get_opcode_display_length(self, ctxt): try: - return self.__class__.opcode_display_length + return self.opcode_display_length except: log.log_error(traceback.format_exc()) return 8 def _get_associated_arch_by_address(self, ctxt, addr): try: - result, new_addr = self.perform_get_associated_arch_by_address(addr[0]) + result, new_addr = self.get_associated_arch_by_address(addr[0]) addr[0] = new_addr return ctypes.cast(result.handle, ctypes.c_void_p).value except: @@ -677,7 +492,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(max_len) ctypes.memmove(buf, data, max_len) - info = self.perform_get_instruction_info(buf.raw, addr) + info = self.get_instruction_info(buf.raw, addr) if info is None: return False result[0].length = info.length @@ -703,7 +518,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length[0]) ctypes.memmove(buf, data, length[0]) - info = self.perform_get_instruction_text(buf.raw, addr) + info = self.get_instruction_text(buf.raw, addr) if info is None: return False tokens = info[0] @@ -743,7 +558,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length[0]) ctypes.memmove(buf, data, length[0]) - result = self.perform_get_instruction_low_level_il(buf.raw, addr, + result = self.get_instruction_low_level_il(buf.raw, addr, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))) if result is None: return False @@ -782,8 +597,8 @@ class Architecture(object): def _get_semantic_flag_class_name(self, ctxt, sem_class): try: - if sem_class in self._semantic_flag_class_by_index: - return core.BNAllocString(self._semantic_flag_class_by_index[sem_class]) + if sem_class in self._semantic_flag_classes_by_index: + return core.BNAllocString(self._semantic_flag_classes_by_index[sem_class]) return core.BNAllocString("") except (KeyError, OSError): log.log_error(traceback.format_exc()) @@ -791,8 +606,8 @@ class Architecture(object): def _get_semantic_flag_group_name(self, ctxt, sem_group): try: - if sem_group in self._semantic_flag_group_by_index: - return core.BNAllocString(self._semantic_flag_group_by_index[sem_group]) + if sem_group in self._semantic_flag_groups_by_index: + return core.BNAllocString(self._semantic_flag_groups_by_index[sem_group]) return core.BNAllocString("") except (KeyError, OSError): log.log_error(traceback.format_exc()) @@ -894,23 +709,18 @@ class Architecture(object): sem_class = self._semantic_flag_classes_by_index[sem_class] else: sem_class = None - return self.perform_get_flag_role(flag, sem_class) + return self.get_flag_role(flag, sem_class) except KeyError: log.log_error(traceback.format_exc()) return FlagRole.SpecialFlagRole - def perform_get_flag_role(self, flag, sem_class): - if flag in self._flag_roles: - return self._flag_roles[flag] - return FlagRole.SpecialFlagRole - def _get_flags_required_for_flag_condition(self, ctxt, cond, sem_class, count): try: if sem_class in self._semantic_flag_classes_by_index: sem_class = self._semantic_flag_classes_by_index[sem_class] else: sem_class = None - flag_names = self.perform_get_flags_required_for_flag_condition(cond, sem_class) + flag_names = self.get_flags_required_for_flag_condition(cond, sem_class) flags = [] for name in flag_names: flags.append(self._flags[name]) @@ -926,11 +736,6 @@ class Architecture(object): count[0] = 0 return None - def perform_get_flags_required_for_flag_condition(self, cond, sem_class): - if cond in self.flags_required_for_flag_condition: - return self.flags_required_for_flag_condition[cond] - return [] - def _get_flags_required_for_semantic_flag_group(self, ctxt, sem_group, count): try: if sem_group in self._flags_required_by_semantic_flag_group: @@ -951,8 +756,8 @@ class Architecture(object): def _get_flag_conditions_for_semantic_flag_group(self, ctxt, sem_group, count): try: - if sem_group in self._flag_conditions_by_semantic_flag_group: - class_cond = self._flag_conditions_by_semantic_flag_group[sem_group] + if sem_group in self._flag_conditions_for_semantic_flag_group: + class_cond = self._flag_conditions_for_semantic_flag_group[sem_group] else: class_cond = {} count[0] = len(class_cond) @@ -963,7 +768,7 @@ class Architecture(object): cond_buf[i].condition = class_cond[class_index] i += 1 result = ctypes.cast(cond_buf, ctypes.c_void_p) - self._pending_conditions[result.value] = (result, cond_buf) + self._pending_condition_lists[result.value] = (result, cond_buf) return result.value except (KeyError, OSError): log.log_error(traceback.format_exc()) @@ -973,9 +778,9 @@ class Architecture(object): def _free_flag_conditions_for_semantic_flag_group(self, ctxt, conditions): try: buf = ctypes.cast(conditions, ctypes.c_void_p) - if buf.value not in self._pending_conditions: + if buf.value not in self._pending_condition_lists: raise ValueError("freeing condition list that wasn't allocated") - del self._pending_conditions[buf.value] + del self._pending_condition_lists[buf.value] except (ValueError, KeyError): log.log_error(traceback.format_exc()) @@ -1021,7 +826,7 @@ class Architecture(object): operand_list.append(lowlevelil.ILRegister(self, operands[i].reg)) else: operand_list.append(lowlevelil.ILRegister(self, operands[i].reg)) - return self.perform_get_flag_write_low_level_il(op, size, write_type_name, flag_name, operand_list, + return self.get_flag_write_low_level_il(op, size, write_type_name, flag_name, operand_list, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))).index except (KeyError, OSError): log.log_error(traceback.format_exc()) @@ -1033,7 +838,7 @@ class Architecture(object): sem_class_name = self._semantic_flag_classes_by_index[sem_class] else: sem_class_name = None - return self.perform_get_flag_condition_low_level_il(cond, sem_class_name, + return self.get_flag_condition_low_level_il(cond, sem_class_name, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))).index except OSError: log.log_error(traceback.format_exc()) @@ -1045,7 +850,7 @@ class Architecture(object): sem_group_name = self._semantic_flag_groups_by_index[sem_group] else: sem_group_name = None - return self.perform_get_semantic_flag_group_low_level_il(sem_group_name, + return self.get_semantic_flag_group_low_level_il(sem_group_name, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))).index except OSError: log.log_error(traceback.format_exc()) @@ -1068,7 +873,7 @@ class Architecture(object): result[0].size = 0 result[0].extend = ImplicitRegisterExtend.NoExtend return - info = self.__class__.regs[self._regs_by_index[reg]] + info = self.regs[self._regs_by_index[reg]] result[0].fullWidthRegister = self._all_regs[info.full_width_reg] result[0].offset = info.offset result[0].size = info.size @@ -1085,26 +890,26 @@ class Architecture(object): def _get_stack_pointer_register(self, ctxt): try: - return self._all_regs[self.__class__.stack_pointer] + return self._all_regs[self.stack_pointer] except KeyError: log.log_error(traceback.format_exc()) return 0 def _get_link_register(self, ctxt): try: - if self.__class__.link_reg is None: + if self.link_reg is None: return 0xffffffff - return self._all_regs[self.__class__.link_reg] + return self._all_regs[self.link_reg] except KeyError: log.log_error(traceback.format_exc()) return 0 def _get_global_registers(self, ctxt, count): try: - count[0] = len(self.__class__.global_regs) - reg_buf = (ctypes.c_uint * len(self.__class__.global_regs))() - for i in xrange(0, len(self.__class__.global_regs)): - reg_buf[i] = self._all_regs[self.__class__.global_regs[i]] + count[0] = len(self.global_regs) + reg_buf = (ctypes.c_uint * len(self.global_regs))() + for i in xrange(0, len(self.global_regs)): + reg_buf[i] = self._all_regs[self.global_regs[i]] result = ctypes.cast(reg_buf, ctypes.c_void_p) self._pending_reg_lists[result.value] = (result, reg_buf) return result.value @@ -1146,7 +951,7 @@ class Architecture(object): result[0].topRelativeCount = 0 result[0].stackTopReg = 0 return - info = self.__class__.regs[self._reg_stacks_by_index[reg_stack]] + info = self.reg_stacks[self._reg_stacks_by_index[reg_stack]] result[0].firstStorageReg = self._all_regs[info.storage_regs[0]] result[0].storageCount = len(info.storage_regs) if len(info.top_relative_regs) > 0: @@ -1208,7 +1013,7 @@ class Architecture(object): count[0] = 0 return None - def _free_name_and_type_list(self, ctxt, buf_raw): + def _free_name_and_type_list(self, ctxt, buf_raw, length): try: buf = ctypes.cast(buf_raw, ctypes.c_void_p) if buf.value not in self._pending_name_and_type_lists: @@ -1240,7 +1045,7 @@ class Architecture(object): count[0] = 0 return None - def _free_type_list(self, ctxt, buf_raw): + def _free_type_list(self, ctxt, buf_raw, length): try: buf = ctypes.cast(buf_raw, ctypes.c_void_p) if buf.value not in self._pending_type_lists: @@ -1255,7 +1060,7 @@ class Architecture(object): def _assemble(self, ctxt, code, addr, result, errors): try: - data, error_str = self.perform_assemble(code, addr) + data, error_str = self.assemble(code, addr) errors[0] = core.BNAllocString(str(error_str)) if data is None: return False @@ -1273,7 +1078,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_never_branch_patch_available(buf.raw, addr) + return self.is_never_branch_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -1282,7 +1087,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_always_branch_patch_available(buf.raw, addr) + return self.is_always_branch_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -1291,7 +1096,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_invert_branch_patch_available(buf.raw, addr) + return self.is_invert_branch_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -1300,7 +1105,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_skip_and_return_zero_patch_available(buf.raw, addr) + return self.is_skip_and_return_zero_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -1309,7 +1114,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_skip_and_return_value_patch_available(buf.raw, addr) + return self.is_skip_and_return_value_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -1318,7 +1123,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - result = self.perform_convert_to_nop(buf.raw, addr) + result = self.convert_to_nop(buf.raw, addr) if result is None: return False result = str(result) @@ -1334,7 +1139,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - result = self.perform_always_branch(buf.raw, addr) + result = self.always_branch(buf.raw, addr) if result is None: return False result = str(result) @@ -1350,7 +1155,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - result = self.perform_invert_branch(buf.raw, addr) + result = self.invert_branch(buf.raw, addr) if result is None: return False result = str(result) @@ -1366,7 +1171,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - result = self.perform_skip_and_return_value(buf.raw, addr, value) + result = self.skip_and_return_value(buf.raw, addr, value) if result is None: return False result = str(result) @@ -1379,27 +1184,15 @@ class Architecture(object): return False def perform_get_associated_arch_by_address(self, addr): + """ + Deprecated method provided for compatibility. Architecture plugins should override ``get_associated_arch_by_address``. + """ return self, addr @abc.abstractmethod def perform_get_instruction_info(self, data, addr): """ - ``perform_get_instruction_info`` implements a method which interpretes the bytes passed in ``data`` as an - :py:Class:`InstructionInfo` object. The InstructionInfo object should have the length of the current instruction. - If the instruction is a branch instruction the method should add a branch of the proper type: - - ===================== =================================================== - BranchType Description - ===================== =================================================== - UnconditionalBranch Branch will always be taken - FalseBranch False branch condition - TrueBranch True branch condition - CallDestination Branch is a call instruction (Branch with Link) - FunctionReturn Branch returns from a function - SystemCall System call instruction - IndirectBranch Branch destination is a memory address or register - UnresolvedBranch Call instruction that isn't - ===================== =================================================== + Deprecated method provided for compatibility. Architecture plugins should override ``get_instruction_info``. :param str data: bytes to decode :param int addr: virtual address of the byte to be decoded @@ -1411,8 +1204,7 @@ class Architecture(object): @abc.abstractmethod def perform_get_instruction_text(self, data, addr): """ - ``perform_get_instruction_text`` implements a method which interpretes the bytes passed in ``data`` as a - list of :py:class:`InstructionTextToken` objects. + Deprecated method provided for compatibility. Architecture plugins should override ``get_instruction_text``. :param str data: bytes to decode :param int addr: virtual address of the byte to be decoded @@ -1424,10 +1216,7 @@ class Architecture(object): @abc.abstractmethod def perform_get_instruction_low_level_il(self, data, addr, il): """ - ``perform_get_instruction_low_level_il`` implements a method to interpret the bytes passed in ``data`` to - low-level IL instructions. The il instructions must be appended to the :py:class:`LowLevelILFunction`. - - .. note:: Architecture subclasses should implement this method. + Deprecated method provided for compatibility. Architecture plugins should override ``get_instruction_low_level_il``. :param str data: bytes to be interpreted as low-level IL instructions :param int addr: virtual address of start of ``data`` @@ -1439,8 +1228,7 @@ class Architecture(object): @abc.abstractmethod def perform_get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): """ - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``get_flag_write_low_level_il``. :param LowLevelILOperation op: :param int size: @@ -1458,8 +1246,7 @@ class Architecture(object): @abc.abstractmethod def perform_get_flag_condition_low_level_il(self, cond, sem_class, il): """ - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``get_flag_condition_low_level_il``. :param LowLevelILFlagCondition cond: Flag condition to be computed :param str sem_class: Semantic class to be used (None for default semantics) @@ -1471,8 +1258,7 @@ class Architecture(object): @abc.abstractmethod def perform_get_semantic_flag_group_low_level_il(self, sem_group, il): """ - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``get_semantic_flag_group_low_level_il``. :param str sem_group: Semantic group to be computed :param LowLevelILFunction il: LowLevelILFunction object to append LowLevelILExpr objects to @@ -1483,14 +1269,7 @@ class Architecture(object): @abc.abstractmethod def perform_assemble(self, code, addr): """ - ``perform_assemble`` implements a method to convert the string of assembly instructions ``code`` loaded at - virtual address ``addr`` to the byte representation of those instructions. This can be done by simply shelling - out to an assembler like yasm or llvm-mc, since this method isn't performance sensitive. - - .. note:: Architecture subclasses should implement this method. - .. note :: It is important that the assembler used accepts a syntax identical to the one emitted by the \ - disassembler. This will prevent confusing the user. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``assemble``. :param str code: string representation of the instructions to be assembled :param int addr: virtual address that the instructions will be loaded at @@ -1502,8 +1281,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_never_branch_patch_available(self, data, addr): """ - ``perform_is_never_branch_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a branch instruction that can be made to never branch. + Deprecated method provided for compatibility. Architecture plugins should override ``is_never_branch_patch_available``. .. note:: Architecture subclasses should implement this method. .. warning:: This method should never be called directly. @@ -1518,11 +1296,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_always_branch_patch_available(self, data, addr): """ - ``perform_is_always_branch_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a conditional branch that can be made unconditional. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``is_always_branch_patch_available``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1534,11 +1308,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_invert_branch_patch_available(self, data, addr): """ - ``perform_is_invert_branch_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a conditional branch which can be inverted. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``is_invert_branch_patch_available``. :param int addr: the virtual address of the instruction to be patched :return: True if the instruction can be patched, False otherwise @@ -1549,13 +1319,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_skip_and_return_zero_patch_available(self, data, addr): """ - ``perform_is_skip_and_return_zero_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a *call-like* instruction which can made into instructions - that are equivilent to "return 0". For example if ``data`` was the x86 instruction ``call eax`` which could be - converted into ``xor eax,eax`` thus this function would return True. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``is_skip_and_return_zero_patch_available``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1567,13 +1331,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_skip_and_return_value_patch_available(self, data, addr): """ - ``perform_is_skip_and_return_value_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a *call-like* instruction which can made into instructions - that are equivilent to "return 0". For example if ``data`` was the x86 instruction ``call 0xdeadbeef`` which could be - converted into ``mov eax, 42`` thus this function would return True. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``is_skip_and_return_value_patch_available``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1585,10 +1343,7 @@ class Architecture(object): @abc.abstractmethod def perform_convert_to_nop(self, data, addr): """ - ``perform_convert_to_nop`` implements a method which returns a nop sequence of len(data) bytes long. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``convert_to_nop``. :param str data: bytes at virtual address ``addr`` :param int addr: the virtual address of the instruction to be patched @@ -1600,11 +1355,7 @@ class Architecture(object): @abc.abstractmethod def perform_always_branch(self, data, addr): """ - ``perform_always_branch`` implements a method which converts the branch represented by the bytes in ``data`` to - at ``addr`` to an unconditional branch. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``always_branch``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1616,11 +1367,7 @@ class Architecture(object): @abc.abstractmethod def perform_invert_branch(self, data, addr): """ - ``perform_invert_branch`` implements a method which inverts the branch represented by the bytes in ``data`` to - at ``addr``. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``invert_branch``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1632,12 +1379,7 @@ class Architecture(object): @abc.abstractmethod def perform_skip_and_return_value(self, data, addr, value): """ - ``perform_skip_and_return_value`` implements a method which converts a *call-like* instruction represented by - the bytes in ``data`` at ``addr`` to one or more instructions that are equivilent to a function returning a - value. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``skip_and_return_value``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1647,76 +1389,70 @@ class Architecture(object): """ return None + def perform_get_flag_role(self, flag, sem_class): + """ + Deprecated method provided for compatibility. Architecture plugins should override ``get_flag_role``. + """ + if flag in self._flag_roles: + return self._flag_roles[flag] + return FlagRole.SpecialFlagRole + + def perform_get_flags_required_for_flag_condition(self, cond, sem_class): + """ + Deprecated method provided for compatibility. Architecture plugins should override ``get_flags_required_for_flag_condition``. + """ + if cond in self.flags_required_for_flag_condition: + return self.flags_required_for_flag_condition[cond] + return [] + def get_associated_arch_by_address(self, addr): - new_addr = ctypes.c_ulonglong() - new_addr.value = addr - result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr) - return Architecture(handle = result), new_addr.value + return self.perform_get_associated_arch_by_address(addr) def get_instruction_info(self, data, addr): """ ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address ``addr`` with data ``data``. + .. note:: Architecture subclasses should implement this method. + .. note :: The instruction info object should always set the InstructionInfo.length to the instruction length, \ and the branches of the proper types shoulde be added if the instruction is a branch. + If the instruction is a branch instruction architecture plugins should add a branch of the proper type: + + ===================== =================================================== + BranchType Description + ===================== =================================================== + UnconditionalBranch Branch will always be taken + FalseBranch False branch condition + TrueBranch True branch condition + CallDestination Branch is a call instruction (Branch with Link) + FunctionReturn Branch returns from a function + SystemCall System call instruction + IndirectBranch Branch destination is a memory address or register + UnresolvedBranch Branch destination is an unknown address + ===================== =================================================== + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` :param int addr: virtual address of bytes in ``data`` :return: the InstructionInfo for the current instruction :rtype: InstructionInfo """ - info = core.BNInstructionInfo() - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - if not core.BNGetInstructionInfo(self.handle, buf, addr, len(data), info): - return None - result = function.InstructionInfo() - result.length = info.length - result.arch_transition_by_target_addr = info.archTransitionByTargetAddr - result.branch_delay = info.branchDelay - for i in xrange(0, info.branchCount): - target = info.branchTarget[i] - if info.branchArch[i]: - arch = Architecture(info.branchArch[i]) - else: - arch = None - result.add_branch(BranchType(info.branchType[i]), target, arch) - return result + return self.perform_get_instruction_info(data, addr) def get_instruction_text(self, data, addr): """ ``get_instruction_text`` returns a list of InstructionTextToken objects for the instruction at the given virtual address ``addr`` with data ``data``. + .. note:: Architecture subclasses should implement this method. + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` :param int addr: virtual address of bytes in ``data`` :return: an InstructionTextToken list for the current instruction :rtype: list(InstructionTextToken) """ - data = str(data) - count = ctypes.c_ulonglong() - length = ctypes.c_ulonglong() - length.value = len(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - tokens = ctypes.POINTER(core.BNInstructionTextToken)() - if not core.BNGetInstructionText(self.handle, buf, addr, length, tokens, count): - return None, 0 - 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 - confidence = tokens[i].confidence - address = tokens[i].address - result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - core.BNFreeInstructionText(tokens, count.value) - return result, length.value + return self.perform_get_instruction_text(data, addr) def get_instruction_low_level_il_instruction(self, bv, addr): il = lowlevelil.LowLevelILFunction(self) @@ -1732,19 +1468,15 @@ class Architecture(object): This is used to analyze arbitrary data at an address, if you are working with an existing binary, you likely want to be using ``Function.get_low_level_il_at``. + .. note:: Architecture subclasses should implement this method. + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` :param int addr: virtual address of bytes in ``data`` :param LowLevelILFunction il: The function the current instruction belongs to :return: the length of the current instruction :rtype: int """ - data = str(data) - length = ctypes.c_ulonglong() - length.value = len(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - core.BNGetInstructionLowLevelIL(self.handle, buf, addr, length, il.handle) - return length.value + return self.perform_get_instruction_low_level_il(data, addr, il) def get_low_level_il_from_bytes(self, data, addr): """ @@ -1944,9 +1676,7 @@ class Architecture(object): :return: flag role :rtype: FlagRole """ - flag = self.get_flag_index(flag) - sem_class = self.get_semantic_flag_class_index(sem_class) - return FlagRole(core.BNGetArchitectureFlagRole(self.handle, flag, sem_class)) + return self.perform_get_flag_role(flag, sem_class) def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): """ @@ -1958,20 +1688,7 @@ class Architecture(object): :param LowLevelILFunction il: :rtype: LowLevelILExpr """ - flag = self.get_flag_index(flag) - operand_list = (core.BNRegisterOrConstant * len(operands))() - for i in xrange(len(operands)): - if isinstance(operands[i], str): - operand_list[i].constant = False - operand_list[i].reg = self.regs[operands[i]].index - elif isinstance(operands[i], lowlevelil.ILRegister): - operand_list[i].constant = False - operand_list[i].reg = operands[i].index - else: - operand_list[i].constant = True - operand_list[i].value = operands[i] - return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagWriteLowLevelIL(self.handle, op, size, - self._flag_write_types[write_type], flag, operand_list, len(operand_list), il.handle)) + return self.perform_get_flag_write_low_level_il(op, size, write_type, flag, operands, il) def get_default_flag_write_low_level_il(self, op, size, role, operands, il): """ @@ -1997,13 +1714,14 @@ class Architecture(object): return lowlevelil.LowLevelILExpr(core.BNGetDefaultArchitectureFlagWriteLowLevelIL(self.handle, op, size, role, operand_list, len(operand_list), il.handle)) - def get_flag_condition_low_level_il(self, cond, il): + def get_flag_condition_low_level_il(self, cond, sem_class, il): """ - :param LowLevelILFlagCondition cond: - :param LowLevelILFunction il: + :param LowLevelILFlagCondition cond: Flag condition to be computed + :param str sem_class: Semantic class to be used (None for default semantics) + :param LowLevelILFunction il: LowLevelILFunction object to append LowLevelILExpr objects to :rtype: LowLevelILExpr """ - return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagConditionLowLevelIL(self.handle, cond, il.handle)) + return self.perform_get_flag_condition_low_level_il(cond, sem_class, il) def get_default_flag_condition_low_level_il(self, cond, sem_class, il): """ @@ -2021,18 +1739,10 @@ class Architecture(object): :param LowLevelILFunction il: :rtype: LowLevelILExpr """ - group_index = self.get_semantic_flag_group_index(sem_group) - return lowlevelil.LowLevelILExpr(core.BNGetArchitectureSemanticFlagGroupLowLevelIL(self.handle, group_index, il.handle)) + return self.perform_get_semantic_flag_group_low_level_il(sem_group, il) def get_flags_required_for_flag_condition(self, cond, sem_class = None): - sem_class = self.get_semantic_flag_class_index(sem_class) - count = ctypes.c_ulonglong() - flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, sem_class, count) - flag_names = [] - for i in xrange(0, count.value): - flag_names.append(self._flags_by_index[flags[i]]) - core.BNFreeRegisterList(flags) - return flag_names + return self.perform_get_flags_required_for_flag_condition(cond, sem_class) def get_modified_regs_on_write(self, reg): """ @@ -2056,6 +1766,14 @@ class Architecture(object): ``assemble`` converts the string of assembly instructions ``code`` loaded at virtual address ``addr`` to the byte representation of those instructions. + .. note:: Architecture subclasses should implement this method. + + Architecture plugins can override this method to provide assembler functionality. This can be done by + simply shelling out to an assembler like yasm or llvm-mc, since this method isn't performance sensitive. + + .. note :: It is important that the assembler used accepts a syntax identical to the one emitted by the \ + disassembler. This will prevent confusing the user. + :param str code: string representation of the instructions to be assembled :param int addr: virtual address that the instructions will be loaded at :return: the bytes for the assembled instructions or error string @@ -2066,16 +1784,14 @@ class Architecture(object): ('\\x0f\\x84\\x04\\x00\\x00\\x00', '') >>> """ - result = databuffer.DataBuffer() - errors = ctypes.c_char_p() - if not core.BNAssemble(self.handle, code, addr, result.handle, errors): - return None, errors.value - return str(result), errors.value + return self.perform_assemble(code, addr) def is_never_branch_patch_available(self, data, addr): """ ``is_never_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **never branch**. + .. note:: Architecture subclasses should implement this method. + :param str data: bytes for the instruction to be checked :param int addr: the virtual address of the instruction to be patched :return: True if the instruction can be patched, False otherwise @@ -2088,16 +1804,15 @@ class Architecture(object): False >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - return core.BNIsArchitectureNeverBranchPatchAvailable(self.handle, buf, addr, len(data)) + return self.perform_is_never_branch_patch_available(data, addr) def is_always_branch_patch_available(self, data, addr): """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **always branch**. + .. note:: Architecture subclasses should implement this method. + :param str data: bytes for the instruction to be checked :param int addr: the virtual address of the instruction to be patched :return: True if the instruction can be patched, False otherwise @@ -2110,15 +1825,14 @@ class Architecture(object): False >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - return core.BNIsArchitectureAlwaysBranchPatchAvailable(self.handle, buf, addr, len(data)) + return self.perform_is_always_branch_patch_available(data, addr) def is_invert_branch_patch_available(self, data, addr): """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be inverted. + .. note:: Architecture subclasses should implement this method. + :param str data: bytes for the instruction to be checked :param int addr: the virtual address of the instruction to be patched :return: True if the instruction can be patched, False otherwise @@ -2131,16 +1845,15 @@ class Architecture(object): False >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - return core.BNIsArchitectureInvertBranchPatchAvailable(self.handle, buf, addr, len(data)) + return self.perform_is_invert_branch_patch_available(data, addr) def is_skip_and_return_zero_patch_available(self, data, addr): """ ``is_skip_and_return_zero_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns zero*. + .. note:: Architecture subclasses should implement this method. + :param str data: bytes for the instruction to be checked :param int addr: the virtual address of the instruction to be patched :return: True if the instruction can be patched, False otherwise @@ -2155,39 +1868,37 @@ class Architecture(object): False >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - return core.BNIsArchitectureSkipAndReturnZeroPatchAvailable(self.handle, buf, addr, len(data)) + return self.perform_is_skip_and_return_zero_patch_available(data, addr) def is_skip_and_return_value_patch_available(self, data, addr): """ - ``is_skip_and_return_zero_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* + ``is_skip_and_return_value_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns a value*. + .. note:: Architecture subclasses should implement this method. + :param str data: bytes for the instruction to be checked :param int addr: the virtual address of the instruction to be patched :return: True if the instruction can be patched, False otherwise :rtype: bool :Example: - >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("call 0")[0], 0) + >>> arch.is_skip_and_return_value_patch_available(arch.assemble("call 0")[0], 0) True - >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("jmp eax")[0], 0) + >>> arch.is_skip_and_return_value_patch_available(arch.assemble("jmp eax")[0], 0) False >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - return core.BNIsArchitectureSkipAndReturnValuePatchAvailable(self.handle, buf, addr, len(data)) + return self.perform_is_skip_and_return_value_patch_available(data, addr) def convert_to_nop(self, data, addr): """ ``convert_to_nop`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of nop instructions of the same length as data. - :param str data: bytes for the instruction to be converted + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction to be converted :param int addr: the virtual address of the instruction to be patched :return: string containing len(data) worth of no-operation instructions :rtype: str @@ -2197,20 +1908,15 @@ class Architecture(object): '\\x90\\x90' >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - if not core.BNArchitectureConvertToNop(self.handle, buf, addr, len(data)): - return None - result = ctypes.create_string_buffer(len(data)) - ctypes.memmove(result, buf, len(data)) - return result.raw + return self.perform_convert_to_nop(data, addr) def always_branch(self, data, addr): """ ``always_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which always branches. + .. note:: Architecture subclasses should implement this method. + :param str data: bytes for the instruction to be converted :param int addr: the virtual address of the instruction to be patched :return: string containing len(data) which always branches to the same location as the provided instruction @@ -2224,20 +1930,15 @@ class Architecture(object): (['jmp ', '0x9'], 5L) >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - if not core.BNArchitectureAlwaysBranch(self.handle, buf, addr, len(data)): - return None - result = ctypes.create_string_buffer(len(data)) - ctypes.memmove(result, buf, len(data)) - return result.raw + return self.perform_always_branch(data, addr) def invert_branch(self, data, addr): """ ``invert_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which inverts the branch of provided instruction. + .. note:: Architecture subclasses should implement this method. + :param str data: bytes for the instruction to be converted :param int addr: the virtual address of the instruction to be patched :return: string containing len(data) which always branches to the same location as the provided instruction @@ -2252,20 +1953,15 @@ class Architecture(object): (['jl ', '0xa'], 6L) >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - if not core.BNArchitectureInvertBranch(self.handle, buf, addr, len(data)): - return None - result = ctypes.create_string_buffer(len(data)) - ctypes.memmove(result, buf, len(data)) - return result.raw + return self.perform_invert_branch(data, addr) def skip_and_return_value(self, data, addr, value): """ ``skip_and_return_value`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which doesn't call and instead *return a value*. + .. note:: Architecture subclasses should implement this method. + :param str data: bytes for the instruction to be converted :param int addr: the virtual address of the instruction to be patched :return: string containing len(data) which always branches to the same location as the provided instruction @@ -2276,14 +1972,7 @@ class Architecture(object): (['mov ', 'eax', ', ', '0x0'], 5L) >>> """ - data = str(data) - buf = (ctypes.c_ubyte * len(data))() - ctypes.memmove(buf, data, len(data)) - if not core.BNArchitectureSkipAndReturnValue(self.handle, buf, addr, len(data), value): - return None - result = ctypes.create_string_buffer(len(data)) - ctypes.memmove(result, buf, len(data)) - return result.raw + return self.perform_skip_and_return_value(data, addr, value) def is_view_type_constant_defined(self, type_name, const_name): """ @@ -2348,6 +2037,656 @@ class Architecture(object): core.BNRegisterCallingConvention(self.handle, cc.handle) +class CoreArchitecture(Architecture): + def __init__(self, handle): + super(CoreArchitecture, self).__init__() + + self.handle = core.handle_of_type(handle, core.BNArchitecture) + self.__dict__["name"] = core.BNGetArchitectureName(self.handle) + self.__dict__["endianness"] = Endianness(core.BNGetArchitectureEndianness(self.handle)) + self.__dict__["address_size"] = core.BNGetArchitectureAddressSize(self.handle) + self.__dict__["default_int_size"] = core.BNGetArchitectureDefaultIntegerSize(self.handle) + self.__dict__["instr_alignment"] = core.BNGetArchitectureInstructionAlignment(self.handle) + self.__dict__["max_instr_length"] = core.BNGetArchitectureMaxInstructionLength(self.handle) + self.__dict__["opcode_display_length"] = core.BNGetArchitectureOpcodeDisplayLength(self.handle) + self.__dict__["stack_pointer"] = core.BNGetArchitectureRegisterName(self.handle, + core.BNGetArchitectureStackPointerRegister(self.handle)) + + link_reg = core.BNGetArchitectureLinkRegister(self.handle) + if link_reg == 0xffffffff: + self.__dict__["link_reg"] = None + else: + self.__dict__["link_reg"] = core.BNGetArchitectureRegisterName(self.handle, link_reg) + + count = ctypes.c_ulonglong() + regs = core.BNGetAllArchitectureRegisters(self.handle, count) + self._all_regs = {} + self._regs_by_index = {} + self._full_width_regs = {} + self.__dict__["regs"] = {} + for i in xrange(0, count.value): + name = core.BNGetArchitectureRegisterName(self.handle, regs[i]) + info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) + full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister) + self.regs[name] = function.RegisterInfo(full_width_reg, info.size, info.offset, + ImplicitRegisterExtend(info.extend), regs[i]) + self._all_regs[name] = regs[i] + self._regs_by_index[regs[i]] = name + for i in xrange(0, count.value): + info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) + full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister) + if full_width_reg not in self._full_width_regs: + self._full_width_regs[full_width_reg] = self._all_regs[full_width_reg] + core.BNFreeRegisterList(regs) + + count = ctypes.c_ulonglong() + flags = core.BNGetAllArchitectureFlags(self.handle, count) + self._flags = {} + self._flags_by_index = {} + self.__dict__["flags"] = [] + for i in xrange(0, count.value): + name = core.BNGetArchitectureFlagName(self.handle, flags[i]) + self._flags[name] = flags[i] + self._flags_by_index[flags[i]] = name + self.flags.append(name) + core.BNFreeRegisterList(flags) + + count = ctypes.c_ulonglong() + write_types = core.BNGetAllArchitectureFlagWriteTypes(self.handle, count) + self._flag_write_types = {} + self._flag_write_types_by_index = {} + self.__dict__["flag_write_types"] = [] + for i in xrange(0, count.value): + name = core.BNGetArchitectureFlagWriteTypeName(self.handle, write_types[i]) + self._flag_write_types[name] = write_types[i] + self._flag_write_types_by_index[write_types[i]] = name + self.flag_write_types.append(name) + core.BNFreeRegisterList(write_types) + + count = ctypes.c_ulonglong() + sem_classes = core.BNGetAllArchitectureSemanticFlagClasses(self.handle, count) + self._semantic_flag_classes = {} + self._semantic_flag_classes_by_index = {} + self.__dict__["semantic_flag_classes"] = [] + for i in xrange(0, count.value): + name = core.BNGetArchitectureSemanticFlagClassName(self.handle, sem_classes[i]) + self._semantic_flag_classes[name] = sem_classes[i] + self._semantic_flag_classes_by_index[sem_classes[i]] = name + self.semantic_flag_classes.append(name) + core.BNFreeRegisterList(sem_classes) + + count = ctypes.c_ulonglong() + sem_groups = core.BNGetAllArchitectureSemanticFlagGroups(self.handle, count) + self._semantic_flag_groups = {} + self._semantic_flag_groups_by_index = {} + self.__dict__["semantic_flag_groups"] = [] + for i in xrange(0, count.value): + name = core.BNGetArchitectureSemanticFlagGroupName(self.handle, sem_groups[i]) + self._semantic_flag_groups[name] = sem_groups[i] + self._semantic_flag_groups_by_index[sem_groups[i]] = name + self.semantic_flag_groups.append(name) + core.BNFreeRegisterList(sem_groups) + + self._flag_roles = {} + self.__dict__["flag_roles"] = {} + for flag in self.__dict__["flags"]: + role = FlagRole(core.BNGetArchitectureFlagRole(self.handle, self._flags[flag], 0)) + self.__dict__["flag_roles"][flag] = role + self._flag_roles[self._flags[flag]] = role + + self.__dict__["flags_required_for_flag_condition"] = {} + for cond in LowLevelILFlagCondition: + count = ctypes.c_ulonglong() + flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, 0, count) + flag_names = [] + for i in xrange(0, count.value): + flag_names.append(self._flags_by_index[flags[i]]) + core.BNFreeRegisterList(flags) + self.__dict__["flags_required_for_flag_condition"][cond] = flag_names + + self._flags_required_by_semantic_flag_group = {} + self.__dict__["flags_required_for_semantic_flag_group"] = {} + for group in self.semantic_flag_groups: + count = ctypes.c_ulonglong() + flags = core.BNGetArchitectureFlagsRequiredForSemanticFlagGroup(self.handle, + self._semantic_flag_groups[group], count) + flag_indexes = [] + flag_names = [] + for i in xrange(0, count.value): + flag_indexes.append(flags[i]) + flag_names.append(self._flags_by_index[flags[i]]) + core.BNFreeRegisterList(flags) + self._flags_required_by_semantic_flag_group[self._semantic_flag_groups[group]] = flag_indexes + self.__dict__["flags_required_for_semantic_flag_group"][cond] = flag_names + + self._flag_conditions_for_semantic_flag_group = {} + self.__dict__["flag_conditions_for_semantic_flag_group"] = {} + for group in self.semantic_flag_groups: + count = ctypes.c_ulonglong() + conditions = core.BNGetArchitectureFlagConditionsForSemanticFlagGroup(self.handle, + self._semantic_flag_groups[group], count) + class_index_cond = {} + class_cond = {} + for i in xrange(0, count.value): + class_index_cond[conditions[i].semanticClass] = conditions[i].condition + if conditions[i].semanticClass == 0: + class_cond[None] = conditions[i].condition + elif conditions[i].semanticClass in self._semantic_flag_classes_by_index: + class_cond[self._semantic_flag_classes_by_index[conditions[i].semanticClass]] = conditions[i].condition + core.BNFreeFlagConditionsForSemanticFlagGroup(conditions) + self._flag_conditions_for_semantic_flag_group[self._semantic_flag_groups[group]] = class_index_cond + self.__dict__["flag_conditions_for_semantic_flag_group"][group] = class_cond + + self._flags_written_by_flag_write_type = {} + self.__dict__["flags_written_by_flag_write_type"] = {} + for write_type in self.flag_write_types: + count = ctypes.c_ulonglong() + flags = core.BNGetArchitectureFlagsWrittenByFlagWriteType(self.handle, + self._flag_write_types[write_type], count) + flag_indexes = [] + flag_names = [] + for i in xrange(0, count.value): + flag_indexes.append(flags[i]) + flag_names.append(self._flags_by_index[flags[i]]) + core.BNFreeRegisterList(flags) + self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flag_indexes + self.__dict__["flags_written_by_flag_write_type"][write_type] = flag_names + + self._semantic_class_for_flag_write_type = {} + self.__dict__["semantic_class_for_flag_write_type"] = {} + for write_type in self.flag_write_types: + sem_class = core.BNGetArchitectureSemanticClassForFlagWriteType(self.handle, + self._flag_write_types[write_type]) + if sem_class == 0: + sem_class_name = None + else: + sem_class_name = self._semantic_flag_classes_by_index[sem_class] + self._semantic_class_for_flag_write_type[self._flag_write_types[write_type]] = sem_class + self.__dict__["semantic_class_for_flag_write_type"][write_type] = sem_class_name + + count = ctypes.c_ulonglong() + regs = core.BNGetArchitectureGlobalRegisters(self.handle, count) + self.__dict__["global_regs"] = [] + for i in xrange(0, count.value): + self.global_regs.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) + core.BNFreeRegisterList(regs) + + count = ctypes.c_ulonglong() + regs = core.BNGetAllArchitectureRegisterStacks(self.handle, count) + self._all_reg_stacks = {} + self._reg_stacks_by_index = {} + self.__dict__["reg_stacks"] = {} + for i in xrange(0, count.value): + name = core.BNGetArchitectureRegisterStackName(self.handle, regs[i]) + info = core.BNGetArchitectureRegisterStackInfo(self.handle, regs[i]) + storage = [] + for j in xrange(0, info.storageCount): + storage.append(core.BNGetArchitectureRegisterName(self.handle, info.firstStorageReg + j)) + top_rel = [] + for j in xrange(0, info.topRelativeCount): + top_rel.append(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j)) + top = core.BNGetArchitectureRegisterName(self.handle, info.stackTopReg) + self.reg_stacks[name] = function.RegisterStackInfo(storage, top_rel, top, regs[i]) + self._all_reg_stacks[name] = regs[i] + self._reg_stacks_by_index[regs[i]] = name + core.BNFreeRegisterList(regs) + + count = ctypes.c_ulonglong() + intrinsics = core.BNGetAllArchitectureIntrinsics(self.handle, count) + self._intrinsics = {} + self._intrinsics_by_index = {} + self.__dict__["intrinsics"] = {} + for i in xrange(0, count.value): + name = core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i]) + input_count = ctypes.c_ulonglong() + inputs = core.BNGetArchitectureIntrinsicInputs(self.handle, intrinsics[i], input_count) + input_list = [] + for j in xrange(0, input_count.value): + input_name = inputs[j].name + type_obj = types.Type(core.BNNewTypeReference(inputs[j].type), confidence = inputs[j].typeConfidence) + input_list.append(function.IntrinsicInput(type_obj, input_name)) + core.BNFreeNameAndTypeList(inputs, input_count.value) + output_count = ctypes.c_ulonglong() + outputs = core.BNGetArchitectureIntrinsicOutputs(self.handle, intrinsics[i], output_count) + output_list = [] + for j in xrange(0, output_count.value): + output_list.append(types.Type(core.BNNewTypeReference(outputs[j].type), confidence = outputs[j].confidence)) + core.BNFreeOutputTypeList(outputs, output_count.value) + self.intrinsics[name] = function.IntrinsicInfo(input_list, output_list) + self._intrinsics[name] = intrinsics[i] + self._intrinsics_by_index[intrinsics[i]] = (name, self.intrinsics[name]) + core.BNFreeRegisterList(intrinsics) + + def get_associated_arch_by_address(self, addr): + new_addr = ctypes.c_ulonglong() + new_addr.value = addr + result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr) + return CoreArchitecture(handle = result), new_addr.value + + def get_instruction_info(self, data, addr): + """ + ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address + ``addr`` with data ``data``. + + .. note :: The instruction info object should always set the InstructionInfo.length to the instruction length, \ + and the branches of the proper types shoulde be added if the instruction is a branch. + + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` + :param int addr: virtual address of bytes in ``data`` + :return: the InstructionInfo for the current instruction + :rtype: InstructionInfo + """ + info = core.BNInstructionInfo() + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + if not core.BNGetInstructionInfo(self.handle, buf, addr, len(data), info): + return None + result = function.InstructionInfo() + result.length = info.length + result.arch_transition_by_target_addr = info.archTransitionByTargetAddr + result.branch_delay = info.branchDelay + for i in xrange(0, info.branchCount): + target = info.branchTarget[i] + if info.branchArch[i]: + arch = CoreArchitecture(info.branchArch[i]) + else: + arch = None + result.add_branch(BranchType(info.branchType[i]), target, arch) + return result + + def get_instruction_text(self, data, addr): + """ + ``get_instruction_text`` returns a list of InstructionTextToken objects for the instruction at the given virtual + address ``addr`` with data ``data``. + + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` + :param int addr: virtual address of bytes in ``data`` + :return: an InstructionTextToken list for the current instruction + :rtype: list(InstructionTextToken) + """ + data = str(data) + count = ctypes.c_ulonglong() + length = ctypes.c_ulonglong() + length.value = len(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + tokens = ctypes.POINTER(core.BNInstructionTextToken)() + if not core.BNGetInstructionText(self.handle, buf, addr, length, tokens, count): + return None, 0 + 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 + confidence = tokens[i].confidence + address = tokens[i].address + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) + core.BNFreeInstructionText(tokens, count.value) + return result, length.value + + def get_instruction_low_level_il(self, data, addr, il): + """ + ``get_instruction_low_level_il`` appends LowLevelILExpr objects to ``il`` for the instruction at the given + virtual address ``addr`` with data ``data``. + + This is used to analyze arbitrary data at an address, if you are working with an existing binary, you likely + want to be using ``Function.get_low_level_il_at``. + + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` + :param int addr: virtual address of bytes in ``data`` + :param LowLevelILFunction il: The function the current instruction belongs to + :return: the length of the current instruction + :rtype: int + """ + data = str(data) + length = ctypes.c_ulonglong() + length.value = len(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + core.BNGetInstructionLowLevelIL(self.handle, buf, addr, length, il.handle) + return length.value + + def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): + """ + :param LowLevelILOperation op: + :param int size: + :param str write_type: + :param list(str or int) operands: a list of either items that are either string register names or constant \ + integer values + :param LowLevelILFunction il: + :rtype: LowLevelILExpr + """ + flag = self.get_flag_index(flag) + operand_list = (core.BNRegisterOrConstant * len(operands))() + for i in xrange(len(operands)): + if isinstance(operands[i], str): + operand_list[i].constant = False + operand_list[i].reg = self.regs[operands[i]].index + elif isinstance(operands[i], lowlevelil.ILRegister): + operand_list[i].constant = False + operand_list[i].reg = operands[i].index + else: + operand_list[i].constant = True + operand_list[i].value = operands[i] + return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagWriteLowLevelIL(self.handle, op, size, + self._flag_write_types[write_type], flag, operand_list, len(operand_list), il.handle)) + + def get_flag_condition_low_level_il(self, cond, sem_class, il): + """ + :param LowLevelILFlagCondition cond: Flag condition to be computed + :param str sem_class: Semantic class to be used (None for default semantics) + :param LowLevelILFunction il: LowLevelILFunction object to append LowLevelILExpr objects to + :rtype: LowLevelILExpr + """ + class_index = self.get_semantic_flag_class_index(sem_class) + return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagConditionLowLevelIL(self.handle, cond, + class_index, il.handle)) + + def get_semantic_flag_group_low_level_il(self, sem_group, il): + """ + :param str sem_group: + :param LowLevelILFunction il: + :rtype: LowLevelILExpr + """ + group_index = self.get_semantic_flag_group_index(sem_group) + return lowlevelil.LowLevelILExpr(core.BNGetArchitectureSemanticFlagGroupLowLevelIL(self.handle, group_index, il.handle)) + + def assemble(self, code, addr=0): + """ + ``assemble`` converts the string of assembly instructions ``code`` loaded at virtual address ``addr`` to the + byte representation of those instructions. + + :param str code: string representation of the instructions to be assembled + :param int addr: virtual address that the instructions will be loaded at + :return: the bytes for the assembled instructions or error string + :rtype: (a tuple of instructions and empty string) or (or None and error string) + :Example: + + >>> arch.assemble("je 10") + ('\\x0f\\x84\\x04\\x00\\x00\\x00', '') + >>> + """ + result = databuffer.DataBuffer() + errors = ctypes.c_char_p() + if not core.BNAssemble(self.handle, code, addr, result.handle, errors): + return None, errors.value + return str(result), errors.value + + def is_never_branch_patch_available(self, data, addr): + """ + ``is_never_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **never branch**. + + :param str data: bytes for the instruction to be checked + :param int addr: the virtual address of the instruction to be patched + :return: True if the instruction can be patched, False otherwise + :rtype: bool + :Example: + + >>> arch.is_never_branch_patch_available(arch.assemble("je 10")[0], 0) + True + >>> arch.is_never_branch_patch_available(arch.assemble("nop")[0], 0) + False + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + return core.BNIsArchitectureNeverBranchPatchAvailable(self.handle, buf, addr, len(data)) + + def is_always_branch_patch_available(self, data, addr): + """ + ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to + **always branch**. + + :param str data: bytes for the instruction to be checked + :param int addr: the virtual address of the instruction to be patched + :return: True if the instruction can be patched, False otherwise + :rtype: bool + :Example: + + >>> arch.is_always_branch_patch_available(arch.assemble("je 10")[0], 0) + True + >>> arch.is_always_branch_patch_available(arch.assemble("nop")[0], 0) + False + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + return core.BNIsArchitectureAlwaysBranchPatchAvailable(self.handle, buf, addr, len(data)) + + def is_invert_branch_patch_available(self, data, addr): + """ + ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be inverted. + + :param str data: bytes for the instruction to be checked + :param int addr: the virtual address of the instruction to be patched + :return: True if the instruction can be patched, False otherwise + :rtype: bool + :Example: + + >>> arch.is_invert_branch_patch_available(arch.assemble("je 10")[0], 0) + True + >>> arch.is_invert_branch_patch_available(arch.assemble("nop")[0], 0) + False + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + return core.BNIsArchitectureInvertBranchPatchAvailable(self.handle, buf, addr, len(data)) + + def is_skip_and_return_zero_patch_available(self, data, addr): + """ + ``is_skip_and_return_zero_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* + instruction that can be made into an instruction *returns zero*. + + :param str data: bytes for the instruction to be checked + :param int addr: the virtual address of the instruction to be patched + :return: True if the instruction can be patched, False otherwise + :rtype: bool + :Example: + + >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("call 0")[0], 0) + True + >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("call eax")[0], 0) + True + >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("jmp eax")[0], 0) + False + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + return core.BNIsArchitectureSkipAndReturnZeroPatchAvailable(self.handle, buf, addr, len(data)) + + def is_skip_and_return_value_patch_available(self, data, addr): + """ + ``is_skip_and_return_value_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* + instruction that can be made into an instruction *returns a value*. + + :param str data: bytes for the instruction to be checked + :param int addr: the virtual address of the instruction to be patched + :return: True if the instruction can be patched, False otherwise + :rtype: bool + :Example: + + >>> arch.is_skip_and_return_value_patch_available(arch.assemble("call 0")[0], 0) + True + >>> arch.is_skip_and_return_value_patch_available(arch.assemble("jmp eax")[0], 0) + False + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + return core.BNIsArchitectureSkipAndReturnValuePatchAvailable(self.handle, buf, addr, len(data)) + + def convert_to_nop(self, data, addr): + """ + ``convert_to_nop`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of nop + instructions of the same length as data. + + :param str data: bytes for the instruction to be converted + :param int addr: the virtual address of the instruction to be patched + :return: string containing len(data) worth of no-operation instructions + :rtype: str + :Example: + + >>> arch.convert_to_nop("\\x00\\x00", 0) + '\\x90\\x90' + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + if not core.BNArchitectureConvertToNop(self.handle, buf, addr, len(data)): + return None + result = ctypes.create_string_buffer(len(data)) + ctypes.memmove(result, buf, len(data)) + return result.raw + + def always_branch(self, data, addr): + """ + ``always_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes + of the same length which always branches. + + :param str data: bytes for the instruction to be converted + :param int addr: the virtual address of the instruction to be patched + :return: string containing len(data) which always branches to the same location as the provided instruction + :rtype: str + :Example: + + >>> bytes = arch.always_branch(arch.assemble("je 10")[0], 0) + >>> arch.get_instruction_text(bytes, 0) + (['nop '], 1L) + >>> arch.get_instruction_text(bytes[1:], 0) + (['jmp ', '0x9'], 5L) + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + if not core.BNArchitectureAlwaysBranch(self.handle, buf, addr, len(data)): + return None + result = ctypes.create_string_buffer(len(data)) + ctypes.memmove(result, buf, len(data)) + return result.raw + + def invert_branch(self, data, addr): + """ + ``invert_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes + of the same length which inverts the branch of provided instruction. + + :param str data: bytes for the instruction to be converted + :param int addr: the virtual address of the instruction to be patched + :return: string containing len(data) which always branches to the same location as the provided instruction + :rtype: str + :Example: + + >>> arch.get_instruction_text(arch.invert_branch(arch.assemble("je 10")[0], 0), 0) + (['jne ', '0xa'], 6L) + >>> arch.get_instruction_text(arch.invert_branch(arch.assemble("jo 10")[0], 0), 0) + (['jno ', '0xa'], 6L) + >>> arch.get_instruction_text(arch.invert_branch(arch.assemble("jge 10")[0], 0), 0) + (['jl ', '0xa'], 6L) + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + if not core.BNArchitectureInvertBranch(self.handle, buf, addr, len(data)): + return None + result = ctypes.create_string_buffer(len(data)) + ctypes.memmove(result, buf, len(data)) + return result.raw + + def skip_and_return_value(self, data, addr, value): + """ + ``skip_and_return_value`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of + bytes of the same length which doesn't call and instead *return a value*. + + :param str data: bytes for the instruction to be converted + :param int addr: the virtual address of the instruction to be patched + :return: string containing len(data) which always branches to the same location as the provided instruction + :rtype: str + :Example: + + >>> arch.get_instruction_text(arch.skip_and_return_value(arch.assemble("call 10")[0], 0, 0), 0) + (['mov ', 'eax', ', ', '0x0'], 5L) + >>> + """ + data = str(data) + buf = (ctypes.c_ubyte * len(data))() + ctypes.memmove(buf, data, len(data)) + if not core.BNArchitectureSkipAndReturnValue(self.handle, buf, addr, len(data), value): + return None + result = ctypes.create_string_buffer(len(data)) + ctypes.memmove(result, buf, len(data)) + return result.raw + + def get_flag_role(self, flag, sem_class = None): + """ + ``get_flag_role`` gets the role of a given flag. + + :param int flag: flag + :param int sem_class: optional semantic flag class + :return: flag role + :rtype: FlagRole + """ + flag = self.get_flag_index(flag) + sem_class = self.get_semantic_flag_class_index(sem_class) + return FlagRole(core.BNGetArchitectureFlagRole(self.handle, flag, sem_class)) + + def get_flags_required_for_flag_condition(self, cond, sem_class = None): + sem_class = self.get_semantic_flag_class_index(sem_class) + count = ctypes.c_ulonglong() + flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, sem_class, count) + flag_names = [] + for i in xrange(0, count.value): + flag_names.append(self._flags_by_index[flags[i]]) + core.BNFreeRegisterList(flags) + return flag_names + + +class ArchitectureHook(CoreArchitecture): + def __init__(self, base_arch): + self.base_arch = base_arch + super(ArchitectureHook, self).__init__(base_arch.handle) + + # To improve performance of simpler hooks, use null callback for functions that are not being overridden + if self.get_associated_arch_by_address.__code__ == CoreArchitecture.get_associated_arch_by_address.__code__: + self._cb.getAssociatedArchitectureByAddress = self._cb.getAssociatedArchitectureByAddress.__class__() + if self.get_instruction_info.__code__ == CoreArchitecture.get_instruction_info.__code__: + self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__() + if self.get_instruction_text.__code__ == CoreArchitecture.get_instruction_text.__code__: + self._cb.getInstructionText = self._cb.getInstructionText.__class__() + if self.__class__.stack_pointer is None: + self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__() + if self.__class__.link_reg is None: + self._cb.getLinkRegister = self._cb.getLinkRegister.__class__() + if len(self.__class__.regs) == 0: + self._cb.getRegisterInfo = self._cb.getRegisterInfo.__class__() + self._cb.getRegisterName = self._cb.getRegisterName.__class__() + if len(self.__class__.reg_stacks) == 0: + self._cb.getRegisterStackName = self._cb.getRegisterStackName.__class__() + self._cb.getRegisterStackInfo = self._cb.getRegisterStackInfo.__class__() + if len(self.__class__.intrinsics) == 0: + self._cb.getIntrinsicName = self._cb.getIntrinsicName.__class__() + self._cb.getIntrinsicInputs = self._cb.getIntrinsicInputs.__class__() + self._cb.freeNameAndTypeList = self._cb.freeNameAndTypeList.__class__() + self._cb.getIntrinsicOutputs = self._cb.getIntrinsicOutputs.__class__() + self._cb.freeTypeList = self._cb.freeTypeList.__class__() + + def register(self): + self.__class__._registered_cb = self._cb + self.handle = core.BNRegisterArchitectureHook(self.base_arch.handle, self._cb) + + class ReferenceSource(object): def __init__(self, func, arch, addr): self.function = func diff --git a/python/basicblock.py b/python/basicblock.py index 8e64c1c1..c93d0b2c 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -100,7 +100,7 @@ class BasicBlock(object): arch = core.BNGetBasicBlockArchitecture(self.handle) if arch is None: return None - self._arch = architecture.Architecture(arch) + self._arch = architecture.CoreArchitecture(arch) return self._arch @property diff --git a/python/binaryview.py b/python/binaryview.py index fae98c14..7a6bc875 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -400,7 +400,7 @@ class BinaryViewType(object): arch = core.BNGetArchitectureForViewType(self.handle, ident, endian) if arch is None: return None - return architecture.Architecture(arch) + return architecture.CoreArchitecture(arch) def register_platform(self, ident, arch, plat): core.BNRegisterPlatformForViewType(self.handle, ident, arch.handle, plat.handle) @@ -812,7 +812,7 @@ class BinaryView(object): arch = core.BNGetDefaultArchitecture(self.handle) if arch is None: return None - return architecture.Architecture(handle=arch) + return architecture.CoreArchitecture(handle=arch) @arch.setter def arch(self, value): @@ -2191,7 +2191,7 @@ class BinaryView(object): else: func = None if refs[i].arch: - arch = architecture.Architecture(refs[i].arch) + arch = architecture.CoreArchitecture(refs[i].arch) else: arch = None addr = refs[i].addr diff --git a/python/callingconvention.py b/python/callingconvention.py index 5aad3317..49ef7666 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -75,7 +75,7 @@ class CallingConvention(object): self.__class__._registered_calling_conventions.append(self) else: self.handle = handle - self.arch = architecture.Architecture(core.BNGetCallingConventionArchitecture(self.handle)) + self.arch = architecture.CoreArchitecture(core.BNGetCallingConventionArchitecture(self.handle)) self.__dict__["name"] = core.BNGetCallingConventionName(self.handle) self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(self.handle) self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(self.handle) diff --git a/python/examples/arch_hook.py b/python/examples/arch_hook.py new file mode 100644 index 00000000..452bd2b6 --- /dev/null +++ b/python/examples/arch_hook.py @@ -0,0 +1,16 @@ +from binaryninja.architecture import Architecture, ArchitectureHook + +class X86ReturnHook(ArchitectureHook): + def get_instruction_text(self, data, addr): + # Call the original implementation's method by calling the superclass + result, length = super(X86ReturnHook, self).get_instruction_text(data, addr) + + # Patch the name of the 'retn' instruction to 'ret' + if len(result) > 0 and result[0].text == 'retn': + result[0].text = 'ret' + + return result, length + +# Install the hook by constructing it with the desired architecture to hook, then registering it +X86ReturnHook(Architecture['x86']).register() + diff --git a/python/examples/nes.py b/python/examples/nes.py index 39544c9f..00451abd 100644 --- a/python/examples/nes.py +++ b/python/examples/nes.py @@ -423,7 +423,7 @@ class M6502(Architecture): return instr, operand, length, value - def perform_get_instruction_info(self, data, addr): + def get_instruction_info(self, data, addr): instr, operand, length, value = self.decode_instruction(data, addr) if instr is None: return None @@ -445,7 +445,7 @@ class M6502(Architecture): result.add_branch(BranchType.FalseBranch, addr + 2) return result - def perform_get_instruction_text(self, data, addr): + def get_instruction_text(self, data, addr): instr, operand, length, value = self.decode_instruction(data, addr) if instr is None: return None @@ -455,7 +455,7 @@ class M6502(Architecture): tokens += OperandTokens[operand](value) return tokens, length - def perform_get_instruction_low_level_il(self, data, addr, il): + def get_instruction_low_level_il(self, data, addr, il): instr, operand, length, value = self.decode_instruction(data, addr) if instr is None: return None @@ -470,48 +470,48 @@ class M6502(Architecture): return length - def perform_get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): + def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): if flag == 'c': if (op == LowLevelILOperation.LLIL_SUB) or (op == LowLevelILOperation.LLIL_SBB): # Subtraction carry flag is inverted from the commom implementation return il.not_expr(0, self.get_default_flag_write_low_level_il(op, size, FlagRole.CarryFlagRole, operands, il)) # Other operations use a normal carry flag return self.get_default_flag_write_low_level_il(op, size, FlagRole.CarryFlagRole, operands, il) - return Architecture.perform_get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il) + return Architecture.get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il) - def perform_is_never_branch_patch_available(self, data, addr): + def is_never_branch_patch_available(self, data, addr): if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"): return True return False - def perform_is_invert_branch_patch_available(self, data, addr): + def is_invert_branch_patch_available(self, data, addr): if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"): return True return False - def perform_is_always_branch_patch_available(self, data, addr): + def is_always_branch_patch_available(self, data, addr): return False - def perform_is_skip_and_return_zero_patch_available(self, data, addr): + def is_skip_and_return_zero_patch_available(self, data, addr): return (data[0] == "\x20") and (len(data) == 3) - def perform_is_skip_and_return_value_patch_available(self, data, addr): + def is_skip_and_return_value_patch_available(self, data, addr): return (data[0] == "\x20") and (len(data) == 3) - def perform_convert_to_nop(self, data, addr): + def convert_to_nop(self, data, addr): return "\xea" * len(data) - def perform_never_branch(self, data, addr): + def never_branch(self, data, addr): if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"): return "\xea" * len(data) return None - def perform_invert_branch(self, data, addr): + def invert_branch(self, data, addr): if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"): return chr(ord(data[0]) ^ 0x20) + data[1:] return None - def perform_skip_and_return_value(self, data, addr, value): + def skip_and_return_value(self, data, addr, value): if (data[0] != "\x20") or (len(data) != 3): return None return "\xa9" + chr(value & 0xff) + "\xea" diff --git a/python/function.py b/python/function.py index 39ace7c6..f68aa76f 100644 --- a/python/function.py +++ b/python/function.py @@ -419,7 +419,7 @@ class Function(object): arch = core.BNGetFunctionArchitecture(self.handle) if arch is None: return None - self._arch = architecture.Architecture(arch) + self._arch = architecture.CoreArchitecture(arch) return self._arch @property @@ -557,7 +557,7 @@ class Function(object): branches = core.BNGetIndirectBranches(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.Architecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -1115,7 +1115,7 @@ class Function(object): branches = core.BNGetIndirectBranchesAt(self.handle, arch.handle, addr, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.Architecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -1633,7 +1633,7 @@ class FunctionGraphBlock(object): arch = core.BNGetFunctionGraphBlockArchitecture(self.handle) if arch is None: return None - return architecture.Architecture(arch) + return architecture.CoreArchitecture(arch) @property def start(self): diff --git a/python/platform.py b/python/platform.py index 5e63d836..09670bac 100644 --- a/python/platform.py +++ b/python/platform.py @@ -105,7 +105,7 @@ class Platform(object): else: self.handle = handle self.__dict__["name"] = core.BNGetPlatformName(self.handle) - self.arch = architecture.Architecture(core.BNGetPlatformArchitecture(self.handle)) + self.arch = architecture.CoreArchitecture(core.BNGetPlatformArchitecture(self.handle)) def __del__(self): core.BNFreePlatform(self.handle) -- cgit v1.3.1 From 1c7349fcf125994f2e577361626fe1fb02eac029 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 7 Mar 2018 18:10:55 -0500 Subject: Add APIs for skipping analysis of functions that are too large, and overriding this behavior --- binaryninjaapi.h | 11 +++++++++++ binaryninjacore.h | 17 +++++++++++++++++ binaryview.cpp | 23 +++++++++++++++++++++++ function.cpp | 24 ++++++++++++++++++++++++ functiongraph.cpp | 6 ++++++ python/binaryview.py | 19 +++++++++++++++++++ python/function.py | 34 +++++++++++++++++++++++++++++++++- 7 files changed, 133 insertions(+), 1 deletion(-) (limited to 'python/function.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 89eba009..2d7e2ccf 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -866,6 +866,7 @@ namespace BinaryNinja static void FunctionAddedCallback(void* ctxt, BNBinaryView* data, BNFunction* func); static void FunctionRemovedCallback(void* ctxt, BNBinaryView* data, BNFunction* func); static void FunctionUpdatedCallback(void* ctxt, BNBinaryView* data, BNFunction* func); + static void FunctionUpdateRequestedCallback(void* ctxt, BNBinaryView* data, BNFunction* func); static void DataVariableAddedCallback(void* ctxt, BNBinaryView* data, BNDataVariable* var); static void DataVariableRemovedCallback(void* ctxt, BNBinaryView* data, BNDataVariable* var); static void DataVariableUpdatedCallback(void* ctxt, BNBinaryView* data, BNDataVariable* var); @@ -886,6 +887,7 @@ namespace BinaryNinja virtual void OnAnalysisFunctionAdded(BinaryView* view, Function* func) { (void)view; (void)func; } virtual void OnAnalysisFunctionRemoved(BinaryView* view, Function* func) { (void)view; (void)func; } virtual void OnAnalysisFunctionUpdated(BinaryView* view, Function* func) { (void)view; (void)func; } + virtual void OnAnalysisFunctionUpdateRequested(BinaryView* view, Function* func) { (void)view; (void)func; } virtual void OnDataVariableAdded(BinaryView* view, const DataVariable& var) { (void)view; (void)var; } virtual void OnDataVariableRemoved(BinaryView* view, const DataVariable& var) { (void)view; (void)var; } virtual void OnDataVariableUpdated(BinaryView* view, const DataVariable& var) { (void)view; (void)var; } @@ -1344,6 +1346,9 @@ namespace BinaryNinja std::string GetStringMetadata(const std::string& key); std::vector GetRawMetadata(const std::string& key); uint64_t GetUIntMetadata(const std::string& key); + + uint64_t GetMaxFunctionSizeForAnalysis(); + void SetMaxFunctionSizeForAnalysis(uint64_t size); }; class BinaryData: public BinaryView @@ -2475,6 +2480,11 @@ namespace BinaryNinja Confidence GetGlobalPointerValue() const; Confidence GetRegisterValueAtExit(uint32_t reg) const; + + bool IsFunctionTooLarge(); + bool IsAnalysisSkipped(); + BNFunctionAnalysisSkipOverride GetAnalysisSkipOverride(); + void SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip); }; class AdvancedFunctionAnalysisDataRequestor @@ -2550,6 +2560,7 @@ namespace BinaryNinja void Abort(); std::vector> GetBlocks(); + bool HasBlocks() const; int GetWidth() const; int GetHeight() const; diff --git a/binaryninjacore.h b/binaryninjacore.h index 5329a1d9..a1b78b1c 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -989,6 +989,7 @@ extern "C" void (*functionAdded)(void* ctxt, BNBinaryView* view, BNFunction* func); void (*functionRemoved)(void* ctxt, BNBinaryView* view, BNFunction* func); void (*functionUpdated)(void* ctxt, BNBinaryView* view, BNFunction* func); + void (*functionUpdateRequested)(void* ctxt, BNBinaryView* view, BNFunction* func); void (*dataVariableAdded)(void* ctxt, BNBinaryView* view, BNDataVariable* var); void (*dataVariableRemoved)(void* ctxt, BNBinaryView* view, BNDataVariable* var); void (*dataVariableUpdated)(void* ctxt, BNBinaryView* view, BNDataVariable* var); @@ -1739,6 +1740,13 @@ extern "C" uint8_t confidence; }; + enum BNFunctionAnalysisSkipOverride + { + DefaultFunctionAnalysisSkip, + NeverSkipFunctionAnalysis, + AlwaysSkipFunctionAnalysis + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); BINARYNINJACOREAPI char** BNAllocStringList(const char** contents, size_t size); @@ -2421,6 +2429,14 @@ extern "C" BINARYNINJACOREAPI void BNSetIntegerConstantDisplayType(BNFunction* func, BNArchitecture* arch, uint64_t instrAddr, uint64_t value, size_t operand, BNIntegerDisplayType type); + BINARYNINJACOREAPI bool BNIsFunctionTooLarge(BNFunction* func); + BINARYNINJACOREAPI bool BNIsFunctionAnalysisSkipped(BNFunction* func); + BINARYNINJACOREAPI BNFunctionAnalysisSkipOverride BNGetFunctionAnalysisSkipOverride(BNFunction* func); + BINARYNINJACOREAPI void BNSetFunctionAnalysisSkipOverride(BNFunction* func, BNFunctionAnalysisSkipOverride skip); + + BINARYNINJACOREAPI uint64_t BNGetMaxFunctionSizeForAnalysis(BNBinaryView* view); + BINARYNINJACOREAPI void BNSetMaxFunctionSizeForAnalysis(BNBinaryView* view, uint64_t size); + BINARYNINJACOREAPI BNAnalysisCompletionEvent* BNAddAnalysisCompletionEvent(BNBinaryView* view, void* ctxt, void (*callback)(void* ctxt)); BINARYNINJACOREAPI BNAnalysisCompletionEvent* BNNewAnalysisCompletionEventReference(BNAnalysisCompletionEvent* event); @@ -2536,6 +2552,7 @@ extern "C" BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocksInRegion( BNFunctionGraph* graph, int left, int top, int right, int bottom, size_t* count); BINARYNINJACOREAPI void BNFreeFunctionGraphBlockList(BNFunctionGraphBlock** blocks, size_t count); + BINARYNINJACOREAPI bool BNFunctionGraphHasBlocks(BNFunctionGraph* graph); BINARYNINJACOREAPI int BNGetFunctionGraphWidth(BNFunctionGraph* graph); BINARYNINJACOREAPI int BNGetFunctionGraphHeight(BNFunctionGraph* graph); diff --git a/binaryview.cpp b/binaryview.cpp index 96fd161d..0dcf6bc3 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -78,6 +78,15 @@ void BinaryDataNotification::FunctionUpdatedCallback(void* ctxt, BNBinaryView* o } +void BinaryDataNotification::FunctionUpdateRequestedCallback(void* ctxt, BNBinaryView* object, BNFunction* func) +{ + BinaryDataNotification* notify = (BinaryDataNotification*)ctxt; + Ref view = new BinaryView(BNNewViewReference(object)); + Ref funcObj = new Function(BNNewFunctionReference(func)); + notify->OnAnalysisFunctionUpdateRequested(view, funcObj); +} + + void BinaryDataNotification::DataVariableAddedCallback(void* ctxt, BNBinaryView* object, BNDataVariable* var) { BinaryDataNotification* notify = (BinaryDataNotification*)ctxt; @@ -148,6 +157,7 @@ BinaryDataNotification::BinaryDataNotification() m_callbacks.functionAdded = FunctionAddedCallback; m_callbacks.functionRemoved = FunctionRemovedCallback; m_callbacks.functionUpdated = FunctionUpdatedCallback; + m_callbacks.functionUpdateRequested = FunctionUpdateRequestedCallback; m_callbacks.dataVariableAdded = DataVariableAddedCallback; m_callbacks.dataVariableRemoved = DataVariableRemovedCallback; m_callbacks.dataVariableUpdated = DataVariableUpdatedCallback; @@ -1949,6 +1959,19 @@ uint64_t BinaryView::GetUIntMetadata(const string& key) return data->GetUnsignedInteger(); } + +uint64_t BinaryView::GetMaxFunctionSizeForAnalysis() +{ + return BNGetMaxFunctionSizeForAnalysis(m_object); +} + + +void BinaryView::SetMaxFunctionSizeForAnalysis(uint64_t size) +{ + BNSetMaxFunctionSizeForAnalysis(m_object, size); +} + + BinaryData::BinaryData(FileMetadata* file): BinaryView(BNCreateBinaryDataView(file->GetObject())) { } diff --git a/function.cpp b/function.cpp index ab5f0ea3..1e91f8f3 100644 --- a/function.cpp +++ b/function.cpp @@ -1359,6 +1359,30 @@ vector Function::GetTypeTokens(DisassemblySettings* setting } +bool Function::IsFunctionTooLarge() +{ + return BNIsFunctionTooLarge(m_object); +} + + +bool Function::IsAnalysisSkipped() +{ + return BNIsFunctionAnalysisSkipped(m_object); +} + + +BNFunctionAnalysisSkipOverride Function::GetAnalysisSkipOverride() +{ + return BNGetFunctionAnalysisSkipOverride(m_object); +} + + +void Function::SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip) +{ + BNSetFunctionAnalysisSkipOverride(m_object, skip); +} + + AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(Function* func): m_func(func) { if (m_func) diff --git a/functiongraph.cpp b/functiongraph.cpp index 77754913..a743254e 100644 --- a/functiongraph.cpp +++ b/functiongraph.cpp @@ -131,6 +131,12 @@ vector> FunctionGraph::GetBlocks() } +bool FunctionGraph::HasBlocks() const +{ + return BNFunctionGraphHasBlocks(m_graph); +} + + int FunctionGraph::GetWidth() const { return BNGetFunctionGraphWidth(m_graph); diff --git a/python/binaryview.py b/python/binaryview.py index 7a6bc875..1c986a94 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -65,6 +65,9 @@ class BinaryDataNotification(object): def function_updated(self, view, func): pass + def function_update_requested(self, view, func): + pass + def data_var_added(self, view, var): pass @@ -180,6 +183,7 @@ class BinaryDataNotificationCallbacks(object): self._cb.functionAdded = self._cb.functionAdded.__class__(self._function_added) self._cb.functionRemoved = self._cb.functionRemoved.__class__(self._function_removed) self._cb.functionUpdated = self._cb.functionUpdated.__class__(self._function_updated) + self._cb.functionUpdateRequested = self._cb.functionUpdateRequested.__class__(self._function_update_requested) self._cb.dataVariableAdded = self._cb.dataVariableAdded.__class__(self._data_var_added) self._cb.dataVariableRemoved = self._cb.dataVariableRemoved.__class__(self._data_var_removed) self._cb.dataVariableUpdated = self._cb.dataVariableUpdated.__class__(self._data_var_updated) @@ -230,6 +234,12 @@ class BinaryDataNotificationCallbacks(object): except: log.log_error(traceback.format_exc()) + def _function_update_requested(self, ctxt, view, func): + try: + self.notify.function_update_requested(self.view, function.Function(self.view, core.BNNewFunctionReference(func))) + except: + log.log_error(traceback.format_exc()) + def _data_var_added(self, ctxt, view, var): try: address = var[0].address @@ -1013,6 +1023,15 @@ class BinaryView(object): result = core.BNGetGlobalPointerValue(self.handle) return function.RegisterValue(self.arch, result.value, confidence = result.confidence) + @property + def max_function_size_for_analysis(self): + """Maximum size of function (sum of basic block sizes in bytes) for auto analysis""" + return core.BNGetMaxFunctionSizeForAnalysis(self.handle) + + @max_function_size_for_analysis.setter + def max_function_size_for_analysis(self, size): + core.BNSetMaxFunctionSizeForAnalysis(self.handle, size) + def __len__(self): return int(core.BNGetViewLength(self.handle)) diff --git a/python/function.py b/python/function.py index f68aa76f..0d796d98 100644 --- a/python/function.py +++ b/python/function.py @@ -26,7 +26,8 @@ import ctypes import _binaryninjacore as core from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend, - DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType) + DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType, + FunctionAnalysisSkipOverride) import architecture import platform import highlight @@ -817,6 +818,32 @@ class Function(object): for i in block: yield i + @property + def too_large(self): + """Whether the function is too large to automatically perform analysis (read-only)""" + return core.BNIsFunctionTooLarge(self.handle) + + @property + def analysis_skipped(self): + """Whether automatic analysis was skipped for this function""" + return core.BNIsFunctionAnalysisSkipped(self.handle) + + @analysis_skipped.setter + def analysis_skipped(self, skip): + if skip: + core.BNSetFunctionAnalysisSkipOverride(self.handle, FunctionAnalysisSkipOverride.AlwaysSkipFunctionAnalysis) + else: + core.BNSetFunctionAnalysisSkipOverride(self.handle, FunctionAnalysisSkipOverride.NeverSkipFunctionAnalysis) + + @property + def analysis_skip_override(self): + """Override for skipping of automatic analysis""" + return FunctionAnalysisSkipOverride(core.BNGetFunctionAnalysisSkipOverride(self.handle)) + + @analysis_skip_override.setter + def analysis_skip_override(self, override): + core.BNSetFunctionAnalysisSkipOverride(self.handle, override) + def __iter__(self): count = ctypes.c_ulonglong() blocks = core.BNGetFunctionBasicBlockList(self.handle, count) @@ -1835,6 +1862,11 @@ class FunctionGraph(object): core.BNFreeFunctionGraphBlockList(blocks, count.value) return result + @property + def has_blocks(self): + """Whether the function graph has at least one block (read-only)""" + return core.BNFunctionGraphHasBlocks(self.handle) + @property def width(self): """Function graph width (read-only)""" -- cgit v1.3.1 From 5f07bf18df013860c9d9870a4ad0fba78379b0f1 Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Tue, 20 Mar 2018 09:53:59 -0400 Subject: Cache all created CoreArchitecture objects --- python/architecture.py | 18 +++++++++++++----- python/basicblock.py | 2 +- python/binaryview.py | 6 +++--- python/callingconvention.py | 2 +- python/function.py | 8 ++++---- python/platform.py | 2 +- 6 files changed, 23 insertions(+), 15 deletions(-) (limited to 'python/function.py') diff --git a/python/architecture.py b/python/architecture.py index 781edcfd..c5f87ec6 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -44,7 +44,7 @@ class _ArchitectureMetaClass(type): archs = core.BNGetArchitectureList(count) result = [] for i in xrange(0, count.value): - result.append(CoreArchitecture(archs[i])) + result.append(CoreArchitecture._from_cache(archs[i])) core.BNFreeArchitectureList(archs) return result @@ -54,7 +54,7 @@ class _ArchitectureMetaClass(type): archs = core.BNGetArchitectureList(count) try: for i in xrange(0, count.value): - yield CoreArchitecture(archs[i]) + yield CoreArchitecture._from_cache(archs[i]) finally: core.BNFreeArchitectureList(archs) @@ -63,7 +63,7 @@ class _ArchitectureMetaClass(type): arch = core.BNGetArchitectureByName(name) if arch is None: raise KeyError("'%s' is not a valid architecture" % str(name)) - return CoreArchitecture(arch) + return CoreArchitecture._from_cache(arch) def register(cls): startup._init_plugins() @@ -2037,6 +2037,7 @@ class Architecture(object): core.BNRegisterCallingConvention(self.handle, cc.handle) +_architecture_cache = {} class CoreArchitecture(Architecture): def __init__(self, handle): super(CoreArchitecture, self).__init__() @@ -2256,12 +2257,19 @@ class CoreArchitecture(Architecture): self._intrinsics[name] = intrinsics[i] self._intrinsics_by_index[intrinsics[i]] = (name, self.intrinsics[name]) core.BNFreeRegisterList(intrinsics) + global _architecture_cache + _architecture_cache[ctypes.addressof(handle.contents)] = self + + @classmethod + def _from_cache(cls, handle): + global _architecture_cache + return _architecture_cache.get(ctypes.addressof(handle.contents)) or cls(handle) def get_associated_arch_by_address(self, addr): new_addr = ctypes.c_ulonglong() new_addr.value = addr result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr) - return CoreArchitecture(handle = result), new_addr.value + return CoreArchitecture._from_cache(handle = result), new_addr.value def get_instruction_info(self, data, addr): """ @@ -2289,7 +2297,7 @@ class CoreArchitecture(Architecture): for i in xrange(0, info.branchCount): target = info.branchTarget[i] if info.branchArch[i]: - arch = CoreArchitecture(info.branchArch[i]) + arch = CoreArchitecture._from_cache(info.branchArch[i]) else: arch = None result.add_branch(BranchType(info.branchType[i]), target, arch) diff --git a/python/basicblock.py b/python/basicblock.py index c93d0b2c..1d932c5e 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -100,7 +100,7 @@ class BasicBlock(object): arch = core.BNGetBasicBlockArchitecture(self.handle) if arch is None: return None - self._arch = architecture.CoreArchitecture(arch) + self._arch = architecture.CoreArchitecture._from_cache(arch) return self._arch @property diff --git a/python/binaryview.py b/python/binaryview.py index 3af0ee50..0cf25e70 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -411,7 +411,7 @@ class BinaryViewType(object): arch = core.BNGetArchitectureForViewType(self.handle, ident, endian) if arch is None: return None - return architecture.CoreArchitecture(arch) + return architecture.CoreArchitecture._from_cache(arch) def register_platform(self, ident, arch, plat): core.BNRegisterPlatformForViewType(self.handle, ident, arch.handle, plat.handle) @@ -823,7 +823,7 @@ class BinaryView(object): arch = core.BNGetDefaultArchitecture(self.handle) if arch is None: return None - return architecture.CoreArchitecture(handle=arch) + return architecture.CoreArchitecture._from_cache(handle=arch) @arch.setter def arch(self, value): @@ -2211,7 +2211,7 @@ class BinaryView(object): else: func = None if refs[i].arch: - arch = architecture.CoreArchitecture(refs[i].arch) + arch = architecture.CoreArchitecture._from_cache(refs[i].arch) else: arch = None addr = refs[i].addr diff --git a/python/callingconvention.py b/python/callingconvention.py index 49ef7666..e3ec7261 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -75,7 +75,7 @@ class CallingConvention(object): self.__class__._registered_calling_conventions.append(self) else: self.handle = handle - self.arch = architecture.CoreArchitecture(core.BNGetCallingConventionArchitecture(self.handle)) + self.arch = architecture.CoreArchitecture._from_cache(core.BNGetCallingConventionArchitecture(self.handle)) self.__dict__["name"] = core.BNGetCallingConventionName(self.handle) self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(self.handle) self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(self.handle) diff --git a/python/function.py b/python/function.py index 0d796d98..8c4b7765 100644 --- a/python/function.py +++ b/python/function.py @@ -420,7 +420,7 @@ class Function(object): arch = core.BNGetFunctionArchitecture(self.handle) if arch is None: return None - self._arch = architecture.CoreArchitecture(arch) + self._arch = architecture.CoreArchitecture._from_cache(arch) return self._arch @property @@ -558,7 +558,7 @@ class Function(object): branches = core.BNGetIndirectBranches(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.CoreArchitecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -1142,7 +1142,7 @@ class Function(object): branches = core.BNGetIndirectBranchesAt(self.handle, arch.handle, addr, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.CoreArchitecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -1660,7 +1660,7 @@ class FunctionGraphBlock(object): arch = core.BNGetFunctionGraphBlockArchitecture(self.handle) if arch is None: return None - return architecture.CoreArchitecture(arch) + return architecture.CoreArchitecture._from_cache(arch) @property def start(self): diff --git a/python/platform.py b/python/platform.py index 09670bac..a79e3b9a 100644 --- a/python/platform.py +++ b/python/platform.py @@ -105,7 +105,7 @@ class Platform(object): else: self.handle = handle self.__dict__["name"] = core.BNGetPlatformName(self.handle) - self.arch = architecture.CoreArchitecture(core.BNGetPlatformArchitecture(self.handle)) + self.arch = architecture.CoreArchitecture._from_cache(core.BNGetPlatformArchitecture(self.handle)) def __del__(self): core.BNFreePlatform(self.handle) -- cgit v1.3.1 From 5e56265478e39ec4a1e7bad40c4f8728c5a46214 Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Fri, 23 Mar 2018 14:23:09 -0400 Subject: Make indirect branch queries initialize CoreArchitecture objects correctly --- python/function.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'python/function.py') diff --git a/python/function.py b/python/function.py index 8c4b7765..1cc4dcac 100644 --- a/python/function.py +++ b/python/function.py @@ -558,7 +558,7 @@ class Function(object): branches = core.BNGetIndirectBranches(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.CoreArchitecture._from_cache(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -1142,7 +1142,7 @@ class Function(object): branches = core.BNGetIndirectBranchesAt(self.handle, arch.handle, addr, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.CoreArchitecture._from_cache(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result -- cgit v1.3.1 From fa716fe2da53a4f136380b1f60197bd197b2793a Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 2 Apr 2018 23:30:56 -0400 Subject: Add plugin commands for LLIL and MLIL --- basicblock.cpp | 37 +++++++++ binaryninjaapi.h | 101 ++++++++++++++++++++--- binaryninjacore.h | 69 ++++++++++++---- binaryview.cpp | 2 + function.cpp | 1 + functiongraph.cpp | 36 ++++++++ functiongraphblock.cpp | 1 + plugin.cpp | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ python/basicblock.py | 21 ++++- python/function.py | 71 +++++++++++++--- python/plugin.py | 219 +++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 736 insertions(+), 40 deletions(-) (limited to 'python/function.py') diff --git a/basicblock.cpp b/basicblock.cpp index d42a1038..33f57d40 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -276,6 +276,7 @@ vector BasicBlock::GetDisassemblyText(DisassemblySettings* { DisassemblyTextLine line; line.addr = lines[i].addr; + line.instrIndex = lines[i].instrIndex; line.tokens.reserve(lines[i].count); for (size_t j = 0; j < lines[i].count; j++) { @@ -417,3 +418,39 @@ bool BasicBlock::IsBackEdge(BasicBlock* source, BasicBlock* target) } return false; } + + +bool BasicBlock::IsILBlock() const +{ + return BNIsILBasicBlock(m_object); +} + + +bool BasicBlock::IsLowLevelILBlock() const +{ + return BNIsLowLevelILBasicBlock(m_object); +} + + +bool BasicBlock::IsMediumLevelILBlock() const +{ + return BNIsMediumLevelILBasicBlock(m_object); +} + + +Ref BasicBlock::GetLowLevelILFunction() const +{ + BNLowLevelILFunction* func = BNGetBasicBlockLowLevelILFunction(m_object); + if (!func) + return nullptr; + return new LowLevelILFunction(func); +} + + +Ref BasicBlock::GetMediumLevelILFunction() const +{ + BNMediumLevelILFunction* func = BNGetBasicBlockMediumLevelILFunction(m_object); + if (!func) + return nullptr; + return new MediumLevelILFunction(func); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index d0c19e7a..81b5105d 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -986,6 +986,7 @@ namespace BinaryNinja struct DisassemblyTextLine { uint64_t addr; + size_t instrIndex; std::vector tokens; }; @@ -1590,6 +1591,7 @@ namespace BinaryNinja }; class LowLevelILFunction; + class MediumLevelILFunction; class FunctionRecognizer; class CallingConvention; @@ -2254,6 +2256,12 @@ namespace BinaryNinja void SetUserBasicBlockHighlight(uint8_t r, uint8_t g, uint8_t b, uint8_t alpha = 255); static bool IsBackEdge(BasicBlock* source, BasicBlock* target); + + bool IsILBlock() const; + bool IsLowLevelILBlock() const; + bool IsMediumLevelILBlock() const; + Ref GetLowLevelILFunction() const; + Ref GetMediumLevelILFunction() const; }; struct VariableNameAndType @@ -2570,6 +2578,12 @@ namespace BinaryNinja bool IsOptionSet(BNDisassemblyOption option) const; void SetOption(BNDisassemblyOption option, bool state = true); + + bool IsILGraph() const; + bool IsLowLevelILGraph() const; + bool IsMediumLevelILGraph() const; + Ref GetLowLevelILFunction() const; + Ref GetMediumLevelILFunction() const; }; struct LowLevelILLabel: public BNLowLevelILLabel @@ -3312,7 +3326,10 @@ namespace BinaryNinja { Ref view; uint64_t address, length; + size_t instrIndex; Ref function; + Ref lowLevelILFunction; + Ref mediumLevelILFunction; PluginCommandContext(); }; @@ -3345,15 +3362,55 @@ namespace BinaryNinja std::function isValid; }; + struct RegisteredLowLevelILFunctionCommand + { + std::function action; + std::function isValid; + }; + + struct RegisteredLowLevelILInstructionCommand + { + std::function action; + std::function isValid; + }; + + struct RegisteredMediumLevelILFunctionCommand + { + std::function action; + std::function isValid; + }; + + struct RegisteredMediumLevelILInstructionCommand + { + std::function action; + std::function isValid; + }; + static void DefaultPluginCommandActionCallback(void* ctxt, BNBinaryView* view); static void AddressPluginCommandActionCallback(void* ctxt, BNBinaryView* view, uint64_t addr); static void RangePluginCommandActionCallback(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len); static void FunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, BNFunction* func); + static void LowLevelILFunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func); + static void LowLevelILInstructionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr); + static void MediumLevelILFunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func); + static void MediumLevelILInstructionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr); static bool DefaultPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view); static bool AddressPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, uint64_t addr); static bool RangePluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len); static bool FunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, BNFunction* func); + static bool LowLevelILFunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func); + static bool LowLevelILInstructionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr); + static bool MediumLevelILFunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func); + static bool MediumLevelILInstructionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr); public: PluginCommand(const BNPluginCommand& cmd); @@ -3363,25 +3420,45 @@ namespace BinaryNinja PluginCommand& operator=(const PluginCommand& cmd); static void Register(const std::string& name, const std::string& description, - const std::function& action); + const std::function& action); static void Register(const std::string& name, const std::string& description, - const std::function& action, - const std::function& isValid); + const std::function& action, + const std::function& isValid); static void RegisterForAddress(const std::string& name, const std::string& description, - const std::function& action); + const std::function& action); static void RegisterForAddress(const std::string& name, const std::string& description, - const std::function& action, - const std::function& isValid); + const std::function& action, + const std::function& isValid); static void RegisterForRange(const std::string& name, const std::string& description, - const std::function& action); + const std::function& action); static void RegisterForRange(const std::string& name, const std::string& description, - const std::function& action, - const std::function& isValid); + const std::function& action, + const std::function& isValid); static void RegisterForFunction(const std::string& name, const std::string& description, - const std::function& action); + const std::function& action); static void RegisterForFunction(const std::string& name, const std::string& description, - const std::function& action, - const std::function& isValid); + const std::function& action, + const std::function& isValid); + static void RegisterForLowLevelILFunction(const std::string& name, const std::string& description, + const std::function& action); + static void RegisterForLowLevelILFunction(const std::string& name, const std::string& description, + const std::function& action, + const std::function& isValid); + static void RegisterForLowLevelILInstruction(const std::string& name, const std::string& description, + const std::function& action); + static void RegisterForLowLevelILInstruction(const std::string& name, const std::string& description, + const std::function& action, + const std::function& isValid); + static void RegisterForMediumLevelILFunction(const std::string& name, const std::string& description, + const std::function& action); + static void RegisterForMediumLevelILFunction(const std::string& name, const std::string& description, + const std::function& action, + const std::function& isValid); + static void RegisterForMediumLevelILInstruction(const std::string& name, const std::string& description, + const std::function& action); + static void RegisterForMediumLevelILInstruction(const std::string& name, const std::string& description, + const std::function& action, + const std::function& isValid); static std::vector GetList(); static std::vector GetValidList(const PluginCommandContext& ctxt); diff --git a/binaryninjacore.h b/binaryninjacore.h index cb4b9eb9..69c5e61b 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1205,6 +1205,7 @@ extern "C" struct BNDisassemblyTextLine { uint64_t addr; + size_t instrIndex; BNInstructionTextToken* tokens; size_t count; }; @@ -1365,7 +1366,11 @@ extern "C" DefaultPluginCommand, AddressPluginCommand, RangePluginCommand, - FunctionPluginCommand + FunctionPluginCommand, + LowLevelILFunctionPluginCommand, + LowLevelILInstructionPluginCommand, + MediumLevelILFunctionPluginCommand, + MediumLevelILInstructionPluginCommand }; struct BNPluginCommand @@ -1379,11 +1384,19 @@ extern "C" void (*addressCommand)(void* ctxt, BNBinaryView* view, uint64_t addr); void (*rangeCommand)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len); void (*functionCommand)(void* ctxt, BNBinaryView* view, BNFunction* func); + void (*lowLevelILFunctionCommand)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func); + void (*lowLevelILInstructionCommand)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr); + void (*mediumLevelILFunctionCommand)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func); + void (*mediumLevelILInstructionCommand)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr); bool (*defaultIsValid)(void* ctxt, BNBinaryView* view); bool (*addressIsValid)(void* ctxt, BNBinaryView* view, uint64_t addr); bool (*rangeIsValid)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len); bool (*functionIsValid)(void* ctxt, BNBinaryView* view, BNFunction* func); + bool (*lowLevelILFunctionIsValid)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func); + bool (*lowLevelILInstructionIsValid)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr); + bool (*mediumLevelILFunctionIsValid)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func); + bool (*mediumLevelILInstructionIsValid)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr); }; struct BNCustomCallingConvention @@ -2347,6 +2360,11 @@ extern "C" BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlockDominanceFrontier(BNBasicBlock* block, size_t* count); BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlockIteratedDominanceFrontier(BNBasicBlock** blocks, size_t incomingCount, size_t* outputCount); + BINARYNINJACOREAPI bool BNIsILBasicBlock(BNBasicBlock* block); + BINARYNINJACOREAPI bool BNIsLowLevelILBasicBlock(BNBasicBlock* block); + BINARYNINJACOREAPI bool BNIsMediumLevelILBasicBlock(BNBasicBlock* block); + BINARYNINJACOREAPI BNLowLevelILFunction* BNGetBasicBlockLowLevelILFunction(BNBasicBlock* block); + BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetBasicBlockMediumLevelILFunction(BNBasicBlock* block); BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetBasicBlockDisassemblyText(BNBasicBlock* block, BNDisassemblySettings* settings, size_t* count); @@ -2547,6 +2565,11 @@ extern "C" BINARYNINJACOREAPI void BNSetFunctionGraphCompleteCallback(BNFunctionGraph* graph, void* ctxt, void (*func)(void* ctxt)); BINARYNINJACOREAPI void BNAbortFunctionGraph(BNFunctionGraph* graph); BINARYNINJACOREAPI BNFunctionGraphType BNGetFunctionGraphType(BNFunctionGraph* graph); + BINARYNINJACOREAPI bool BNIsILFunctionGraph(BNFunctionGraph* graph); + BINARYNINJACOREAPI bool BNIsLowLevelILFunctionGraph(BNFunctionGraph* graph); + BINARYNINJACOREAPI bool BNIsMediumLevelILFunctionGraph(BNFunctionGraph* graph); + BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFunctionGraphLowLevelILFunction(BNFunctionGraph* graph); + BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetFunctionGraphMediumLevelILFunction(BNFunctionGraph* graph); BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocks(BNFunctionGraph* graph, size_t* count); BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocksInRegion( @@ -3017,29 +3040,45 @@ extern "C" // Plugin commands BINARYNINJACOREAPI void BNRegisterPluginCommand(const char* name, const char* description, - void (*action)(void* ctxt, BNBinaryView* view), - bool (*isValid)(void* ctxt, BNBinaryView* view), void* context); + void (*action)(void* ctxt, BNBinaryView* view), bool (*isValid)(void* ctxt, BNBinaryView* view), void* context); BINARYNINJACOREAPI void BNRegisterPluginCommandForAddress(const char* name, const char* description, - void (*action)(void* ctxt, BNBinaryView* view, uint64_t addr), - bool (*isValid)(void* ctxt, BNBinaryView* view, uint64_t addr), - void* context); + void (*action)(void* ctxt, BNBinaryView* view, uint64_t addr), + bool (*isValid)(void* ctxt, BNBinaryView* view, uint64_t addr), void* context); BINARYNINJACOREAPI void BNRegisterPluginCommandForRange(const char* name, const char* description, - void (*action)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len), - bool (*isValid)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len), - void* context); + void (*action)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len), + bool (*isValid)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len), void* context); BINARYNINJACOREAPI void BNRegisterPluginCommandForFunction(const char* name, const char* description, - void (*action)(void* ctxt, BNBinaryView* view, BNFunction* func), - bool (*isValid)(void* ctxt, BNBinaryView* view, BNFunction* func), - void* context); + void (*action)(void* ctxt, BNBinaryView* view, BNFunction* func), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNFunction* func), void* context); + BINARYNINJACOREAPI void BNRegisterPluginCommandForLowLevelILFunction(const char* name, const char* description, + void (*action)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func), void* context); + BINARYNINJACOREAPI void BNRegisterPluginCommandForLowLevelILInstruction(const char* name, const char* description, + void (*action)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr), void* context); + BINARYNINJACOREAPI void BNRegisterPluginCommandForMediumLevelILFunction(const char* name, const char* description, + void (*action)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func), void* context); + BINARYNINJACOREAPI void BNRegisterPluginCommandForMediumLevelILInstruction(const char* name, const char* description, + void (*action)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr), void* context); BINARYNINJACOREAPI BNPluginCommand* BNGetAllPluginCommands(size_t* count); BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommands(BNBinaryView* view, size_t* count); BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForAddress(BNBinaryView* view, uint64_t addr, - size_t* count); + size_t* count); BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForRange(BNBinaryView* view, uint64_t addr, - uint64_t len, size_t* count); + uint64_t len, size_t* count); BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForFunction(BNBinaryView* view, BNFunction* func, - size_t* count); + size_t* count); + BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForLowLevelILFunction(BNBinaryView* view, + BNLowLevelILFunction* func, size_t* count); + BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForLowLevelILInstruction(BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr, size_t* count); + BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForMediumLevelILFunction(BNBinaryView* view, + BNMediumLevelILFunction* func, size_t* count); + BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForMediumLevelILInstruction(BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr, size_t* count); BINARYNINJACOREAPI void BNFreePluginCommandList(BNPluginCommand* commands); // Calling conventions diff --git a/binaryview.cpp b/binaryview.cpp index 8dcae40f..0a9a7118 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1459,6 +1459,7 @@ vector BinaryView::GetPreviousLinearDisassemblyLines(Line line.block = lines[i].block ? new BasicBlock(BNNewBasicBlockReference(lines[i].block)) : nullptr; line.lineOffset = lines[i].lineOffset; line.contents.addr = lines[i].contents.addr; + line.contents.instrIndex = lines[i].contents.instrIndex; line.contents.tokens.reserve(lines[i].contents.count); for (size_t j = 0; j < lines[i].contents.count; j++) { @@ -1507,6 +1508,7 @@ vector BinaryView::GetNextLinearDisassemblyLines(LinearDi line.block = lines[i].block ? new BasicBlock(BNNewBasicBlockReference(lines[i].block)) : nullptr; line.lineOffset = lines[i].lineOffset; line.contents.addr = lines[i].contents.addr; + line.contents.instrIndex = lines[i].contents.instrIndex; line.contents.tokens.reserve(lines[i].contents.count); for (size_t j = 0; j < lines[i].contents.count; j++) { diff --git a/function.cpp b/function.cpp index 1e91f8f3..835ab144 100644 --- a/function.cpp +++ b/function.cpp @@ -1337,6 +1337,7 @@ vector Function::GetTypeTokens(DisassemblySettings* setting { DisassemblyTextLine line; line.addr = lines[i].addr; + line.instrIndex = lines[i].instrIndex; line.tokens.reserve(lines[i].count); for (size_t j = 0; j < lines[i].count; j++) { diff --git a/functiongraph.cpp b/functiongraph.cpp index a743254e..9948d70e 100644 --- a/functiongraph.cpp +++ b/functiongraph.cpp @@ -186,3 +186,39 @@ void FunctionGraph::SetOption(BNDisassemblyOption option, bool state) { BNSetFunctionGraphOption(m_graph, option, state); } + + +bool FunctionGraph::IsILGraph() const +{ + return BNIsILFunctionGraph(m_graph); +} + + +bool FunctionGraph::IsLowLevelILGraph() const +{ + return BNIsLowLevelILFunctionGraph(m_graph); +} + + +bool FunctionGraph::IsMediumLevelILGraph() const +{ + return BNIsMediumLevelILFunctionGraph(m_graph); +} + + +Ref FunctionGraph::GetLowLevelILFunction() const +{ + BNLowLevelILFunction* func = BNGetFunctionGraphLowLevelILFunction(m_graph); + if (!func) + return nullptr; + return new LowLevelILFunction(func); +} + + +Ref FunctionGraph::GetMediumLevelILFunction() const +{ + BNMediumLevelILFunction* func = BNGetFunctionGraphMediumLevelILFunction(m_graph); + if (!func) + return nullptr; + return new MediumLevelILFunction(func); +} diff --git a/functiongraphblock.cpp b/functiongraphblock.cpp index 06a35eee..469fb175 100644 --- a/functiongraphblock.cpp +++ b/functiongraphblock.cpp @@ -94,6 +94,7 @@ const vector& FunctionGraphBlock::GetLines() { DisassemblyTextLine line; line.addr = lines[i].addr; + line.instrIndex = lines[i].instrIndex; line.tokens.reserve(lines[i].count); for (size_t j = 0; j < lines[i].count; j++) { diff --git a/plugin.cpp b/plugin.cpp index 972ce28b..22befd65 100644 --- a/plugin.cpp +++ b/plugin.cpp @@ -19,6 +19,8 @@ // IN THE SOFTWARE. #include "binaryninjaapi.h" +#include "lowlevelilinstruction.h" +#include "mediumlevelilinstruction.h" using namespace BinaryNinja; using namespace std; @@ -27,6 +29,7 @@ using namespace std; PluginCommandContext::PluginCommandContext() { address = length = 0; + instrIndex = BN_INVALID_EXPR; } @@ -97,6 +100,48 @@ void PluginCommand::FunctionPluginCommandActionCallback(void* ctxt, BNBinaryView } +void PluginCommand::LowLevelILFunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func) +{ + RegisteredLowLevelILFunctionCommand* cmd = (RegisteredLowLevelILFunctionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func)); + cmd->action(viewObject, funcObject); +} + + +void PluginCommand::LowLevelILInstructionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr) +{ + RegisteredLowLevelILInstructionCommand* cmd = (RegisteredLowLevelILInstructionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func)); + LowLevelILInstruction instrObject = funcObject->GetInstruction(instr); + cmd->action(viewObject, instrObject); +} + + +void PluginCommand::MediumLevelILFunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func) +{ + RegisteredMediumLevelILFunctionCommand* cmd = (RegisteredMediumLevelILFunctionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func)); + cmd->action(viewObject, funcObject); +} + + +void PluginCommand::MediumLevelILInstructionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr) +{ + RegisteredMediumLevelILInstructionCommand* cmd = (RegisteredMediumLevelILInstructionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func)); + MediumLevelILInstruction instrObject = funcObject->GetInstruction(instr); + cmd->action(viewObject, instrObject); +} + + bool PluginCommand::DefaultPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view) { RegisteredDefaultCommand* cmd = (RegisteredDefaultCommand*)ctxt; @@ -130,6 +175,48 @@ bool PluginCommand::FunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryVie } +bool PluginCommand::LowLevelILFunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func) +{ + RegisteredLowLevelILFunctionCommand* cmd = (RegisteredLowLevelILFunctionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func)); + return cmd->isValid(viewObject, funcObject); +} + + +bool PluginCommand::LowLevelILInstructionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr) +{ + RegisteredLowLevelILInstructionCommand* cmd = (RegisteredLowLevelILInstructionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func)); + LowLevelILInstruction instrObject = funcObject->GetInstruction(instr); + return cmd->isValid(viewObject, instrObject); +} + + +bool PluginCommand::MediumLevelILFunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func) +{ + RegisteredMediumLevelILFunctionCommand* cmd = (RegisteredMediumLevelILFunctionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func)); + return cmd->isValid(viewObject, funcObject); +} + + +bool PluginCommand::MediumLevelILInstructionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr) +{ + RegisteredMediumLevelILInstructionCommand* cmd = (RegisteredMediumLevelILInstructionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func)); + MediumLevelILInstruction instrObject = funcObject->GetInstruction(instr); + return cmd->isValid(viewObject, instrObject); +} + + void PluginCommand::Register(const string& name, const string& description, const function& action) { @@ -206,6 +293,89 @@ void PluginCommand::RegisterForFunction(const string& name, const string& descri } +void PluginCommand::RegisterForLowLevelILFunction(const string& name, const string& description, + const function& action) +{ + RegisterForLowLevelILFunction(name, description, action, [](BinaryView*, LowLevelILFunction*) { return true; }); +} + + +void PluginCommand::RegisterForLowLevelILFunction(const string& name, const string& description, + const function& action, + const function& isValid) +{ + RegisteredLowLevelILFunctionCommand* cmd = new RegisteredLowLevelILFunctionCommand; + cmd->action = action; + cmd->isValid = isValid; + BNRegisterPluginCommandForLowLevelILFunction(name.c_str(), description.c_str(), + LowLevelILFunctionPluginCommandActionCallback, + LowLevelILFunctionPluginCommandIsValidCallback, cmd); +} + + +void PluginCommand::RegisterForLowLevelILInstruction(const string& name, const string& description, + const function& action) +{ + RegisterForLowLevelILInstruction(name, description, action, + [](BinaryView*, const LowLevelILInstruction&) { return true; }); +} + + +void PluginCommand::RegisterForLowLevelILInstruction(const string& name, const string& description, + const function& action, + const function& isValid) +{ + RegisteredLowLevelILInstructionCommand* cmd = new RegisteredLowLevelILInstructionCommand; + cmd->action = action; + cmd->isValid = isValid; + BNRegisterPluginCommandForLowLevelILInstruction(name.c_str(), description.c_str(), + LowLevelILInstructionPluginCommandActionCallback, + LowLevelILInstructionPluginCommandIsValidCallback, cmd); +} + + +void PluginCommand::RegisterForMediumLevelILFunction(const string& name, const string& description, + const function& action) +{ + RegisterForMediumLevelILFunction(name, description, action, + [](BinaryView*, MediumLevelILFunction*) { return true; }); +} + + +void PluginCommand::RegisterForMediumLevelILFunction(const string& name, const string& description, + const function& action, + const function& isValid) +{ + RegisteredMediumLevelILFunctionCommand* cmd = new RegisteredMediumLevelILFunctionCommand; + cmd->action = action; + cmd->isValid = isValid; + BNRegisterPluginCommandForMediumLevelILFunction(name.c_str(), description.c_str(), + MediumLevelILFunctionPluginCommandActionCallback, + MediumLevelILFunctionPluginCommandIsValidCallback, cmd); +} + + +void PluginCommand::RegisterForMediumLevelILInstruction(const string& name, const string& description, + const function& action) +{ + RegisterForMediumLevelILInstruction(name, description, action, + [](BinaryView*, const MediumLevelILInstruction&) { return true; }); +} + + +void PluginCommand::RegisterForMediumLevelILInstruction(const string& name, const string& description, + const function& action, + const function& isValid) +{ + RegisteredMediumLevelILInstructionCommand* cmd = new RegisteredMediumLevelILInstructionCommand; + cmd->action = action; + cmd->isValid = isValid; + BNRegisterPluginCommandForMediumLevelILInstruction(name.c_str(), description.c_str(), + MediumLevelILInstructionPluginCommandActionCallback, + MediumLevelILInstructionPluginCommandIsValidCallback, cmd); +} + + vector PluginCommand::GetList() { vector result; @@ -259,6 +429,38 @@ bool PluginCommand::IsValid(const PluginCommandContext& ctxt) const if (!m_command.functionIsValid) return true; return m_command.functionIsValid(m_command.context, ctxt.view->GetObject(), ctxt.function->GetObject()); + case LowLevelILFunctionPluginCommand: + if (!ctxt.lowLevelILFunction) + return false; + if (!m_command.lowLevelILFunctionIsValid) + return true; + return m_command.lowLevelILFunctionIsValid(m_command.context, ctxt.view->GetObject(), + ctxt.lowLevelILFunction->GetObject()); + case LowLevelILInstructionPluginCommand: + if (!ctxt.lowLevelILFunction) + return false; + if (ctxt.instrIndex == BN_INVALID_EXPR) + return false; + if (!m_command.lowLevelILInstructionIsValid) + return true; + return m_command.lowLevelILInstructionIsValid(m_command.context, ctxt.view->GetObject(), + ctxt.lowLevelILFunction->GetObject(), ctxt.instrIndex); + case MediumLevelILFunctionPluginCommand: + if (!ctxt.mediumLevelILFunction) + return false; + if (!m_command.mediumLevelILFunctionIsValid) + return true; + return m_command.mediumLevelILFunctionIsValid(m_command.context, ctxt.view->GetObject(), + ctxt.mediumLevelILFunction->GetObject()); + case MediumLevelILInstructionPluginCommand: + if (!ctxt.mediumLevelILFunction) + return false; + if (ctxt.instrIndex == BN_INVALID_EXPR) + return false; + if (!m_command.mediumLevelILInstructionIsValid) + return true; + return m_command.mediumLevelILInstructionIsValid(m_command.context, ctxt.view->GetObject(), + ctxt.mediumLevelILFunction->GetObject(), ctxt.instrIndex); default: return false; } @@ -284,6 +486,22 @@ void PluginCommand::Execute(const PluginCommandContext& ctxt) const case FunctionPluginCommand: m_command.functionCommand(m_command.context, ctxt.view->GetObject(), ctxt.function->GetObject()); break; + case LowLevelILFunctionPluginCommand: + m_command.lowLevelILFunctionCommand(m_command.context, ctxt.view->GetObject(), + ctxt.lowLevelILFunction->GetObject()); + break; + case LowLevelILInstructionPluginCommand: + m_command.lowLevelILInstructionCommand(m_command.context, ctxt.view->GetObject(), + ctxt.lowLevelILFunction->GetObject(), ctxt.instrIndex); + break; + case MediumLevelILFunctionPluginCommand: + m_command.mediumLevelILFunctionCommand(m_command.context, ctxt.view->GetObject(), + ctxt.mediumLevelILFunction->GetObject()); + break; + case MediumLevelILInstructionPluginCommand: + m_command.mediumLevelILInstructionCommand(m_command.context, ctxt.view->GetObject(), + ctxt.mediumLevelILFunction->GetObject(), ctxt.instrIndex); + break; default: break; } diff --git a/python/basicblock.py b/python/basicblock.py index 1d932c5e..4dc783c3 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -256,6 +256,21 @@ class BasicBlock(object): def highlight(self, value): self.set_user_highlight(value) + @property + def is_il(self): + """Whether the basic block contains IL""" + return core.BNIsILBasicBlock(self.handle) + + @property + def is_low_level_il(self): + """Whether the basic block contains Low Level IL""" + return core.BNIsLowLevelILBasicBlock(self.handle) + + @property + def is_medium_level_il(self): + """Whether the basic block contains Medium Level IL""" + return core.BNIsMediumLevelILBasicBlock(self.handle) + @classmethod def get_iterated_dominance_frontier(self, blocks): if len(blocks) == 0: @@ -322,6 +337,10 @@ class BasicBlock(object): result = [] for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(self, 'il_function'): + il_instr = self.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -333,7 +352,7 @@ class BasicBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(function.DisassemblyTextLine(addr, tokens)) + result.append(function.DisassemblyTextLine(addr, tokens, il_instr)) core.BNFreeDisassemblyTextLines(lines, count.value) return result diff --git a/python/function.py b/python/function.py index 1cc4dcac..6db44e6d 100644 --- a/python/function.py +++ b/python/function.py @@ -1598,9 +1598,10 @@ class AdvancedFunctionAnalysisDataRequestor(object): class DisassemblyTextLine(object): - def __init__(self, addr, tokens): + def __init__(self, addr, tokens, il_instr = None): self.address = addr self.tokens = tokens + self.il_instruction = il_instr def __str__(self): result = "" @@ -1625,8 +1626,9 @@ class FunctionGraphEdge(object): class FunctionGraphBlock(object): - def __init__(self, handle): + def __init__(self, handle, graph): self.handle = handle + self.graph = graph def __del__(self): core.BNFreeFunctionGraphBlock(self.handle) @@ -1645,13 +1647,22 @@ class FunctionGraphBlock(object): def basic_block(self): """Basic block associated with this part of the function graph (read-only)""" block = core.BNGetFunctionGraphBasicBlock(self.handle) - func = core.BNGetBasicBlockFunction(block) - if func is None: + func_handle = core.BNGetBasicBlockFunction(block) + if func_handle is None: core.BNFreeBasicBlock(block) - block = None + return None + + view = binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle)) + func = Function(view, func_handle) + + if core.BNIsLowLevelILBasicBlock(block): + block = lowlevelil.LowLevelILBasicBlock(view, block, + lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func)) + elif core.BNIsMediumLevelILBasicBlock(block): + block = mediumlevelil.MediumLevelILBasicBlock(view, block, + mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func)) else: - block = basicblock.BasicBlock(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), block) - core.BNFreeFunction(func) + block = basicblock.BasicBlock(view, block) return block @property @@ -1697,9 +1708,14 @@ class FunctionGraphBlock(object): """Function graph block list of lines (read-only)""" count = ctypes.c_ulonglong() lines = core.BNGetFunctionGraphBlockLines(self.handle, count) + block = self.basic_block result = [] for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'): + il_instr = block.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -1711,7 +1727,7 @@ class FunctionGraphBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(DisassemblyTextLine(addr, tokens)) + result.append(DisassemblyTextLine(addr, tokens, il_instr)) core.BNFreeDisassemblyTextLines(lines, count.value) return result @@ -1756,9 +1772,14 @@ class FunctionGraphBlock(object): def __iter__(self): count = ctypes.c_ulonglong() lines = core.BNGetFunctionGraphBlockLines(self.handle, count) + block = self.basic_block try: for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'): + il_instr = block.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -1770,7 +1791,7 @@ class FunctionGraphBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - yield DisassemblyTextLine(addr, tokens) + yield DisassemblyTextLine(addr, tokens, il_instr) finally: core.BNFreeDisassemblyTextLines(lines, count.value) @@ -1858,7 +1879,7 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocks(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]))) + result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)) core.BNFreeFunctionGraphBlockList(blocks, count.value) return result @@ -1897,6 +1918,32 @@ class FunctionGraph(object): def settings(self): return DisassemblySettings(core.BNGetFunctionGraphSettings(self.handle)) + @property + def is_il(self): + return core.BNIsILFunctionGraph(self.handle) + + @property + def is_low_level_il(self): + return core.BNIsLowLevelILFunctionGraph(self.handle) + + @property + def is_medium_level_il(self): + return core.BNIsMediumLevelILFunctionGraph(self.handle) + + @property + def il_function(self): + if self.is_low_level_il: + il_func = core.BNGetFunctionGraphLowLevelILFunction(self.handle) + if not il_func: + return None + return lowlevelil.LowLevelILFunction(self.function.arch, il_func, self.function) + if self.is_medium_level_il: + il_func = core.BNGetFunctionGraphMediumLevelILFunction(self.handle) + if not il_func: + return None + return mediumlevelil.MediumLevelILFunction(self.function.arch, il_func, self.function) + return None + def __setattr__(self, name, value): try: object.__setattr__(self, name, value) @@ -1911,7 +1958,7 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocks(self.handle, count) try: for i in xrange(0, count.value): - yield FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i])) + yield FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self) finally: core.BNFreeFunctionGraphBlockList(blocks, count.value) @@ -1954,7 +2001,7 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocksInRegion(self.handle, left, top, right, bottom, count) result = [] for i in xrange(0, count.value): - result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]))) + result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)) core.BNFreeFunctionGraphBlockList(blocks, count.value) return result diff --git a/python/plugin.py b/python/plugin.py index e0054d86..c6cd9fc0 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -30,6 +30,8 @@ import filemetadata import binaryview import function import log +import lowlevelil +import mediumlevelil class PluginCommandContext(object): @@ -38,6 +40,7 @@ class PluginCommandContext(object): self.address = 0 self.length = 0 self.function = None + self.instruction = None class _PluginCommandMetaClass(type): @@ -117,6 +120,50 @@ class PluginCommand(object): except: log.log_error(traceback.format_exc()) + @classmethod + def _low_level_il_function_action(cls, view, func, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + action(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _low_level_il_instruction_action(cls, view, func, instr, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + action(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _medium_level_il_function_action(cls, view, func, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + action(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _medium_level_il_instruction_action(cls, view, func, instr, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + action(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + @classmethod def _default_is_valid(cls, view, is_valid): try: @@ -166,6 +213,62 @@ class PluginCommand(object): log.log_error(traceback.format_exc()) return False + @classmethod + def _low_level_il_function_is_valid(cls, view, func, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _low_level_il_instruction_is_valid(cls, view, func, instr, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _medium_level_il_function_is_valid(cls, view, func, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _medium_level_il_instruction_is_valid(cls, view, func, instr, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + return False + @classmethod def register(cls, name, description, action, is_valid = None): """ @@ -242,6 +345,82 @@ class PluginCommand(object): cls._registered_commands.append((action_obj, is_valid_obj)) core.BNRegisterPluginCommandForFunction(name, description, action_obj, is_valid_obj, None) + @classmethod + def register_for_low_level_il_function(cls, name, description, action, is_valid = None): + """ + ``register_for_low_level_il_function`` Register a plugin to be called with a low level IL function argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``LowLevelILFunction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_low_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_action(view, func, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_is_valid(view, func, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForLowLevelILFunction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_low_level_il_instruction(cls, name, description, action, is_valid = None): + """ + ``register_for_low_level_il_instruction`` Register a plugin to be called with a low level IL instruction argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``LowLevelILInstruction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_low_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_action(view, func, instr, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_is_valid(view, func, instr, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForLowLevelILInstruction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_medium_level_il_function(cls, name, description, action, is_valid = None): + """ + ``register_for_medium_level_il_function`` Register a plugin to be called with a medium level IL function argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``MediumLevelILFunction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_medium_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_action(view, func, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_is_valid(view, func, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForMediumLevelILFunction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_medium_level_il_instruction(cls, name, description, action, is_valid = None): + """ + ``register_for_medium_level_il_instruction`` Register a plugin to be called with a medium level IL instruction argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``MediumLevelILInstruction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_medium_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_action(view, func, instr, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_is_valid(view, func, instr, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForMediumLevelILInstruction(name, description, action_obj, is_valid_obj, None) + @classmethod def get_valid_list(cls, context): """Dict of registered plugins""" @@ -275,6 +454,36 @@ class PluginCommand(object): if not self.command.functionIsValid: return True return self.command.functionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILFunctionPluginCommand: + if context.function is None: + return False + if not self.command.lowLevelILFunctionIsValid: + return True + return self.command.lowLevelILFunctionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILInstructionPluginCommand: + if context.instruction is None: + return False + if not isinstance(context.instruction, lowlevelil.LowLevelILInstruction): + return False + if not self.command.lowLevelILInstructionIsValid: + return True + return self.command.lowLevelILInstructionIsValid(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) + elif self.command.type == PluginCommandType.MediumLevelILFunctionPluginCommand: + if context.function is None: + return False + if not self.command.mediumLevelILFunctionIsValid: + return True + return self.command.mediumLevelILFunctionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.MediumLevelILInstructionPluginCommand: + if context.instruction is None: + return False + if not isinstance(context.instruction, mediumlevelil.MediumLevelILInstruction): + return False + if not self.command.mediumLevelILInstructionIsValid: + return True + return self.command.mediumLevelILInstructionIsValid(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) return False def execute(self, context): @@ -288,6 +497,16 @@ class PluginCommand(object): self.command.rangeCommand(self.command.context, context.view.handle, context.address, context.length) elif self.command.type == PluginCommandType.FunctionPluginCommand: self.command.functionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILFunctionPluginCommand: + self.command.lowLevelILFunctionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILInstructionPluginCommand: + self.command.lowLevelILInstructionCommand(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) + elif self.command.type == PluginCommandType.MediumLevelILFunctionPluginCommand: + self.command.mediumLevelILFunctionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.MediumLevelILInstructionPluginCommand: + self.command.mediumLevelILInstructionCommand(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) def __repr__(self): return "" % self.name -- cgit v1.3.1 From 08409f8e134b3d93fc56e5e29670f8a8f4def890 Mon Sep 17 00:00:00 2001 From: Brian Potchik Date: Tue, 26 Jun 2018 23:30:22 -0400 Subject: Add new API to query active analysis info and set analysis limits. --- binaryninjaapi.h | 23 +++++++++++++++++++++++ binaryninjacore.h | 38 ++++++++++++++++++++++++++++++++++++++ binaryview.cpp | 27 +++++++++++++++++++++++++++ function.cpp | 6 ++++++ python/binaryview.py | 43 +++++++++++++++++++++++++++++++++++++++++++ python/function.py | 7 ++++++- 6 files changed, 143 insertions(+), 1 deletion(-) (limited to 'python/function.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 9c0b9bc4..f2c15fde 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1022,6 +1022,25 @@ namespace BinaryNinja void Cancel(); }; + struct ActiveAnalysisInfo + { + Ref func; + uint64_t analysisTime; + size_t updateCount; + size_t submitCount; + + ActiveAnalysisInfo(Ref f, uint64_t t, size_t uc, size_t sc) : func(f), analysisTime(t), updateCount(uc), submitCount(sc) + { + } + }; + + struct AnalysisInfo + { + BNAnalysisState state; + uint64_t analysisTime; + std::vector activeInfo; + }; + struct DataVariable { DataVariable() { } @@ -1271,6 +1290,7 @@ namespace BinaryNinja Ref AddAnalysisCompletionEvent(const std::function& callback); + AnalysisInfo GetAnalysisInfo(); BNAnalysisProgress GetAnalysisProgress(); Ref GetBackgroundAnalysisTask(); @@ -1350,6 +1370,8 @@ namespace BinaryNinja std::vector GetRawMetadata(const std::string& key); uint64_t GetUIntMetadata(const std::string& key); + BNAnalysisParameters GetParametersForAnalysis(); + void SetParametersForAnalysis(BNAnalysisParameters params); uint64_t GetMaxFunctionSizeForAnalysis(); void SetMaxFunctionSizeForAnalysis(uint64_t size); }; @@ -2493,6 +2515,7 @@ namespace BinaryNinja bool IsFunctionTooLarge(); bool IsAnalysisSkipped(); + BNAnalysisSkipReason GetAnalysisSkipReason(); BNFunctionAnalysisSkipOverride GetAnalysisSkipOverride(); void SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip); }; diff --git a/binaryninjacore.h b/binaryninjacore.h index f77a9475..fda26d47 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1480,12 +1480,37 @@ extern "C" ExtendedAnalyzeState }; + struct BNActiveAnalysisInfo + { + BNFunction* func; + uint64_t analysisTime; + size_t updateCount; + size_t submitCount; + }; + + struct BNAnalysisInfo + { + BNAnalysisState state; + uint64_t analysisTime; + BNActiveAnalysisInfo* activeInfo; + size_t count; + }; + struct BNAnalysisProgress { BNAnalysisState state; size_t count, total; }; + struct BNAnalysisParameters + { + uint64_t maxAnalysisTime; + uint64_t maxFunctionSize; + uint64_t maxFunctionAnalysisTime; + size_t maxFunctionUpdateCount; + size_t maxFunctionSubmitCount; + }; + struct BNDownloadInstanceOutputCallbacks { uint64_t (*writeCallback)(uint8_t* data, uint64_t len, void* ctxt); @@ -1790,6 +1815,14 @@ extern "C" AlwaysSkipFunctionAnalysis }; + enum BNAnalysisSkipReason + { + NoSkipReason, + AlwaysSkipReason, + ExceedFunctionSizeSkipReason, + ExceedFunctionAnalysisTimeSkipReason + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); BINARYNINJACOREAPI char** BNAllocStringList(const char** contents, size_t size); @@ -2479,9 +2512,12 @@ extern "C" BINARYNINJACOREAPI bool BNIsFunctionTooLarge(BNFunction* func); BINARYNINJACOREAPI bool BNIsFunctionAnalysisSkipped(BNFunction* func); + BINARYNINJACOREAPI BNAnalysisSkipReason BNGetAnalysisSkipReason(BNFunction* func); BINARYNINJACOREAPI BNFunctionAnalysisSkipOverride BNGetFunctionAnalysisSkipOverride(BNFunction* func); BINARYNINJACOREAPI void BNSetFunctionAnalysisSkipOverride(BNFunction* func, BNFunctionAnalysisSkipOverride skip); + BINARYNINJACOREAPI BNAnalysisParameters BNGetParametersForAnalysis(BNBinaryView* view); + BINARYNINJACOREAPI void BNSetParametersForAnalysis(BNBinaryView* view, BNAnalysisParameters params); BINARYNINJACOREAPI uint64_t BNGetMaxFunctionSizeForAnalysis(BNBinaryView* view); BINARYNINJACOREAPI void BNSetMaxFunctionSizeForAnalysis(BNBinaryView* view, uint64_t size); @@ -2491,6 +2527,8 @@ extern "C" BINARYNINJACOREAPI void BNFreeAnalysisCompletionEvent(BNAnalysisCompletionEvent* event); BINARYNINJACOREAPI void BNCancelAnalysisCompletionEvent(BNAnalysisCompletionEvent* event); + BINARYNINJACOREAPI BNAnalysisInfo* BNGetAnalysisInfo(BNBinaryView* view); + BINARYNINJACOREAPI void BNFreeAnalysisInfo(BNAnalysisInfo* info); BINARYNINJACOREAPI BNAnalysisProgress BNGetAnalysisProgress(BNBinaryView* view); BINARYNINJACOREAPI BNBackgroundTask* BNGetBackgroundAnalysisTask(BNBinaryView* view); diff --git a/binaryview.cpp b/binaryview.cpp index 9aaf3595..bebfb801 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1014,6 +1014,21 @@ vector> BinaryView::GetAnalysisFunctionList() } +AnalysisInfo BinaryView::GetAnalysisInfo() +{ + AnalysisInfo result; + BNAnalysisInfo* info = BNGetAnalysisInfo(m_object); + result.state = info->state; + result.analysisTime = info->analysisTime; + result.activeInfo.reserve(info->count); + for (size_t i = 0; i < info->count; i++) + result.activeInfo.emplace_back(new Function(BNNewFunctionReference(info->activeInfo[i].func)), + info->activeInfo[i].analysisTime, info->activeInfo[i].submitCount, info->activeInfo[i].updateCount); + BNFreeAnalysisInfo(info); + return result; +} + + bool BinaryView::HasFunctions() const { return BNHasFunctions(m_object); @@ -1969,6 +1984,18 @@ uint64_t BinaryView::GetUIntMetadata(const string& key) } +BNAnalysisParameters BinaryView::GetParametersForAnalysis() +{ + return BNGetParametersForAnalysis(m_object); +} + + +void BinaryView::SetParametersForAnalysis(BNAnalysisParameters params) +{ + BNSetParametersForAnalysis(m_object, params); +} + + uint64_t BinaryView::GetMaxFunctionSizeForAnalysis() { return BNGetMaxFunctionSizeForAnalysis(m_object); diff --git a/function.cpp b/function.cpp index 835ab144..9c56c644 100644 --- a/function.cpp +++ b/function.cpp @@ -1372,6 +1372,12 @@ bool Function::IsAnalysisSkipped() } +BNAnalysisSkipReason Function::GetAnalysisSkipReason() +{ + return BNGetAnalysisSkipReason(m_object); +} + + BNFunctionAnalysisSkipOverride Function::GetAnalysisSkipOverride() { return BNGetFunctionAnalysisSkipOverride(m_object); diff --git a/python/binaryview.py b/python/binaryview.py index 4360502f..b784106e 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -145,6 +145,27 @@ class AnalysisCompletionEvent(object): core.BNCancelAnalysisCompletionEvent(self.handle) +class ActiveAnalysisInfo(object): + def __init__(self, func, analysis_time, update_count, submit_count): + self.func = func + self.analysis_time = analysis_time + self.update_count = update_count + self.submit_count = submit_count + + def __repr__(self): + return "" % (self.func, self.analysis_time, self.update_count, self.submit_count) + + +class AnalysisInfo(object): + def __init__(self, state, analysis_time, active_info): + self.state = AnalysisState(state) + self.analysis_time = analysis_time + self.active_info = active_info + + def __repr__(self): + return "" % (self.state, self.analysis_time, self.active_info) + + class AnalysisProgress(object): def __init__(self, state, count, total): self.state = state @@ -935,6 +956,20 @@ class BinaryView(object): def saved(self, value): self.file.saved = value + @property + def analysis_info(self): + """Relevant analysis information with list of functions under active analysis (read-only)""" + info_ref = core.BNGetAnalysisInfo(self.handle) + info = info_ref[0] + active_info_list = [] + for i in xrange(0, info.count): + func = function.Function(self, core.BNNewFunctionReference(info.activeInfo[i].func)) + active_info = ActiveAnalysisInfo(func, info.activeInfo[i].analysisTime, info.activeInfo[i].updateCount, info.activeInfo[i].submitCount) + active_info_list.append(active_info) + result = AnalysisInfo(info.state, info.analysisTime, active_info_list) + core.BNFreeAnalysisInfo(info_ref) + return result + @property def analysis_progress(self): """Status of current analysis (read-only)""" @@ -1026,6 +1061,14 @@ class BinaryView(object): result = core.BNGetGlobalPointerValue(self.handle) return function.RegisterValue(self.arch, result.value, confidence = result.confidence) + @property + def parameters_for_analysis(self): + return core.BNGetParametersForAnalysis(self.handle) + + @parameters_for_analysis.setter + def parameters_for_analysis(self, params): + core.BNSetParametersForAnalysis(self.handle, params) + @property def max_function_size_for_analysis(self): """Maximum size of function (sum of basic block sizes in bytes) for auto analysis""" diff --git a/python/function.py b/python/function.py index 6db44e6d..2f794f47 100644 --- a/python/function.py +++ b/python/function.py @@ -24,7 +24,7 @@ import ctypes # Binary Ninja components import _binaryninjacore as core -from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, +from enums import (AnalysisSkipReason, FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend, DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType, FunctionAnalysisSkipOverride) @@ -828,6 +828,11 @@ class Function(object): """Whether automatic analysis was skipped for this function""" return core.BNIsFunctionAnalysisSkipped(self.handle) + @property + def analysis_skip_reason(self): + """Function analysis skip reason""" + return AnalysisSkipReason(core.BNGetAnalysisSkipReason(self.handle)) + @analysis_skipped.setter def analysis_skipped(self, skip): if skip: -- cgit v1.3.1