From 6a84981b1ec92dc0a2b7eb02133fe055ddc1b22a Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Mon, 19 Oct 2026 13:35:26 -0700 Subject: [PATCH 1/4] Fix C++ IL operand tables and expression handling The operand tables behind GetOperands(), the IL operand classes and the untyped instruction accessors read several ops' operands from the wrong slots, or reported them under the wrong usage. MLIL's CopyTo also didn't handle phis, and HLIL's expression ordering threw on WHILE_SSA and ignored the operands of a few ops. Now each op's operands are read from the right slots, CopyTo copies phis, and expression ordering compares every operand. --- highlevelilinstruction.cpp | 77 +++++++++++++++++++++++++++++++----- highlevelilinstruction.h | 6 ++- lowlevelilinstruction.cpp | 33 ++++++++++++++-- mediumlevelilinstruction.cpp | 27 +++++++++---- 4 files changed, 121 insertions(+), 22 deletions(-) diff --git a/highlevelilinstruction.cpp b/highlevelilinstruction.cpp index 6fe86fdcd3..19aa451256 100644 --- a/highlevelilinstruction.cpp +++ b/highlevelilinstruction.cpp @@ -93,7 +93,8 @@ static constexpr std::array s_operandTypeForUsage = { OperandUsageType{SourceSSAVariablesHighLevelOperandUsage, SSAVariableListHighLevelOperand}, OperandUsageType{SourceMemoryVersionHighLevelOperandUsage, IndexHighLevelOperand}, OperandUsageType{SourceMemoryVersionsHighLevelOperandUsage, IndexListHighLevelOperand}, - OperandUsageType{DestMemoryVersionHighLevelOperandUsage, IndexHighLevelOperand} + OperandUsageType{DestMemoryVersionHighLevelOperandUsage, IndexHighLevelOperand}, + OperandUsageType{ConstraintHighLevelOperandUsage, ConstraintHighLevelOperand} }; static_assert(std::is_sorted(s_operandTypeForUsage.begin(), s_operandTypeForUsage.end()), @@ -159,7 +160,7 @@ static constexpr std::array s_instructionOperandUsage = { OperandUsage{HLIL_ASSIGN, {DestExprHighLevelOperandUsage, SourceExprHighLevelOperandUsage}}, OperandUsage{HLIL_ASSIGN_UNPACK, {DestExprsHighLevelOperandUsage, SourceExprHighLevelOperandUsage}}, OperandUsage{HLIL_FORCE_VER, {DestVariableHighLevelOperandUsage, VariableHighLevelOperandUsage}}, - OperandUsage{HLIL_ASSERT, {VariableHighLevelOperandUsage, ConstantHighLevelOperandUsage}}, + OperandUsage{HLIL_ASSERT, {VariableHighLevelOperandUsage, ConstraintHighLevelOperandUsage}}, OperandUsage{HLIL_VAR, {VariableHighLevelOperandUsage}}, OperandUsage{HLIL_STRUCT_FIELD, {SourceExprHighLevelOperandUsage, OffsetHighLevelOperandUsage, MemberIndexHighLevelOperandUsage}}, OperandUsage{HLIL_ARRAY_INDEX, {SourceExprHighLevelOperandUsage, IndexExprHighLevelOperandUsage}}, @@ -260,7 +261,7 @@ static constexpr std::array s_instructionOperandUsage = { OperandUsage{HLIL_ASSIGN_MEM_SSA, {DestExprHighLevelOperandUsage, DestMemoryVersionHighLevelOperandUsage, SourceExprHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage}}, OperandUsage{HLIL_ASSIGN_UNPACK_MEM_SSA, {DestExprsHighLevelOperandUsage, DestMemoryVersionHighLevelOperandUsage, SourceExprHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage}}, OperandUsage{HLIL_FORCE_VER_SSA, {DestSSAVariableHighLevelOperandUsage, SSAVariableHighLevelOperandUsage}}, - OperandUsage{HLIL_ASSERT_SSA, {SSAVariableHighLevelOperandUsage, ConstantHighLevelOperandUsage}}, + OperandUsage{HLIL_ASSERT_SSA, {SSAVariableHighLevelOperandUsage, ConstraintHighLevelOperandUsage}}, OperandUsage{HLIL_VAR_SSA, {SSAVariableHighLevelOperandUsage}}, OperandUsage{HLIL_VAR_SSA_PARTIAL, {SSAVariableHighLevelOperandUsage, PartialSSAVariableSourceHighLevelOperandUsage}}, OperandUsage{HLIL_ARRAY_INDEX_SSA, {SourceExprHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage, IndexExprHighLevelOperandUsage}}, @@ -632,6 +633,8 @@ SSAVariable HighLevelILOperand::GetSSAVariable() const { if (m_type != SSAVariableHighLevelOperand) throw HighLevelILInstructionAccessException(); + if (m_usage == PartialSSAVariableSourceHighLevelOperandUsage) + return m_instr.GetRawOperandAsPartialSSAVariableSource(m_operandIndex - 2); return m_instr.GetRawOperandAsSSAVariable(m_operandIndex); } @@ -1798,11 +1801,11 @@ bool HighLevelILInstruction::operator<(const HighLevelILInstruction& other) cons return true; if (other.GetConditionPhiExpr() < GetConditionPhiExpr()) return false; - if (GetConditionExpr() < other.GetConditionExpr()) + if (GetConditionExpr() < other.GetConditionExpr()) return true; - if (other.GetConditionExpr() < GetConditionExpr()) + if (other.GetConditionExpr() < GetConditionExpr()) return false; - return GetLoopExpr() < other.GetLoopExpr(); + return GetLoopExpr() < other.GetLoopExpr(); case HLIL_DO_WHILE: if (GetLoopExpr() < other.GetLoopExpr()) return true; @@ -1913,6 +1916,46 @@ bool HighLevelILInstruction::operator<(const HighLevelILInstruction& other) cons if (other.GetSourceExpr() < GetSourceExpr()) return false; return CompareExprList(GetDestExprs(), other.GetDestExprs()); + case HLIL_FORCE_VER: + if (size < other.size) + return true; + if (size > other.size) + return false; + if (GetDestVariable() < other.GetDestVariable()) + return true; + if (other.GetDestVariable() < GetDestVariable()) + return false; + return GetVariable() < other.GetVariable(); + case HLIL_FORCE_VER_SSA: + if (size < other.size) + return true; + if (size > other.size) + return false; + if (GetDestSSAVariable() < other.GetDestSSAVariable()) + return true; + if (other.GetDestSSAVariable() < GetDestSSAVariable()) + return false; + return GetSSAVariable() < other.GetSSAVariable(); + case HLIL_ASSERT: + if (size < other.size) + return true; + if (size > other.size) + return false; + if (GetVariable() < other.GetVariable()) + return true; + if (other.GetVariable() < GetVariable()) + return false; + return GetRawOperandAsInteger(1) < other.GetRawOperandAsInteger(1); + case HLIL_ASSERT_SSA: + if (size < other.size) + return true; + if (size > other.size) + return false; + if (GetSSAVariable() < other.GetSSAVariable()) + return true; + if (other.GetSSAVariable() < GetSSAVariable()) + return false; + return GetRawOperandAsInteger(2) < other.GetRawOperandAsInteger(2); case HLIL_ASSIGN_MEM_SSA: if (size < other.size) return true; @@ -2225,12 +2268,29 @@ bool HighLevelILInstruction::operator<(const HighLevelILInstruction& other) cons if (other.AsTwoOperandWithCarry().GetRightExpr() < AsTwoOperandWithCarry().GetRightExpr()) return false; return AsTwoOperandWithCarry().GetCarryExpr() < other.AsTwoOperandWithCarry().GetCarryExpr(); - case HLIL_CONST: case HLIL_CONST_DATA: + if (GetRawOperandAsInteger(0) < other.GetRawOperandAsInteger(0)) + return true; + if (other.GetRawOperandAsInteger(0) < GetRawOperandAsInteger(0)) + return false; + return GetRawOperandAsInteger(1) < other.GetRawOperandAsInteger(1); + case HLIL_CONST: case HLIL_CONST_PTR: case HLIL_FLOAT_CONST: case HLIL_IMPORT: return AsConstant().GetConstant() < other.AsConstant().GetConstant(); + case HLIL_UNIMPL: + return As().IsUnknown() < other.As().IsUnknown(); + case HLIL_UNIMPL_MEM: + if (size < other.size) + return true; + if (size > other.size) + return false; + if (GetSourceExpr() < other.GetSourceExpr()) + return true; + if (other.GetSourceExpr() < GetSourceExpr()) + return false; + return As().IsUnknown() < other.As().IsUnknown(); case HLIL_DEREF: case HLIL_NEG: case HLIL_NOT: @@ -2245,7 +2305,6 @@ bool HighLevelILInstruction::operator<(const HighLevelILInstruction& other) cons case HLIL_ZX: case HLIL_LOW_PART: case HLIL_BOOL_TO_INT: - case HLIL_UNIMPL_MEM: case HLIL_FSQRT: case HLIL_FNEG: case HLIL_FABS: @@ -2396,7 +2455,7 @@ SSAVariable HighLevelILInstruction::GetSourceSSAVariable() const size_t operandIndex; if (GetOperandIndexForUsage(PartialSSAVariableSourceHighLevelOperandUsage, operandIndex)) return GetRawOperandAsPartialSSAVariableSource(operandIndex - 2); - throw MediumLevelILInstructionAccessException(); + throw HighLevelILInstructionAccessException(); } diff --git a/highlevelilinstruction.h b/highlevelilinstruction.h index 150cf37dd6..71d232ec7b 100644 --- a/highlevelilinstruction.h +++ b/highlevelilinstruction.h @@ -76,7 +76,8 @@ namespace BinaryNinja SSAVariableHighLevelOperand, ExprListHighLevelOperand, SSAVariableListHighLevelOperand, - IndexListHighLevelOperand + IndexListHighLevelOperand, + ConstraintHighLevelOperand }; /*! @@ -122,7 +123,8 @@ namespace BinaryNinja SourceSSAVariablesHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage, SourceMemoryVersionsHighLevelOperandUsage, - DestMemoryVersionHighLevelOperandUsage + DestMemoryVersionHighLevelOperandUsage, + ConstraintHighLevelOperandUsage }; } // namespace BinaryNinjaCore diff --git a/lowlevelilinstruction.cpp b/lowlevelilinstruction.cpp index bad95a103f..ae277bc6ef 100644 --- a/lowlevelilinstruction.cpp +++ b/lowlevelilinstruction.cpp @@ -188,6 +188,14 @@ using OperandUsage = detail::ILInstructionOperandUsage +static constexpr OperandUsage WithOperandIndices(OperandUsage usage, const uint8_t (&indices)[N]) +{ + std::copy(indices, indices + N, usage.indices); + return usage; +} + + static constexpr std::array s_instructionOperandUsage = { OperandUsage{LLIL_NOP}, OperandUsage{LLIL_SET_REG, {DestRegisterLowLevelOperandUsage, SourceExprLowLevelOperandUsage}}, @@ -305,8 +313,8 @@ static constexpr std::array s_instructionOperandUsage = { OperandUsage{LLIL_REG_STACK_DEST_SSA}, OperandUsage{LLIL_REG_SSA, {SourceSSARegisterLowLevelOperandUsage}}, OperandUsage{LLIL_REG_SSA_PARTIAL, {SourceSSARegisterLowLevelOperandUsage, PartialRegisterLowLevelOperandUsage}}, - OperandUsage{LLIL_REG_SPLIT_SSA, {HighSSARegisterLowLevelOperandUsage, LowSSARegisterLowLevelOperandUsage}}, - OperandUsage{LLIL_REG_STACK_REL_SSA, {SourceSSARegisterStackLowLevelOperandUsage, TopSSARegisterLowLevelOperandUsage, SourceExprLowLevelOperandUsage}}, + WithOperandIndices(OperandUsage{LLIL_REG_SPLIT_SSA, {HighSSARegisterLowLevelOperandUsage, LowSSARegisterLowLevelOperandUsage}}, {0, 2}), + OperandUsage{LLIL_REG_STACK_REL_SSA, {SourceSSARegisterStackLowLevelOperandUsage, SourceExprLowLevelOperandUsage, TopSSARegisterLowLevelOperandUsage}}, OperandUsage{LLIL_REG_STACK_ABS_SSA, {SourceSSARegisterStackLowLevelOperandUsage, SourceRegisterLowLevelOperandUsage}}, OperandUsage{LLIL_REG_STACK_FREE_REL_SSA, {DestSSARegisterStackLowLevelOperandUsage, PartialSSARegisterStackSourceLowLevelOperandUsage, DestExprLowLevelOperandUsage, TopSSARegisterLowLevelOperandUsage}}, OperandUsage{LLIL_REG_STACK_FREE_ABS_SSA, {DestSSARegisterStackLowLevelOperandUsage, PartialSSARegisterStackSourceLowLevelOperandUsage, DestRegisterLowLevelOperandUsage}}, @@ -329,7 +337,7 @@ static constexpr std::array s_instructionOperandUsage = { OperandUsage{LLIL_INTRINSIC_SSA, {OutputSSARegisterOrFlagListLowLevelOperandUsage, IntrinsicLowLevelOperandUsage, ParameterExprsLowLevelOperandUsage}}, OperandUsage{LLIL_MEMORY_INTRINSIC_SSA, {OutputMemoryIntrinsicLowLevelOperandUsage, OutputMemoryVersionLowLevelOperandUsage, IntrinsicLowLevelOperandUsage, ParameterExprsLowLevelOperandUsage, SourceMemoryVersionLowLevelOperandUsage}}, OperandUsage{LLIL_REG_PHI, {DestSSARegisterLowLevelOperandUsage, SourceSSARegistersLowLevelOperandUsage}}, - OperandUsage{LLIL_REG_STACK_PHI, {DestSSARegisterStackLowLevelOperandUsage, SourceSSARegisterStacksLowLevelOperandUsage}}, + WithOperandIndices(OperandUsage{LLIL_REG_STACK_PHI, {DestSSARegisterStackLowLevelOperandUsage, SourceSSARegisterStacksLowLevelOperandUsage}}, {0, 2}), OperandUsage{LLIL_FLAG_PHI, {DestSSAFlagLowLevelOperandUsage, SourceSSAFlagsLowLevelOperandUsage}}, OperandUsage{LLIL_MEM_PHI, {DestMemoryVersionLowLevelOperandUsage, SourceMemoryVersionsLowLevelOperandUsage}}, OperandUsage{LLIL_BSWAP, {SourceExprLowLevelOperandUsage}}, @@ -1243,6 +1251,9 @@ SSARegister LowLevelILOperand::GetSSARegister() const { if (m_type != SSARegisterLowLevelOperand) throw LowLevelILInstructionAccessException(); + if (((m_usage == HighSSARegisterLowLevelOperandUsage) || (m_usage == LowSSARegisterLowLevelOperandUsage)) + && (m_instr.operation == LLIL_REG_SPLIT_SSA)) + return m_instr.GetRawOperandAsSSARegister(m_operandIndex); if ((m_usage == HighSSARegisterLowLevelOperandUsage) || (m_usage == LowSSARegisterLowLevelOperandUsage) || (m_usage == StackSSARegisterLowLevelOperandUsage) || (m_usage == TopSSARegisterLowLevelOperandUsage)) return m_instr.GetRawOperandAsExpr(m_operandIndex).GetRawOperandAsSSARegister(0); @@ -1254,7 +1265,7 @@ SSARegisterStack LowLevelILOperand::GetSSARegisterStack() const { if (m_type != SSARegisterStackLowLevelOperand) throw LowLevelILInstructionAccessException(); - if (m_usage == DestSSARegisterStackLowLevelOperandUsage) + if ((m_usage == DestSSARegisterStackLowLevelOperandUsage) && (m_instr.operation != LLIL_REG_STACK_PHI)) return m_instr.GetRawOperandAsExpr(m_operandIndex).GetRawOperandAsSSARegisterStack(0); if (m_usage == PartialSSARegisterStackSourceLowLevelOperandUsage) return m_instr.GetRawOperandAsExpr(m_operandIndex).GetRawOperandAsPartialSSARegisterStackSource(0); @@ -1290,6 +1301,8 @@ LowLevelILInstructionList LowLevelILOperand::GetExprList() const { if (m_type != ExprListLowLevelOperand) throw LowLevelILInstructionAccessException(); + if (m_operandIndex == 0) + return m_instr.GetRawOperandAsExprList(0); return m_instr.GetRawOperandAsExpr(m_operandIndex).GetRawOperandAsExprList(0); } @@ -2585,7 +2598,11 @@ SSARegisterStack LowLevelILInstruction::GetDestSSARegisterStack() const { size_t operandIndex; if (GetOperandIndexForUsage(DestSSARegisterStackLowLevelOperandUsage, operandIndex)) + { + if (operation == LLIL_REG_STACK_PHI) + return GetRawOperandAsSSARegisterStack(operandIndex); return GetRawOperandAsExpr(operandIndex).GetRawOperandAsSSARegisterStack(0); + } throw LowLevelILInstructionAccessException(); } @@ -2693,7 +2710,11 @@ SSARegister LowLevelILInstruction::GetHighSSARegister() const { size_t operandIndex; if (GetOperandIndexForUsage(HighSSARegisterLowLevelOperandUsage, operandIndex)) + { + if (operation == LLIL_REG_SPLIT_SSA) + return GetRawOperandAsSSARegister(operandIndex); return GetRawOperandAsExpr(operandIndex).GetRawOperandAsSSARegister(0); + } throw LowLevelILInstructionAccessException(); } @@ -2711,7 +2732,11 @@ SSARegister LowLevelILInstruction::GetLowSSARegister() const { size_t operandIndex; if (GetOperandIndexForUsage(LowSSARegisterLowLevelOperandUsage, operandIndex)) + { + if (operation == LLIL_REG_SPLIT_SSA) + return GetRawOperandAsSSARegister(operandIndex); return GetRawOperandAsExpr(operandIndex).GetRawOperandAsSSARegister(0); + } throw LowLevelILInstructionAccessException(); } diff --git a/mediumlevelilinstruction.cpp b/mediumlevelilinstruction.cpp index a2f5b69dec..b810a07051 100644 --- a/mediumlevelilinstruction.cpp +++ b/mediumlevelilinstruction.cpp @@ -68,8 +68,8 @@ static constexpr std::array s_operandTypeForUsage = { OperandUsageType{ConditionExprMediumLevelOperandUsage, ExprMediumLevelOperand}, OperandUsageType{HighVariableMediumLevelOperandUsage, VariableMediumLevelOperand}, OperandUsageType{LowVariableMediumLevelOperandUsage, VariableMediumLevelOperand}, - OperandUsageType{HighSSAVariableMediumLevelOperandUsage, VariableMediumLevelOperand}, - OperandUsageType{LowSSAVariableMediumLevelOperandUsage, VariableMediumLevelOperand}, + OperandUsageType{HighSSAVariableMediumLevelOperandUsage, SSAVariableMediumLevelOperand}, + OperandUsageType{LowSSAVariableMediumLevelOperandUsage, SSAVariableMediumLevelOperand}, OperandUsageType{OffsetMediumLevelOperandUsage, IntegerMediumLevelOperand}, OperandUsageType{ConstantMediumLevelOperandUsage, IntegerMediumLevelOperand}, OperandUsageType{ConstantDataMediumLevelOperandUsage, ConstantDataMediumLevelOperand}, @@ -213,7 +213,7 @@ static constexpr std::array s_instructionOperandUsage = { OperandUsage{MLIL_JUMP_TO, {DestExprMediumLevelOperandUsage, TargetsMediumLevelOperandUsage}}, OperandUsage{MLIL_RET_HINT, {DestExprMediumLevelOperandUsage}}, OperandUsage{MLIL_CALL, {OutputExprsMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage}}, - OperandUsage{MLIL_CALL_UNTYPED, {OutputExprsMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, UntypedParameterExprsMediumLevelOperandUsage}}, + OperandUsage{MLIL_CALL_UNTYPED, {OutputExprsMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, UntypedParameterExprsMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}}, OperandUsage{MLIL_CALL_PARAM, {ParameterExprsMediumLevelOperandUsage}}, OperandUsage{MLIL_SEPARATE_PARAM_LIST, {ParameterExprsMediumLevelOperandUsage}}, OperandUsage{MLIL_SHARED_PARAM_SLOT, {ParameterExprsMediumLevelOperandUsage}}, @@ -240,7 +240,7 @@ static constexpr std::array s_instructionOperandUsage = { OperandUsage{MLIL_SYSCALL, {OutputExprsMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage}}, OperandUsage{MLIL_SYSCALL_UNTYPED, {OutputExprsMediumLevelOperandUsage, UntypedParameterExprsMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}}, OperandUsage{MLIL_TAILCALL, {OutputExprsMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage}}, - OperandUsage{MLIL_TAILCALL_UNTYPED, {OutputExprsMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, UntypedParameterExprsMediumLevelOperandUsage}}, + OperandUsage{MLIL_TAILCALL_UNTYPED, {OutputExprsMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, UntypedParameterExprsMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}}, OperandUsage{MLIL_INTRINSIC, {OutputVariablesMediumLevelOperandUsage, IntrinsicMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage}}, OperandUsage{MLIL_FREE_VAR_SLOT, {DestVariableMediumLevelOperandUsage}}, OperandUsage{MLIL_BP}, @@ -288,13 +288,13 @@ static constexpr std::array s_instructionOperandUsage = { OperandUsage{MLIL_SYSCALL_UNTYPED_SSA, {OutputExprsSubExprMediumLevelOperandUsage, OutputSSAMemoryVersionMediumLevelOperandUsage, UntypedParameterSSAExprsMediumLevelOperandUsage, ParameterSSAMemoryVersionMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}}, OperandUsage{MLIL_TAILCALL_SSA, {OutputExprsSubExprMediumLevelOperandUsage, OutputSSAMemoryVersionMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}}, OperandUsage{MLIL_TAILCALL_UNTYPED_SSA, {OutputExprsSubExprMediumLevelOperandUsage, OutputSSAMemoryVersionMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, UntypedParameterSSAExprsMediumLevelOperandUsage, ParameterSSAMemoryVersionMediumLevelOperandUsage, StackExprMediumLevelOperandUsage}}, - OperandUsage{MLIL_CALL_PARAM_SSA, {ParameterExprsMediumLevelOperandUsage}}, - OperandUsage{MLIL_CALL_OUTPUT_SSA, {OutputSSAVariablesMediumLevelOperandUsage}}, + OperandUsage{MLIL_CALL_PARAM_SSA, {SourceMemoryVersionMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage}}, + OperandUsage{MLIL_CALL_OUTPUT_SSA, {DestMemoryVersionMediumLevelOperandUsage, OutputExprsMediumLevelOperandUsage}}, OperandUsage{MLIL_VAR_OUTPUT_SSA, {DestSSAVariableMediumLevelOperandUsage}}, OperandUsage{MLIL_VAR_OUTPUT_SSA_FIELD, {DestSSAVariableMediumLevelOperandUsage, PartialSSAVariableSourceMediumLevelOperandUsage, OffsetMediumLevelOperandUsage}}, OperandUsage{MLIL_VAR_OUTPUT_ALIASED, {DestSSAVariableMediumLevelOperandUsage, PartialSSAVariableSourceMediumLevelOperandUsage}}, OperandUsage{MLIL_VAR_OUTPUT_ALIASED_FIELD, {DestSSAVariableMediumLevelOperandUsage, PartialSSAVariableSourceMediumLevelOperandUsage, OffsetMediumLevelOperandUsage}}, - OperandUsage{MLIL_MEMORY_INTRINSIC_OUTPUT_SSA, {OutputSSAVariablesMediumLevelOperandUsage}}, + OperandUsage{MLIL_MEMORY_INTRINSIC_OUTPUT_SSA, {DestMemoryVersionMediumLevelOperandUsage, OutputSSAVariablesMediumLevelOperandUsage}}, OperandUsage{MLIL_LOAD_SSA, {SourceExprMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}}, OperandUsage{MLIL_LOAD_STRUCT_SSA, {SourceExprMediumLevelOperandUsage, OffsetMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}}, OperandUsage{MLIL_STORE_SSA, {DestExprMediumLevelOperandUsage, DestMemoryVersionMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage, SourceExprMediumLevelOperandUsage}}, @@ -2030,6 +2030,19 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest, return dest->FreeVarSlotSSA(GetDestSSAVariable().var, GetDestSSAVariable().version, GetSourceSSAVariable().version, loc); + case MLIL_VAR_PHI: + { + SSAVariable phiDest = GetDestSSAVariable(); + vector sources = GetSourceSSAVariables(); + return dest->AddExprWithLocation(MLIL_VAR_PHI, loc, size, phiDest.var.ToIdentifier(), phiDest.version, + sources.size() * 2, dest->AddSSAVariableList(sources)); + } + case MLIL_MEM_PHI: + { + vector sources = GetSourceMemoryVersions(); + return dest->AddExprWithLocation(MLIL_MEM_PHI, loc, size, GetDestMemoryVersion(), sources.size(), + dest->AddIndexList(sources)); + } case MLIL_UNDEF: return dest->Undefined(loc); case MLIL_UNIMPL: From 07f59540291c91d4bbe7af5c60cbd63d1ee2db0c Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Mon, 19 Oct 2026 12:29:14 -0700 Subject: [PATCH 2/4] Fix the Rust flag-write callback ignoring some ops and reading a null slice Rust architectures were never asked for the flags of comparisons, float operations or intrinsics. `LowLevelILFlagWriteOp` had no variants for them, so the callback logged a warning and used core's default flag IL instead. Each now has a variant. `Intrinsic` carries a parameter list, so the enum is no longer `Copy`. The callback also built its operand slice with `std::slice::from_raw_parts`, which is undefined behavior if it is ever passed null. It now uses `ffi::slice_from_raw_parts`, which returns an empty slice instead. --- rust/src/architecture.rs | 4 +- rust/src/low_level_il/lifting.rs | 281 +++++++++++++++++++++++++++---- 2 files changed, 254 insertions(+), 31 deletions(-) diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index c8e6b7f103..d3eae7eecf 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -26,7 +26,7 @@ use crate::{ calling_convention::CoreCallingConvention, data_buffer::DataBuffer, disassembly::InstructionTextToken, - ffi::INVALID_REGISTER, + ffi::{slice_from_raw_parts, INVALID_REGISTER}, function::{Function, Location, NativeBlock}, platform::Platform, rc::*, @@ -2206,7 +2206,7 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; let flag_write = custom_arch.flag_write_from_id(FlagWriteId(flag_write)); let flag = custom_arch.flag_from_id(FlagId(flag)); - let operands = unsafe { std::slice::from_raw_parts(operands_raw, operand_count) }; + let operands = unsafe { slice_from_raw_parts(operands_raw, operand_count) }; let lifter = unsafe { LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; diff --git a/rust/src/low_level_il/lifting.rs b/rust/src/low_level_il/lifting.rs index e2fb84e425..8dd778b533 100644 --- a/rust/src/low_level_il/lifting.rs +++ b/rust/src/low_level_il/lifting.rs @@ -20,7 +20,7 @@ use binaryninjacore_sys::{ }; use super::*; -use crate::architecture::{Architecture, FlagWriteId, RegisterId}; +use crate::architecture::{Architecture, FlagWriteId, IntrinsicId, RegisterId}; use crate::architecture::{CoreRegister, Register as ArchReg}; use crate::architecture::{ Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite, Intrinsic, @@ -68,8 +68,7 @@ impl From> for BNRegisterOrConstant } } -// TODO flesh way out -#[derive(Copy, Clone)] +#[derive(Clone)] pub enum LowLevelILFlagWriteOp { SetReg(usize, LowLevelILRegisterOrConstant), SetRegSplit( @@ -106,6 +105,15 @@ pub enum LowLevelILFlagWriteOp { LowPart(usize, LowLevelILRegisterOrConstant), BoolToInt(usize, LowLevelILRegisterOrConstant), FloatToInt(usize, LowLevelILRegisterOrConstant), + Fsqrt(usize, LowLevelILRegisterOrConstant), + Fneg(usize, LowLevelILRegisterOrConstant), + Fabs(usize, LowLevelILRegisterOrConstant), + IntToFloat(usize, LowLevelILRegisterOrConstant), + FloatConv(usize, LowLevelILRegisterOrConstant), + RoundToInt(usize, LowLevelILRegisterOrConstant), + Floor(usize, LowLevelILRegisterOrConstant), + Ceil(usize, LowLevelILRegisterOrConstant), + Ftrunc(usize, LowLevelILRegisterOrConstant), Store( usize, @@ -239,6 +247,117 @@ pub enum LowLevelILFlagWriteOp { LowLevelILRegisterOrConstant, LowLevelILRegisterOrConstant, ), + CmpE( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpNe( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpSlt( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpUlt( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpSle( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpUle( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpSge( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpUge( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpSgt( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + CmpUgt( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + + Fadd( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + Fsub( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + Fmul( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + Fdiv( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + FcmpE( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + FcmpNE( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + FcmpLT( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + FcmpLE( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + FcmpGE( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + FcmpGT( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + FcmpO( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), + FcmpUO( + usize, + LowLevelILRegisterOrConstant, + LowLevelILRegisterOrConstant, + ), Adc( usize, @@ -266,7 +385,9 @@ pub enum LowLevelILFlagWriteOp { ), Pop(usize), - // TODO: floating point stuff, llil comparison ops that set flags, intrinsics + + /// Core doesn't pass each parameter's width, so the parameters carry the intrinsic's size, which is usually 0. + Intrinsic(usize, IntrinsicId, Vec>), } impl LowLevelILFlagWriteOp { @@ -332,6 +453,15 @@ impl LowLevelILFlagWriteOp { (1, LLIL_LOW_PART) => op!(LowPart, 0), (1, LLIL_BOOL_TO_INT) => op!(BoolToInt, 0), (1, LLIL_FLOAT_TO_INT) => op!(FloatToInt, 0), + (1, LLIL_FSQRT) => op!(Fsqrt, 0), + (1, LLIL_FNEG) => op!(Fneg, 0), + (1, LLIL_FABS) => op!(Fabs, 0), + (1, LLIL_INT_TO_FLOAT) => op!(IntToFloat, 0), + (1, LLIL_FLOAT_CONV) => op!(FloatConv, 0), + (1, LLIL_ROUND_TO_INT) => op!(RoundToInt, 0), + (1, LLIL_FLOOR) => op!(Floor, 0), + (1, LLIL_CEIL) => op!(Ceil, 0), + (1, LLIL_FTRUNC) => op!(Ftrunc, 0), (2, LLIL_STORE) => op!(Store, 0, 1), @@ -361,6 +491,29 @@ impl LowLevelILFlagWriteOp { (2, LLIL_TEST_BIT) => op!(TestBit, 0, 1), (2, LLIL_ADD_OVERFLOW) => op!(AddOverflow, 0, 1), + (2, LLIL_CMP_E) => op!(CmpE, 0, 1), + (2, LLIL_CMP_NE) => op!(CmpNe, 0, 1), + (2, LLIL_CMP_SLT) => op!(CmpSlt, 0, 1), + (2, LLIL_CMP_ULT) => op!(CmpUlt, 0, 1), + (2, LLIL_CMP_SLE) => op!(CmpSle, 0, 1), + (2, LLIL_CMP_ULE) => op!(CmpUle, 0, 1), + (2, LLIL_CMP_SGE) => op!(CmpSge, 0, 1), + (2, LLIL_CMP_UGE) => op!(CmpUge, 0, 1), + (2, LLIL_CMP_SGT) => op!(CmpSgt, 0, 1), + (2, LLIL_CMP_UGT) => op!(CmpUgt, 0, 1), + + (2, LLIL_FADD) => op!(Fadd, 0, 1), + (2, LLIL_FSUB) => op!(Fsub, 0, 1), + (2, LLIL_FMUL) => op!(Fmul, 0, 1), + (2, LLIL_FDIV) => op!(Fdiv, 0, 1), + (2, LLIL_FCMP_E) => op!(FcmpE, 0, 1), + (2, LLIL_FCMP_NE) => op!(FcmpNE, 0, 1), + (2, LLIL_FCMP_LT) => op!(FcmpLT, 0, 1), + (2, LLIL_FCMP_LE) => op!(FcmpLE, 0, 1), + (2, LLIL_FCMP_GE) => op!(FcmpGE, 0, 1), + (2, LLIL_FCMP_GT) => op!(FcmpGT, 0, 1), + (2, LLIL_FCMP_O) => op!(FcmpO, 0, 1), + (2, LLIL_FCMP_UO) => op!(FcmpUO, 0, 1), (3, LLIL_ADC) => op!(Adc, 0, 1, 2), (3, LLIL_SBB) => op!(Sbb, 0, 1, 2), @@ -369,6 +522,16 @@ impl LowLevelILFlagWriteOp { (0, LLIL_POP) => op!(Pop,), + // Core passes the intrinsic as a constant, followed by each parameter. + (n, LLIL_INTRINSIC) if n >= 1 && operands[0].constant => Intrinsic( + size, + IntrinsicId(operands[0].value as u32), + operands[1..] + .iter() + .map(|operand| build_op(arch, size, operand)) + .collect(), + ), + _ => return None, }) } @@ -401,6 +564,15 @@ impl LowLevelILFlagWriteOp { LowPart(size, ..) => (size, LLIL_LOW_PART), BoolToInt(size, ..) => (size, LLIL_BOOL_TO_INT), FloatToInt(size, ..) => (size, LLIL_FLOAT_TO_INT), + Fsqrt(size, ..) => (size, LLIL_FSQRT), + Fneg(size, ..) => (size, LLIL_FNEG), + Fabs(size, ..) => (size, LLIL_FABS), + IntToFloat(size, ..) => (size, LLIL_INT_TO_FLOAT), + FloatConv(size, ..) => (size, LLIL_FLOAT_CONV), + RoundToInt(size, ..) => (size, LLIL_ROUND_TO_INT), + Floor(size, ..) => (size, LLIL_FLOOR), + Ceil(size, ..) => (size, LLIL_CEIL), + Ftrunc(size, ..) => (size, LLIL_FTRUNC), Store(size, ..) => (size, LLIL_STORE), @@ -430,6 +602,29 @@ impl LowLevelILFlagWriteOp { TestBit(size, ..) => (size, LLIL_TEST_BIT), AddOverflow(size, ..) => (size, LLIL_ADD_OVERFLOW), + CmpE(size, ..) => (size, LLIL_CMP_E), + CmpNe(size, ..) => (size, LLIL_CMP_NE), + CmpSlt(size, ..) => (size, LLIL_CMP_SLT), + CmpUlt(size, ..) => (size, LLIL_CMP_ULT), + CmpSle(size, ..) => (size, LLIL_CMP_SLE), + CmpUle(size, ..) => (size, LLIL_CMP_ULE), + CmpSge(size, ..) => (size, LLIL_CMP_SGE), + CmpUge(size, ..) => (size, LLIL_CMP_UGE), + CmpSgt(size, ..) => (size, LLIL_CMP_SGT), + CmpUgt(size, ..) => (size, LLIL_CMP_UGT), + + Fadd(size, ..) => (size, LLIL_FADD), + Fsub(size, ..) => (size, LLIL_FSUB), + Fmul(size, ..) => (size, LLIL_FMUL), + Fdiv(size, ..) => (size, LLIL_FDIV), + FcmpE(size, ..) => (size, LLIL_FCMP_E), + FcmpNE(size, ..) => (size, LLIL_FCMP_NE), + FcmpLT(size, ..) => (size, LLIL_FCMP_LT), + FcmpLE(size, ..) => (size, LLIL_FCMP_LE), + FcmpGE(size, ..) => (size, LLIL_FCMP_GE), + FcmpGT(size, ..) => (size, LLIL_FCMP_GT), + FcmpO(size, ..) => (size, LLIL_FCMP_O), + FcmpUO(size, ..) => (size, LLIL_FCMP_UO), Adc(size, ..) => (size, LLIL_ADC), Sbb(size, ..) => (size, LLIL_SBB), @@ -437,16 +632,16 @@ impl LowLevelILFlagWriteOp { Rrc(size, ..) => (size, LLIL_RRC), Pop(size) => (size, LLIL_POP), + + Intrinsic(size, ..) => (size, LLIL_INTRINSIC), } } - pub(crate) fn raw_operands(&self) -> (usize, [BNRegisterOrConstant; 5]) { + pub(crate) fn raw_operands(&self) -> Vec { use self::LowLevelILFlagWriteOp::*; - let mut operands: [BNRegisterOrConstant; 5] = [BNRegisterOrConstant::default(); 5]; - - let count = match *self { - Pop(_) => 0, + match *self { + Pop(_) => Vec::new(), SetReg(_, op0) | Load(_, op0) @@ -464,10 +659,16 @@ impl LowLevelILFlagWriteOp { | Zx(_, op0) | LowPart(_, op0) | BoolToInt(_, op0) - | FloatToInt(_, op0) => { - operands[0] = op0.into(); - 1 - } + | FloatToInt(_, op0) + | Fsqrt(_, op0) + | Fneg(_, op0) + | Fabs(_, op0) + | IntToFloat(_, op0) + | FloatConv(_, op0) + | RoundToInt(_, op0) + | Floor(_, op0) + | Ceil(_, op0) + | Ftrunc(_, op0) => vec![op0.into()], SetRegSplit(_, op0, op1) | Sub(_, op0, op1) @@ -497,24 +698,46 @@ impl LowLevelILFlagWriteOp { | ModuDp(_, op0, op1) | ModsDp(_, op0, op1) | TestBit(_, op0, op1) - | AddOverflow(_, op0, op1) => { - operands[0] = op0.into(); - operands[1] = op1.into(); - 2 - } + | AddOverflow(_, op0, op1) + | CmpE(_, op0, op1) + | CmpNe(_, op0, op1) + | CmpSlt(_, op0, op1) + | CmpUlt(_, op0, op1) + | CmpSle(_, op0, op1) + | CmpUle(_, op0, op1) + | CmpSge(_, op0, op1) + | CmpUge(_, op0, op1) + | CmpSgt(_, op0, op1) + | CmpUgt(_, op0, op1) + | Fadd(_, op0, op1) + | Fsub(_, op0, op1) + | Fmul(_, op0, op1) + | Fdiv(_, op0, op1) + | FcmpE(_, op0, op1) + | FcmpNE(_, op0, op1) + | FcmpLT(_, op0, op1) + | FcmpLE(_, op0, op1) + | FcmpGE(_, op0, op1) + | FcmpGT(_, op0, op1) + | FcmpO(_, op0, op1) + | FcmpUO(_, op0, op1) => vec![op0.into(), op1.into()], Adc(_, op0, op1, op2) | Sbb(_, op0, op1, op2) | Rlc(_, op0, op1, op2) - | Rrc(_, op0, op1, op2) => { - operands[0] = op0.into(); - operands[1] = op1.into(); - operands[2] = op2.into(); - 3 + | Rrc(_, op0, op1, op2) => vec![op0.into(), op1.into(), op2.into()], + + Intrinsic(_, id, ref params) => { + let id = BNRegisterOrConstant { + constant: true, + reg: 0, + value: id.0 as u64, + }; + std::iter::once(id) + .chain(params.iter().map(|¶m| param.into())) + .collect() } - }; - - (count, operands) + } } } @@ -528,7 +751,7 @@ where A: 'func + Architecture, { let (size, operation) = op.size_and_op(); - let (count, operands) = op.raw_operands(); + let mut operands = op.raw_operands(); let expr_idx = unsafe { use binaryninjacore_sys::BNGetDefaultArchitectureFlagWriteLowLevelIL; @@ -537,8 +760,8 @@ where operation, size, role, - operands.as_ptr() as *mut _, - count, + operands.as_mut_ptr(), + operands.len(), il.handle, ) }; From ff2b87629c07efb37a3d92bcbf8607a634549fe6 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Mon, 19 Oct 2026 13:36:40 -0700 Subject: [PATCH 3/4] Fix Rust IL bindings decoding operations incorrectly Rust's IL bindings read several ops' operands from the wrong slots, and decoded ASSERT and FORCE_VER as Undef. The LLIL visitor also missed some operands of intrinsics and the SSA calls. LLIL comparisons reported a size of 0, unlike the C++ and Python bindings. The rlc and rrc lifters took no carry, and the float conversion lifters lifted their source at the wrong width. Now each op decodes correctly, and ASSERT and FORCE_VER have their own variants. MLIL's unused NotYetImplemented and CallOutput variants are gone. Comparisons report their size like any other operation. rlc and rrc take a carry, so msp430 now passes its carry flag. --- arch/msp430/src/lift.rs | 28 +++++----- rust/binaryninjacore-sys/build.rs | 1 + rust/examples/medium_level_il.rs | 8 +++ rust/src/high_level_il/instruction.rs | 48 ++++++++++++++--- rust/src/high_level_il/lift.rs | 46 ++++++++++++++-- rust/src/high_level_il/operation.rs | 40 +++++++++++++- rust/src/low_level_il/expression.rs | 22 +++----- rust/src/low_level_il/instruction.rs | 29 ++++++---- rust/src/low_level_il/lifting.rs | 10 ++-- rust/src/low_level_il/operation.rs | 71 ++++++------------------- rust/src/medium_level_il/instruction.rs | 65 +++++++++++++++++----- rust/src/medium_level_il/lift.rs | 47 ++++++++++++---- rust/src/medium_level_il/operation.rs | 57 +++++++++++++++----- 13 files changed, 328 insertions(+), 144 deletions(-) diff --git a/arch/msp430/src/lift.rs b/arch/msp430/src/lift.rs index cad7029776..529179e975 100644 --- a/arch/msp430/src/lift.rs +++ b/arch/msp430/src/lift.rs @@ -172,12 +172,14 @@ pub(crate) fn lift_instruction(inst: &Instruction, addr: u64, il: &LowLevelILMut let src = il.const_int(size, 1); let dest = lift_source_operand(inst.source(), size, il); let op = match inst.operand_width() { - Some(OperandWidth::Byte) => { - il.zx(2, il.rrc(size, dest, src).with_flag_write(FlagWrite::All)) - } - Some(OperandWidth::Word) | None => { - il.rrc(size, dest, src).with_flag_write(FlagWrite::All) - } + Some(OperandWidth::Byte) => il.zx( + 2, + il.rrc(size, dest, src, il.flag(Flag::C)) + .with_flag_write(FlagWrite::All), + ), + Some(OperandWidth::Word) | None => il + .rrc(size, dest, src, il.flag(Flag::C)) + .with_flag_write(FlagWrite::All), }; one_operand!(inst.source(), il, op); } @@ -580,12 +582,14 @@ pub(crate) fn lift_instruction(inst: &Instruction, addr: u64, il: &LowLevelILMut let src = il.const_int(size, 1); let dest = lift_source_operand(&inst.destination().unwrap(), size, il); let op = match inst.operand_width() { - Some(OperandWidth::Byte) => { - il.zx(2, il.rlc(size, dest, src).with_flag_write(FlagWrite::All)) - } - Some(OperandWidth::Word) | None => { - il.rlc(size, dest, src).with_flag_write(FlagWrite::All) - } + Some(OperandWidth::Byte) => il.zx( + 2, + il.rlc(size, dest, src, il.flag(Flag::C)) + .with_flag_write(FlagWrite::All), + ), + Some(OperandWidth::Word) | None => il + .rlc(size, dest, src, il.flag(Flag::C)) + .with_flag_write(FlagWrite::All), }; emulated!(inst, il, op); } diff --git a/rust/binaryninjacore-sys/build.rs b/rust/binaryninjacore-sys/build.rs index 41ff06c662..e77c9d8daa 100644 --- a/rust/binaryninjacore-sys/build.rs +++ b/rust/binaryninjacore-sys/build.rs @@ -122,6 +122,7 @@ fn main() { .allowlist_var("BN_CURRENT_CORE_ABI_VERSION") .allowlist_var("BN_MINIMUM_CORE_ABI_VERSION") .allowlist_var("MAX_RELOCATION_SIZE") + .allowlist_type("BNForceVersionReason") .allowlist_type("BNLinearSweepAnalysisCapability") .allowlist_type("BNMcpToolAnnotation") .raw_line(format!( diff --git a/rust/examples/medium_level_il.rs b/rust/examples/medium_level_il.rs index 4e9cac8375..9c9aa44c32 100644 --- a/rust/examples/medium_level_il.rs +++ b/rust/examples/medium_level_il.rs @@ -82,6 +82,14 @@ mod visitor { print_indent(indent); println!("float {:e}", float); } + ForceVersionReason(reason) => { + print_indent(indent); + println!("force version reason {:?}", reason); + } + PossibleValueSet(values) => { + print_indent(indent); + println!("possible values {:?}", values); + } Expr(expr) => print_il_expr(&expr, indent), Var(var) => { print_indent(indent); diff --git a/rust/src/high_level_il/instruction.rs b/rust/src/high_level_il/instruction.rs index a499e5265d..2c3a305040 100644 --- a/rust/src/high_level_il/instruction.rs +++ b/rust/src/high_level_il/instruction.rs @@ -9,7 +9,7 @@ use crate::confidence::Conf; use crate::disassembly::DisassemblyTextLine; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; use crate::types::Type; -use crate::variable::{ConstantData, RegisterValue, SSAVariable, Variable}; +use crate::variable::{ConstantData, PossibleValueSet, RegisterValue, SSAVariable, Variable}; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct HighLevelInstructionIndex(pub usize); @@ -121,7 +121,6 @@ impl HighLevelILInstruction { HLIL_UNREACHABLE => Op::Unreachable, HLIL_BP => Op::Bp, HLIL_UNDEF => Op::Undef, - HLIL_FORCE_VER | HLIL_FORCE_VER_SSA | HLIL_ASSERT | HLIL_ASSERT_SSA => Op::Undef, HLIL_UNIMPL => Op::Unimpl, HLIL_ADC => Op::Adc(BinaryOpCarry { left: HighLevelExpressionIndex::from(op.operands[0]), @@ -348,6 +347,14 @@ impl HighLevelILInstruction { src_memory: op.operands[1], index: HighLevelExpressionIndex::from(op.operands[2]), }), + HLIL_ASSERT => Op::Assert(Assert { + src: get_var(op.operands[0]), + constraint_index: op.operands[1] as usize, + }), + HLIL_ASSERT_SSA => Op::AssertSsa(AssertSsa { + src: get_var_ssa((op.operands[0], op.operands[1] as usize)), + constraint_index: op.operands[2] as usize, + }), HLIL_ASSIGN => Op::Assign(Assign { dest: HighLevelExpressionIndex::from(op.operands[0]), src: HighLevelExpressionIndex::from(op.operands[1]), @@ -524,6 +531,14 @@ impl HighLevelILInstruction { update: HighLevelExpressionIndex::from(op.operands[3]), body: HighLevelExpressionIndex::from(op.operands[4]), }), + HLIL_FORCE_VER => Op::ForceVer(ForceVer { + dest: get_var(op.operands[0]), + src: get_var(op.operands[1]), + }), + HLIL_FORCE_VER_SSA => Op::ForceVerSsa(ForceVerSsa { + dest: get_var_ssa((op.operands[0], op.operands[1] as usize)), + src: get_var_ssa((op.operands[2], op.operands[3] as usize)), + }), HLIL_GOTO => Op::Goto(Label { target: op.operands[0], }), @@ -641,9 +656,9 @@ impl HighLevelILInstruction { body: HighLevelExpressionIndex::from(op.operands[2]), }), HLIL_DO_WHILE_SSA => Op::DoWhileSsa(WhileSsa { - condition_phi: HighLevelExpressionIndex::from(op.operands[0]), - condition: HighLevelExpressionIndex::from(op.operands[1]), - body: HighLevelExpressionIndex::from(op.operands[2]), + body: HighLevelExpressionIndex::from(op.operands[0]), + condition_phi: HighLevelExpressionIndex::from(op.operands[1]), + condition: HighLevelExpressionIndex::from(op.operands[2]), }), }; Self { @@ -688,6 +703,13 @@ impl HighLevelILInstruction { .collect() } + fn get_constraint(&self, constraint_index: usize) -> PossibleValueSet { + let value = unsafe { + BNGetCachedHighLevelILPossibleValueSet(self.function.handle, constraint_index) + }; + PossibleValueSet::from_owned_core_raw(value) + } + pub fn lift(&self) -> HighLevelILLiftedInstruction { use HighLevelILInstructionKind::*; use HighLevelILLiftedInstructionKind as Lifted; @@ -765,6 +787,14 @@ impl HighLevelILInstruction { src_memory: op.src_memory, index: self.lift_operand(op.index), }), + Assert(op) => Lifted::Assert(LiftedAssert { + src: op.src, + constraint: self.get_constraint(op.constraint_index), + }), + AssertSsa(op) => Lifted::AssertSsa(LiftedAssertSsa { + src: op.src, + constraint: self.get_constraint(op.constraint_index), + }), Assign(op) => Lifted::Assign(LiftedAssign { dest: self.lift_operand(op.dest), src: self.lift_operand(op.src), @@ -898,6 +928,8 @@ impl HighLevelILInstruction { update: self.lift_operand(op.update), body: self.lift_operand(op.body), }), + ForceVer(op) => Lifted::ForceVer(op), + ForceVerSsa(op) => Lifted::ForceVerSsa(op), If(op) => Lifted::If(LiftedIf { condition: self.lift_operand(op.condition), cond_true: self.lift_operand(op.cond_true), @@ -1228,6 +1260,8 @@ pub enum HighLevelILInstructionKind { FcmpUo(BinaryOp), ArrayIndex(ArrayIndex), ArrayIndexSsa(ArrayIndexSsa), + Assert(Assert), + AssertSsa(AssertSsa), Assign(Assign), AssignMemSsa(AssignMemSsa), AssignUnpack(AssignUnpack), @@ -1275,6 +1309,8 @@ pub enum HighLevelILInstructionKind { FloatConst(FloatConst), For(ForLoop), ForSsa(ForLoopSsa), + ForceVer(ForceVer), + ForceVerSsa(ForceVerSsa), Goto(Label), Label(Label), If(If), @@ -1319,7 +1355,7 @@ fn get_var(id: u64) -> Variable { } fn get_member_index(idx: u64) -> Option { - (idx as i64 > 0).then_some(idx as usize) + (idx as i64 >= 0).then_some(idx as usize) } fn get_var_ssa(input: (u64, usize)) -> SSAVariable { diff --git a/rust/src/high_level_il/lift.rs b/rust/src/high_level_il/lift.rs index b1dec190e7..8cfde71664 100644 --- a/rust/src/high_level_il/lift.rs +++ b/rust/src/high_level_il/lift.rs @@ -4,7 +4,7 @@ use std::fmt::{Debug, Formatter}; use crate::architecture::CoreIntrinsic; use crate::rc::Ref; -use crate::variable::{ConstantData, SSAVariable, Variable}; +use crate::variable::{ConstantData, PossibleValueSet, SSAVariable, Variable}; #[derive(Clone, Debug)] pub enum HighLevelILLiftedOperand { @@ -17,6 +17,7 @@ pub enum HighLevelILLiftedOperand { Intrinsic(CoreIntrinsic), Label(GotoLabel), MemberIndex(Option), + PossibleValueSet(PossibleValueSet), Var(Variable), VarSsa(SSAVariable), VarSsaList(Vec), @@ -101,6 +102,8 @@ pub enum HighLevelILLiftedInstructionKind { FcmpUo(LiftedBinaryOp), ArrayIndex(LiftedArrayIndex), ArrayIndexSsa(LiftedArrayIndexSsa), + Assert(LiftedAssert), + AssertSsa(LiftedAssertSsa), Assign(LiftedAssign), AssignMemSsa(LiftedAssignMemSsa), AssignUnpack(LiftedAssignUnpack), @@ -148,6 +151,8 @@ pub enum HighLevelILLiftedInstructionKind { FloatConst(FloatConst), For(LiftedForLoop), ForSsa(LiftedForLoopSsa), + ForceVer(ForceVer), + ForceVerSsa(ForceVerSsa), Goto(LiftedLabel), Label(LiftedLabel), If(LiftedIf), @@ -245,6 +250,8 @@ impl HighLevelILLiftedInstruction { FcmpUo(_) => "FcmpUo", ArrayIndex(_) => "ArrayIndex", ArrayIndexSsa(_) => "ArrayIndexSsa", + Assert(_) => "Assert", + AssertSsa(_) => "AssertSsa", Assign(_) => "Assign", AssignMemSsa(_) => "AssignMemSsa", AssignUnpack(_) => "AssignUnpack", @@ -292,6 +299,8 @@ impl HighLevelILLiftedInstruction { FloatConst(_) => "FloatConst", For(_) => "For", ForSsa(_) => "ForSsa", + ForceVer(_) => "ForceVer", + ForceVerSsa(_) => "ForceVerSsa", Goto(_) => "Goto", Label(_) => "Label", If(_) => "If", @@ -353,6 +362,20 @@ impl HighLevelILLiftedInstruction { ("src_memory", Operand::Int(op.src_memory)), ("index", Operand::Expr(*op.index.clone())), ], + Assert(op) => vec![ + ("src", Operand::Var(op.src)), + ( + "constraint", + Operand::PossibleValueSet(op.constraint.clone()), + ), + ], + AssertSsa(op) => vec![ + ("src", Operand::VarSsa(op.src)), + ( + "constraint", + Operand::PossibleValueSet(op.constraint.clone()), + ), + ], Assign(op) => vec![ ("dest", Operand::Expr(*op.dest.clone())), ("src", Operand::Expr(*op.src.clone())), @@ -428,6 +451,14 @@ impl HighLevelILLiftedInstruction { ("update", Operand::Expr(*op.update.clone())), ("body", Operand::Expr(*op.body.clone())), ], + ForceVer(op) => vec![ + ("dest", Operand::Var(op.dest)), + ("src", Operand::Var(op.src)), + ], + ForceVerSsa(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("src", Operand::VarSsa(op.src)), + ], Goto(op) | Label(op) => vec![("target", Operand::Label(op.target.clone()))], If(op) => vec![ ("condition", Operand::Expr(*op.condition.clone())), @@ -495,15 +526,24 @@ impl HighLevelILLiftedInstruction { ("dest", Operand::VarSsa(op.dest)), ("prev", Operand::VarSsa(op.prev)), ], - While(op) | DoWhile(op) => vec![ + While(op) => vec![ ("condition", Operand::Expr(*op.condition.clone())), ("body", Operand::Expr(*op.body.clone())), ], - WhileSsa(op) | DoWhileSsa(op) => vec![ + DoWhile(op) => vec![ + ("body", Operand::Expr(*op.body.clone())), + ("condition", Operand::Expr(*op.condition.clone())), + ], + WhileSsa(op) => vec![ ("condition_phi", Operand::Expr(*op.condition_phi.clone())), ("condition", Operand::Expr(*op.condition.clone())), ("body", Operand::Expr(*op.body.clone())), ], + DoWhileSsa(op) => vec![ + ("body", Operand::Expr(*op.body.clone())), + ("condition_phi", Operand::Expr(*op.condition_phi.clone())), + ("condition", Operand::Expr(*op.condition.clone())), + ], } } } diff --git a/rust/src/high_level_il/operation.rs b/rust/src/high_level_il/operation.rs index 1d545a409e..e4515d0de6 100644 --- a/rust/src/high_level_il/operation.rs +++ b/rust/src/high_level_il/operation.rs @@ -7,7 +7,7 @@ use crate::architecture::CoreIntrinsic; use crate::function::Function; use crate::rc::Ref; use crate::string::{BnString, IntoCStr}; -use crate::variable::{ConstantData, SSAVariable, Variable}; +use crate::variable::{ConstantData, PossibleValueSet, SSAVariable, Variable}; #[derive(Clone, PartialEq, Eq)] pub struct GotoLabel { @@ -93,6 +93,30 @@ pub struct LiftedArrayIndexSsa { pub index: Box, } +// ASSERT +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Assert { + pub src: Variable, + pub constraint_index: usize, +} +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LiftedAssert { + pub src: Variable, + pub constraint: PossibleValueSet, +} + +// ASSERT_SSA +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct AssertSsa { + pub src: SSAVariable, + pub constraint_index: usize, +} +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LiftedAssertSsa { + pub src: SSAVariable, + pub constraint: PossibleValueSet, +} + // ASSIGN #[derive(Debug, Copy, Clone)] pub struct Assign { @@ -312,6 +336,20 @@ pub struct LiftedForLoopSsa { pub body: Box, } +// FORCE_VER +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ForceVer { + pub dest: Variable, + pub src: Variable, +} + +// FORCE_VER_SSA +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ForceVerSsa { + pub dest: SSAVariable, + pub src: SSAVariable, +} + // GOTO, LABEL #[derive(Debug, Copy, Clone)] pub struct Label { diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index 233b06a55f..84c5f877af 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -269,7 +269,6 @@ where ExternPtr(Operation<'func, M, F, operation::Extern>), RegStackPop(Operation<'func, M, F, operation::RegStackPop>), - RegStackFreeReg(Operation<'func, M, F, operation::RegStackPop>), CallOutputSsa(Operation<'func, M, F, operation::CallOutputSsa>), CallParamSsa(Operation<'func, M, F, operation::CallParamSsa>), @@ -429,9 +428,6 @@ where LLIL_REG_STACK_POP => { LowLevelILExpressionKind::RegStackPop(Operation::new(function, op, index)) } - LLIL_REG_STACK_FREE_REG => { - LowLevelILExpressionKind::RegStackFreeReg(Operation::new(function, op, index)) - } LLIL_CALL_OUTPUT_SSA => { LowLevelILExpressionKind::CallOutputSsa(Operation::new(function, op, index)) @@ -572,7 +568,7 @@ where } } - /// Returns the size of the result of this expression + /// Returns the size of the operation in bytes /// /// If the expression is malformed or is `Unimpl` there /// is no meaningful size associated with the result. @@ -582,10 +578,7 @@ where match *self { Undef(..) | Unimpl(..) => None, - FlagCond(..) | FlagGroup(..) | CmpE(..) | CmpNe(..) | CmpSlt(..) | CmpUlt(..) - | CmpSle(..) | CmpUle(..) | CmpSge(..) | CmpUge(..) | CmpSgt(..) | CmpUgt(..) => { - Some(0) - } + FlagCond(..) | FlagGroup(..) => Some(0), _ => Some(self.raw_struct().size), } @@ -628,9 +621,8 @@ where | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) | DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) - | MinSigned(ref op) | MaxSigned(ref op) | MinUnsigned(ref op) | MaxUnsigned(ref op) => { - Some(op) - } + | MinSigned(ref op) | MaxSigned(ref op) | MinUnsigned(ref op) | MaxUnsigned(ref op) + | TestBit(ref op) | AddOverflow(ref op) => Some(op), _ => None, } } @@ -723,8 +715,8 @@ where // Do not have any sub expressions. Pop(_) | Reg(_) | RegSsa(_) | RegPartialSsa(_) | RegSplit(_) | RegSplitSsa(_) | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) | ExternPtr(_) | FlagCond(_) - | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) | RegStackFreeReg(_) - | CallOutputSsa(_) | CallStackSsa(_) | FloatConst(_) => {} + | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) | CallOutputSsa(_) + | CallStackSsa(_) | FloatConst(_) => {} } VisitorAction::Sibling @@ -773,7 +765,6 @@ where ExternPtr(ref op) => &op.op, RegStackPop(ref op) => &op.op, - RegStackFreeReg(ref op) => &op.op, CallOutputSsa(ref op) => &op.op, CallParamSsa(ref op) => &op.op, @@ -848,7 +839,6 @@ impl LowLevelILExpressionKind<'_, Mutable, NonSSA> { ExternPtr(ref op) => op.flag_write(), RegStackPop(ref op) => op.flag_write(), - RegStackFreeReg(ref op) => op.flag_write(), CallOutputSsa(ref op) => op.flag_write(), CallParamSsa(ref op) => op.flag_write(), diff --git a/rust/src/low_level_il/instruction.rs b/rust/src/low_level_il/instruction.rs index 720117fbb5..83d4c2b109 100644 --- a/rust/src/low_level_il/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -244,6 +244,7 @@ where Push(Operation<'func, M, F, operation::UnaryOp>), RegStackPush(Operation<'func, M, F, operation::RegStackPush>), + RegStackFreeReg(Operation<'func, M, F, operation::RegStackFreeReg>), Jump(Operation<'func, M, F, operation::Jump>), JumpTo(Operation<'func, M, F, operation::JumpTo>), @@ -324,6 +325,9 @@ where LLIL_REG_STACK_PUSH => { LowLevelILInstructionKind::RegStackPush(Operation::new(function, op, expr_index)) } + LLIL_REG_STACK_FREE_REG => { + LowLevelILInstructionKind::RegStackFreeReg(Operation::new(function, op, expr_index)) + } LLIL_JUMP => LowLevelILInstructionKind::Jump(Operation::new(function, op, expr_index)), LLIL_JUMP_TO => { @@ -410,7 +414,11 @@ where SetRegSsa(ref op) => visit!(&op.source_expr()), SetRegPartialSsa(ref op) => visit!(&op.source_expr()), SetRegSplit(ref op) => visit!(&op.source_expr()), - SetRegSplitSsa(ref op) => visit!(&op.source_expr()), + SetRegSplitSsa(ref op) => { + visit!(&op.dest_expr_high()); + visit!(&op.dest_expr_low()); + visit!(&op.source_expr()); + } SetFlag(ref op) => visit!(&op.source_expr()), SetFlagSsa(ref op) => visit!(&op.source_expr()), Store(ref op) => { @@ -427,21 +435,24 @@ where JumpTo(ref op) => visit!(&op.target()), SyscallSsa(ref op) => { visit!(&op.output_expr()); - visit!(&op.param_expr()); visit!(&op.stack_expr()); + visit!(&op.param_expr()); } Call(ref op) | TailCall(ref op) => visit!(&op.target()), - CallSsa(ref op) | TailCallSsa(ref op) => visit!(&op.target()), + CallSsa(ref op) | TailCallSsa(ref op) => { + visit!(&op.output_expr()); + visit!(&op.target()); + visit!(&op.stack_expr()); + visit!(&op.param_expr()); + } Ret(ref op) => visit!(&op.target()), If(ref op) => visit!(&op.condition()), - Intrinsic(ref _op) => { - // TODO: Visit when we support expression lists - } + Intrinsic(ref op) => visit!(&op.inputs()), Value(e) => visit!(e), // Do not have any sub expressions. - Nop(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_) | Undef(_) | Assert(_) - | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_) | RegPhi(_) | FlagPhi(_) - | MemPhi(_) => {} + Nop(_) | RegStackFreeReg(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_) + | Undef(_) | Assert(_) | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_) + | RegPhi(_) | FlagPhi(_) | MemPhi(_) => {} } VisitorAction::Sibling diff --git a/rust/src/low_level_il/lifting.rs b/rust/src/low_level_il/lifting.rs index 8dd778b533..ac939c4d69 100644 --- a/rust/src/low_level_il/lifting.rs +++ b/rust/src/low_level_il/lifting.rs @@ -1758,9 +1758,9 @@ impl LowLevelILMutableFunction { binary_op_lifter!(asr, LLIL_ASR); binary_op_lifter!(rol, LLIL_ROL); - binary_op_lifter!(rlc, LLIL_RLC); + binary_op_carry_lifter!(rlc, LLIL_RLC); binary_op_lifter!(ror, LLIL_ROR); - binary_op_lifter!(rrc, LLIL_RRC); + binary_op_carry_lifter!(rrc, LLIL_RRC); binary_op_lifter!(mul, LLIL_MUL); binary_op_lifter!(muls_dp, LLIL_MULS_DP); binary_op_lifter!(mulu_dp, LLIL_MULU_DP); @@ -1807,9 +1807,9 @@ impl LowLevelILMutableFunction { sized_unary_op_lifter!(fsqrt, LLIL_FSQRT, ValueExpr); sized_unary_op_lifter!(fneg, LLIL_FNEG, ValueExpr); sized_unary_op_lifter!(fabs, LLIL_FABS, ValueExpr); - sized_unary_op_lifter!(float_to_int, LLIL_FLOAT_TO_INT, ValueExpr); - sized_unary_op_lifter!(int_to_float, LLIL_INT_TO_FLOAT, ValueExpr); - sized_unary_op_lifter!(float_conv, LLIL_FLOAT_CONV, ValueExpr); + size_changing_unary_op_lifter!(float_to_int, LLIL_FLOAT_TO_INT, ValueExpr); + size_changing_unary_op_lifter!(int_to_float, LLIL_INT_TO_FLOAT, ValueExpr); + size_changing_unary_op_lifter!(float_conv, LLIL_FLOAT_CONV, ValueExpr); sized_unary_op_lifter!(round_to_int, LLIL_ROUND_TO_INT, ValueExpr); sized_unary_op_lifter!(floor, LLIL_FLOOR, ValueExpr); sized_unary_op_lifter!(ceil, LLIL_CEIL, ValueExpr); diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index 0b86346414..71391a5c66 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -13,8 +13,8 @@ // limitations under the License. use binaryninjacore_sys::{ - BNGetCachedLowLevelILPossibleValueSet, BNGetLowLevelILByIndex, BNLowLevelILFreeOperandList, - BNLowLevelILGetOperandList, BNLowLevelILInstruction, + BNGetCachedLowLevelILPossibleValueSet, BNLowLevelILFreeOperandList, BNLowLevelILGetOperandList, + BNLowLevelILInstruction, }; use super::*; @@ -248,7 +248,7 @@ impl From for IntrinsicOutput { } } -impl Operation<'_, M, F, Intrinsic> +impl<'func, M, F> Operation<'func, M, F, Intrinsic> where M: FunctionMutability, F: FunctionForm, @@ -287,7 +287,7 @@ where /// /// This will just be a CallParamSsa expression. #[inline] - pub fn inputs(&self) -> LowLevelILExpression<'_, M, F, ValueExpr> { + pub fn inputs(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[3] as usize), @@ -902,12 +902,12 @@ where self.op.size } - pub fn low_reg(&self) -> LowLevelILRegisterKind { + pub fn high_reg(&self) -> LowLevelILRegisterKind { let raw_id = RegisterId(self.op.operands[0] as u32); LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") } - pub fn high_reg(&self) -> LowLevelILRegisterKind { + pub fn low_reg(&self) -> LowLevelILRegisterKind { let raw_id = RegisterId(self.op.operands[1] as u32); LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") } @@ -922,8 +922,8 @@ where f.debug_struct("RegSplit") .field("address", &self.address()) .field("size", &self.size()) - .field("low_reg", &self.low_reg()) .field("high_reg", &self.high_reg()) + .field("low_reg", &self.low_reg()) .finish() } } @@ -940,7 +940,7 @@ where self.op.size } - pub fn low_reg(&self) -> LowLevelILSSARegisterKind { + pub fn high_reg(&self) -> LowLevelILSSARegisterKind { let raw_id = RegisterId(self.op.operands[0] as u32); let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) .expect("Bad register ID"); @@ -948,7 +948,7 @@ where LowLevelILSSARegisterKind::new_full(reg_kind, version) } - pub fn high_reg(&self) -> LowLevelILSSARegisterKind { + pub fn low_reg(&self) -> LowLevelILSSARegisterKind { let raw_id = RegisterId(self.op.operands[2] as u32); let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) .expect("Bad register ID"); @@ -966,8 +966,8 @@ where f.debug_struct("RegSplitSsa") .field("address", &self.address()) .field("size", &self.size()) - .field("low_reg", &self.low_reg()) .field("high_reg", &self.high_reg()) + .field("low_reg", &self.low_reg()) .finish() } } @@ -1157,34 +1157,6 @@ where // LLIL_JUMP_TO pub struct JumpTo; -struct TargetListIter<'func, M, F> -where - M: FunctionMutability, - F: FunctionForm, -{ - function: &'func LowLevelILFunction, - cursor: BNLowLevelILInstruction, - cursor_operand: usize, -} - -impl TargetListIter<'_, M, F> -where - M: FunctionMutability, - F: FunctionForm, -{ - fn next(&mut self) -> u64 { - if self.cursor_operand >= 3 { - self.cursor = unsafe { - BNGetLowLevelILByIndex(self.function.handle, self.cursor.operands[3] as usize) - }; - self.cursor_operand = 0; - } - let result = self.cursor.operands[self.cursor_operand]; - self.cursor_operand += 1; - result - } -} - impl<'func, M, F> Operation<'func, M, F, JumpTo> where M: FunctionMutability, @@ -1198,23 +1170,12 @@ where } pub fn target_list(&self) -> BTreeMap { - let mut result = BTreeMap::new(); - let count = self.op.operands[1] as usize / 2; - let mut list = TargetListIter { - function: self.function, - cursor: unsafe { - BNGetLowLevelILByIndex(self.function.handle, self.op.operands[2] as usize) - }, - cursor_operand: 0, - }; - - for _ in 0..count { - let value = list.next(); - let target = LowLevelInstructionIndex(list.next() as usize); - result.insert(value, target); - } - - result + self.get_operand_list(1) + .as_chunks::<2>() + .0 + .iter() + .map(|pair| (pair[0], LowLevelInstructionIndex(pair[1] as usize))) + .collect() } } diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs index 69936e6038..3276038719 100644 --- a/rust/src/medium_level_il/instruction.rs +++ b/rust/src/medium_level_il/instruction.rs @@ -121,7 +121,28 @@ impl MediumLevelILInstruction { MLIL_NORET => Op::Noret, MLIL_BP => Op::Bp, MLIL_UNDEF => Op::Undef, - MLIL_ASSERT | MLIL_ASSERT_SSA | MLIL_FORCE_VER | MLIL_FORCE_VER_SSA => Op::Undef, + MLIL_ASSERT => Op::Assert(Assert { + src: get_var(op.operands[0]), + constraint_index: op.operands[1] as usize, + }), + MLIL_ASSERT_SSA => Op::AssertSsa(AssertSsa { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), + constraint_index: op.operands[2] as usize, + }), + MLIL_FORCE_VER => Op::ForceVer(ForceVer { + dest: get_var(op.operands[0]), + src: get_var(op.operands[1]), + reason: unsafe { + std::mem::transmute::(op.operands[2] as u8) + }, + }), + MLIL_FORCE_VER_SSA => Op::ForceVerSsa(ForceVerSsa { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + src: get_var_ssa(op.operands[2], op.operands[3] as usize), + reason: unsafe { + std::mem::transmute::(op.operands[4] as u8) + }, + }), MLIL_UNIMPL => Op::Unimpl, MLIL_IF => Op::If(MediumLevelILOperationIf { condition: MediumLevelExpressionIndex::from(op.operands[0]), @@ -474,8 +495,8 @@ impl MediumLevelILInstruction { first_param: op.operands[4] as usize, }), MLIL_CALL_PARAM => Op::CallParam(CallParam { - first_param: op.operands[0] as usize, - num_params: op.operands[1] as usize, + num_params: op.operands[0] as usize, + first_param: op.operands[1] as usize, }), MLIL_CALL_OUTPUT_SSA => Op::CallOutputSsa(CallOutputSsa { dest_memory: op.operands[0], @@ -524,8 +545,8 @@ impl MediumLevelILInstruction { MLIL_MEMORY_INTRINSIC_OUTPUT_SSA => { Op::MemoryIntrinsicOutputSsa(MemoryIntrinsicOutputSsa { dest_memory: op.operands[0], - first_output: op.operands[1] as usize, - num_outputs: op.operands[2] as usize, + num_outputs: op.operands[1] as usize, + first_output: op.operands[2] as usize, }) } MLIL_CALL_SSA => Op::CallSsa(CallSsa { @@ -823,7 +844,6 @@ impl MediumLevelILInstruction { Bp => Lifted::Bp, Undef => Lifted::Undef, Unimpl => Lifted::Unimpl, - NotYetImplemented => Lifted::NotYetImplemented, If(op) => Lifted::If(LiftedIf { condition: self.lift_operand(op.condition), dest_true: op.dest_true, @@ -938,6 +958,26 @@ impl MediumLevelILInstruction { low: op.low, src: self.lift_operand(op.src), }), + Assert(op) => Lifted::Assert(LiftedAssert { + src: op.src, + constraint: PossibleValueSet::from_owned_core_raw(unsafe { + BNGetCachedMediumLevelILPossibleValueSet( + self.function.handle, + op.constraint_index, + ) + }), + }), + ForceVer(op) => Lifted::ForceVer(op), + AssertSsa(op) => Lifted::AssertSsa(LiftedAssertSsa { + src: op.src, + constraint: PossibleValueSet::from_owned_core_raw(unsafe { + BNGetCachedMediumLevelILPossibleValueSet( + self.function.handle, + op.constraint_index, + ) + }), + }), + ForceVerSsa(op) => Lifted::ForceVerSsa(op), Add(op) => Lifted::Add(self.lift_binary_op(op)), Sub(op) => Lifted::Sub(self.lift_binary_op(op)), @@ -995,15 +1035,12 @@ impl MediumLevelILInstruction { Rrc(op) => Lifted::Rrc(self.lift_binary_op_carry(op)), Call(op) => Lifted::Call(self.lift_call(op)), - CallOutput(_op) => Lifted::CallOutput(LiftedCallOutput { - output: self.get_var_list(0), - }), CallParam(_op) => Lifted::CallParam(LiftedCallParam { params: self.get_expr_list(0).iter().map(|i| i.lift()).collect(), }), CallOutputSsa(op) => Lifted::CallOutputSsa(LiftedCallOutputSsa { dest_memory: op.dest_memory, - output: self.get_ssa_var_list(1), + output: self.get_expr_list(1).iter().map(|i| i.lift()).collect(), }), CallParamSsa(op) => Lifted::CallParamSsa(LiftedCallParamSsa { src_memory: op.src_memory, @@ -1844,8 +1881,12 @@ pub enum MediumLevelILInstructionKind { MemPhi(MemPhi), VarSplit(VarSplit), SetVarSplit(SetVarSplit), + Assert(Assert), + ForceVer(ForceVer), VarSplitSsa(VarSplitSsa), SetVarSplitSsa(SetVarSplitSsa), + AssertSsa(AssertSsa), + ForceVerSsa(ForceVerSsa), Add(BinaryOp), Sub(BinaryOp), And(BinaryOp), @@ -1900,7 +1941,6 @@ pub enum MediumLevelILInstructionKind { Rlc(BinaryOpCarry), Rrc(BinaryOpCarry), Call(Call), - CallOutput(CallOutput), CallParam(CallParam), CallOutputSsa(CallOutputSsa), CallParamSsa(CallParamSsa), @@ -1969,9 +2009,6 @@ pub enum MediumLevelILInstructionKind { VarOutputAliasedField(VarOutputAliasedField), Trap(Trap), BlockToExpand(BlockToExpand), - // A placeholder for instructions that the Rust bindings do not yet support. - // Distinct from `Unimpl` as that is a valid instruction. - NotYetImplemented, } fn get_float(value: u64, size: usize) -> f64 { diff --git a/rust/src/medium_level_il/lift.rs b/rust/src/medium_level_il/lift.rs index f886d93a94..addbf525e1 100644 --- a/rust/src/medium_level_il/lift.rs +++ b/rust/src/medium_level_il/lift.rs @@ -2,7 +2,7 @@ use super::operation::*; use super::{MediumLevelExpressionIndex, MediumLevelILFunction, MediumLevelInstructionIndex}; use crate::architecture::CoreIntrinsic; use crate::rc::Ref; -use crate::variable::{ConstantData, SSAVariable, Variable}; +use crate::variable::{ConstantData, PossibleValueSet, SSAVariable, Variable}; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; @@ -13,8 +13,10 @@ pub enum MediumLevelILLiftedOperand { Expr(MediumLevelILLiftedInstruction), ExprList(Vec), Float(f64), + ForceVersionReason(ForceVersionReason), Int(u64), IntList(Vec), + PossibleValueSet(PossibleValueSet), TargetMap(BTreeMap), Var(Variable), VarList(Vec), @@ -79,8 +81,12 @@ pub enum MediumLevelILLiftedInstructionKind { MemPhi(LiftedMemPhi), VarSplit(VarSplit), SetVarSplit(LiftedSetVarSplit), + Assert(LiftedAssert), + ForceVer(ForceVer), VarSplitSsa(VarSplitSsa), SetVarSplitSsa(LiftedSetVarSplitSsa), + AssertSsa(LiftedAssertSsa), + ForceVerSsa(ForceVerSsa), Add(LiftedBinaryOp), Sub(LiftedBinaryOp), And(LiftedBinaryOp), @@ -135,7 +141,6 @@ pub enum MediumLevelILLiftedInstructionKind { Rlc(LiftedBinaryOpCarry), Rrc(LiftedBinaryOpCarry), Call(LiftedCall), - CallOutput(LiftedCallOutput), CallParam(LiftedCallParam), CallOutputSsa(LiftedCallOutputSsa), CallParamSsa(LiftedCallParamSsa), @@ -204,9 +209,6 @@ pub enum MediumLevelILLiftedInstructionKind { VarOutputAliasedField(VarOutputAliasedField), Trap(Trap), BlockToExpand(LiftedBlockToExpand), - // A placeholder for instructions that the Rust bindings do not yet support. - // Distinct from `Unimpl` as that is a valid instruction. - NotYetImplemented, } impl MediumLevelILLiftedInstruction { @@ -218,7 +220,6 @@ impl MediumLevelILLiftedInstruction { Bp => "Bp", Undef => "Undef", Unimpl => "Unimpl", - NotYetImplemented => "NotYetImplemented", If(_) => "If", FloatConst(_) => "FloatConst", Const(_) => "Const", @@ -246,8 +247,12 @@ impl MediumLevelILLiftedInstruction { MemPhi(_) => "MemPhi", VarSplit(_) => "VarSplit", SetVarSplit(_) => "SetVarSplit", + Assert(_) => "Assert", + ForceVer(_) => "ForceVer", VarSplitSsa(_) => "VarSplitSsa", SetVarSplitSsa(_) => "SetVarSplitSsa", + AssertSsa(_) => "AssertSsa", + ForceVerSsa(_) => "ForceVerSsa", Add(_) => "Add", Sub(_) => "Sub", And(_) => "And", @@ -302,7 +307,6 @@ impl MediumLevelILLiftedInstruction { Rlc(_) => "Rlc", Rrc(_) => "Rrc", Call(_) => "Call", - CallOutput(_) => "CallOutput", CallParam(_) => "CallParam", CallOutputSsa(_) => "CallOutputSsa", CallParamSsa(_) => "CallParamSsa", @@ -378,7 +382,7 @@ impl MediumLevelILLiftedInstruction { use MediumLevelILLiftedInstructionKind::*; use MediumLevelILLiftedOperand as Operand; match &self.kind { - Nop | Noret | Bp | Undef | Unimpl | NotYetImplemented => vec![], + Nop | Noret | Bp | Undef | Unimpl => vec![], If(op) => vec![ ("condition", Operand::Expr(*op.condition.clone())), ("dest_true", Operand::InstructionIndex(op.dest_true)), @@ -468,6 +472,18 @@ impl MediumLevelILLiftedInstruction { ("low", Operand::Var(op.low)), ("src", Operand::Expr(*op.src.clone())), ], + Assert(op) => vec![ + ("src", Operand::Var(op.src)), + ( + "constraint", + Operand::PossibleValueSet(op.constraint.clone()), + ), + ], + ForceVer(op) => vec![ + ("dest", Operand::Var(op.dest)), + ("src", Operand::Var(op.src)), + ("reason", Operand::ForceVersionReason(op.reason)), + ], VarSplitSsa(op) => vec![ ("high", Operand::VarSsa(op.high)), ("low", Operand::VarSsa(op.low)), @@ -477,6 +493,18 @@ impl MediumLevelILLiftedInstruction { ("low", Operand::VarSsa(op.low)), ("src", Operand::Expr(*op.src.clone())), ], + AssertSsa(op) => vec![ + ("src", Operand::VarSsa(op.src)), + ( + "constraint", + Operand::PossibleValueSet(op.constraint.clone()), + ), + ], + ForceVerSsa(op) => vec![ + ("dest", Operand::VarSsa(op.dest)), + ("src", Operand::VarSsa(op.src)), + ("reason", Operand::ForceVersionReason(op.reason)), + ], Add(op) | Sub(op) | And(op) | Or(op) | Xor(op) | Lsl(op) | Lsr(op) | Asr(op) | Rol(op) | Ror(op) | Mul(op) | MuluDp(op) | MulsDp(op) | Divu(op) | DivuDp(op) | Divs(op) | DivsDp(op) | Modu(op) | ModuDp(op) | Mods(op) | ModsDp(op) @@ -498,10 +526,9 @@ impl MediumLevelILLiftedInstruction { ("dest", Operand::Expr(*op.dest.clone())), ("params", Operand::ExprList(op.params.clone())), ], - CallOutput(op) => vec![("output", Operand::VarList(op.output.clone()))], CallParam(op) => vec![("params", Operand::ExprList(op.params.clone()))], CallOutputSsa(op) => vec![ - ("output", Operand::VarSsaList(op.output.clone())), + ("output", Operand::ExprList(op.output.clone())), ("dest_memory", Operand::Int(op.dest_memory)), ], CallParamSsa(op) => vec![ diff --git a/rust/src/medium_level_il/operation.rs b/rust/src/medium_level_il/operation.rs index 1886b3d0a5..48b4a80fd4 100644 --- a/rust/src/medium_level_il/operation.rs +++ b/rust/src/medium_level_il/operation.rs @@ -2,9 +2,11 @@ use super::{ MediumLevelExpressionIndex, MediumLevelILLiftedInstruction, MediumLevelInstructionIndex, }; use crate::architecture::CoreIntrinsic; -use crate::variable::{ConstantData, SSAVariable, Variable}; +use crate::variable::{ConstantData, PossibleValueSet, SSAVariable, Variable}; use std::collections::BTreeMap; +pub use binaryninjacore_sys::BNForceVersionReason as ForceVersionReason; + // IF #[derive(Debug, Copy, Clone)] pub struct MediumLevelILOperationIf { @@ -267,6 +269,26 @@ pub struct LiftedSetVarSplit { pub src: Box, } +// ASSERT +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Assert { + pub src: Variable, + pub constraint_index: usize, +} +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LiftedAssert { + pub src: Variable, + pub constraint: PossibleValueSet, +} + +// FORCE_VER +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ForceVer { + pub dest: Variable, + pub src: Variable, + pub reason: ForceVersionReason, +} + // VAR_SPLIT_SSA #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct VarSplitSsa { @@ -288,6 +310,26 @@ pub struct LiftedSetVarSplitSsa { pub src: Box, } +// ASSERT_SSA +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct AssertSsa { + pub src: SSAVariable, + pub constraint_index: usize, +} +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LiftedAssertSsa { + pub src: SSAVariable, + pub constraint: PossibleValueSet, +} + +// FORCE_VER_SSA +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ForceVerSsa { + pub dest: SSAVariable, + pub src: SSAVariable, + pub reason: ForceVersionReason, +} + // ADD, SUB, AND, OR, XOR, LSL, LSR, ASR, ROL, ROR, MUL, MULU_DP, MULS_DP, DIVU, DIVU_DP, DIVS, DIVS_DP, MODU, MODU_DP, MODS, MODS_DP, CMP_E, CMP_NE, CMP_SLT, CMP_ULT, CMP_SLE, CMP_ULE, CMP_SGE, CMP_UGE, CMP_SGT, CMP_UGT, TEST_BIT, ADD_OVERFLOW, FCMP_E, FCMP_NE, FCMP_LT, FCMP_LE, FCMP_GE, FCMP_GT, FCMP_O, FCMP_UO, FADD, FSUB, FMUL, FDIV #[derive(Debug, Copy, Clone)] pub struct BinaryOp { @@ -330,17 +372,6 @@ pub struct LiftedCall { pub params: Vec, } -// CALL_OUTPUT -#[derive(Debug, Copy, Clone)] -pub struct CallOutput { - pub first_output: usize, - pub num_outputs: usize, -} -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedCallOutput { - pub output: Vec, -} - // CALL_PARAM_SSA #[derive(Debug, Copy, Clone)] pub struct CallParam { @@ -362,7 +393,7 @@ pub struct CallOutputSsa { #[derive(Clone, Debug, PartialEq)] pub struct LiftedCallOutputSsa { pub dest_memory: u64, - pub output: Vec, + pub output: Vec, } // CALL_PARAM_SSA From bcdadc1ae608e437289d5c64879a206dc54bf71d Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Mon, 19 Oct 2026 13:35:50 -0700 Subject: [PATCH 4/4] Fix Python IL bindings reporting operands and variables incorrectly Python's IL bindings reported no operands for ASSERT and FORCE_VER, and the wrong variables as read or written for a handful of MLIL ops. ILOperations named some operands after their slots rather than their properties. LLIL also turned negative register-stack adjustments into -1, HLIL's ROR read a carry it doesn't have, and a few HLIL builders stored their operands in the wrong slots. Now each op reports its operands and variables correctly, and the builders store their operands in the right slots. --- python/highlevelil.py | 56 +++++++++++++--- python/lowlevelil.py | 36 +++++++++- python/mediumlevelil.py | 144 ++++++++++++++++++++++++++++++++++------ 3 files changed, 205 insertions(+), 31 deletions(-) diff --git a/python/highlevelil.py b/python/highlevelil.py index 744b508854..ec3bd5e063 100644 --- a/python/highlevelil.py +++ b/python/highlevelil.py @@ -187,12 +187,16 @@ class HighLevelILInstruction(BaseILInstruction): ("dest_memory", "int"), ("src", "expr"), ("src_memory", "int")], + HighLevelILOperation.HLIL_FORCE_VER: [("dest", "var"), ("src", "var")], + HighLevelILOperation.HLIL_ASSERT: [("src", "var"), ("constraint", "constraint")], + HighLevelILOperation.HLIL_FORCE_VER_SSA: [("dest", "var_ssa"), ("src", "var_ssa")], + HighLevelILOperation.HLIL_ASSERT_SSA: [("src", "var_ssa"), ("constraint", "constraint")], HighLevelILOperation.HLIL_ASSIGN_UNPACK_MEM_SSA: [ ("dest", "expr_list"), ("dest_memory", "int"), ("src", "expr"), ("src_memory", "int") ], HighLevelILOperation.HLIL_VAR: [("var", "var")], HighLevelILOperation.HLIL_VAR_SSA: [ ("var", "var_ssa") ], HighLevelILOperation.HLIL_VAR_SSA_PARTIAL: [ - ("var", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src") + ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src") ], HighLevelILOperation.HLIL_VAR_PHI: [("dest", "var_ssa"), ("src", "var_ssa_list")], HighLevelILOperation.HLIL_MEM_PHI: [ ("dest", "int"), ("src", "int_list") @@ -1998,7 +2002,7 @@ class HighLevelILRlc(HighLevelILCarryBase): @dataclass(frozen=True, repr=False, eq=False) -class HighLevelILRor(HighLevelILCarryBase): +class HighLevelILRor(HighLevelILBinaryBase, Arithmetic): pass @@ -2505,6 +2509,13 @@ def src(self) -> variable.Variable: def constraint(self) -> variable.PossibleValueSet: return self._get_constraint(1) + @property + def detailed_operands(self) -> List[Tuple[str, HighLevelILOperandType, str]]: + return [ + ("src", self.src, "Variable"), + ("constraint", self.constraint, "PossibleValueSet"), + ] + @dataclass(frozen=True, repr=False, eq=False) class HighLevelILAssertSsa(HighLevelILInstruction, SSA): @property @@ -2515,6 +2526,13 @@ def src(self) -> 'mediumlevelil.SSAVariable': def constraint(self) -> variable.PossibleValueSet: return self._get_constraint(2) + @property + def detailed_operands(self) -> List[Tuple[str, HighLevelILOperandType, str]]: + return [ + ("src", self.src, "SSAVariable"), + ("constraint", self.constraint, "PossibleValueSet"), + ] + @dataclass(frozen=True, repr=False, eq=False) class HighLevelILForceVer(HighLevelILInstruction): @property @@ -2525,6 +2543,17 @@ def dest(self) -> variable.Variable: def src(self) -> variable.Variable: return self._get_var(1) + @property + def detailed_operands(self) -> List[Tuple[str, HighLevelILOperandType, str]]: + return [ + ("dest", self.dest, "Variable"), + ("src", self.src, "Variable"), + ] + + @property + def vars_written(self) -> VariablesList: + return [self.dest] + @dataclass(frozen=True, repr=False, eq=False) class HighLevelILForceVerSsa(HighLevelILInstruction, SSA): @property @@ -2535,6 +2564,17 @@ def dest(self) -> 'mediumlevelil.SSAVariable': def src(self) -> 'mediumlevelil.SSAVariable': return self._get_var_ssa(2, 3) + @property + def detailed_operands(self) -> List[Tuple[str, HighLevelILOperandType, str]]: + return [ + ("dest", self.dest, "SSAVariable"), + ("src", self.src, "SSAVariable"), + ] + + @property + def vars_written(self) -> VariablesList: + return [self.dest] + ILInstruction = { HighLevelILOperation.HLIL_NOP: HighLevelILNop, # , @@ -3269,7 +3309,7 @@ def while_expr( return self.expr(HighLevelILOperation.HLIL_WHILE, condition, loop_expr, source_location=loc) def do_while_expr( - self, condition: ExpressionIndex, loop_expr: ExpressionIndex, loc: Optional['ILSourceLocation'] = None + self, loop_expr: ExpressionIndex, condition: ExpressionIndex, loc: Optional['ILSourceLocation'] = None ) -> ExpressionIndex: """ ``do_while_expr`` a do-while-loop expression with a condition and loop body. @@ -3280,7 +3320,7 @@ def do_while_expr( :return: The expression ``do { loop_expr } while (condition)`` :rtype: ExpressionIndex """ - return self.expr(HighLevelILOperation.HLIL_DO_WHILE, condition, loop_expr, source_location=loc) + return self.expr(HighLevelILOperation.HLIL_DO_WHILE, loop_expr, condition, source_location=loc) def for_expr( self, init_expr: ExpressionIndex, condition: ExpressionIndex, update_expr: ExpressionIndex, loop_expr: ExpressionIndex, @@ -3558,7 +3598,7 @@ def struct_init_field( """ return self.expr(HighLevelILOperation.HLIL_STRUCT_INIT_FIELD, offset, member_index, src, size=size, source_location=loc) - def deref(self, size: int, src: ExpressionIndex, loc: Optional['ILSourceLocation']) -> ExpressionIndex: + def deref(self, size: int, src: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: """ ``deref`` dereferences expression ``src`` and reads a value of size ``size`` @@ -3571,7 +3611,7 @@ def deref(self, size: int, src: ExpressionIndex, loc: Optional['ILSourceLocation return self.expr(HighLevelILOperation.HLIL_DEREF, src, size=size, source_location=loc) def deref_field( - self, size: int, src: ExpressionIndex, offset: int, member_index: int, loc: Optional['ILSourceLocation'] + self, size: int, src: ExpressionIndex, offset: int, member_index: int, loc: Optional['ILSourceLocation'] = None ) -> ExpressionIndex: """ ``deref_field`` dereferences structure field in expression ``src`` at offset ``offset`` and index ``member_index`` of size ``size`` @@ -3607,7 +3647,7 @@ def pass_by_ref(self, size: int, src: ExpressionIndex, loc: Optional['ILSourceLo :return: The expression ``ref *src`` :rtype: ExpressionIndex """ - return self.expr(HighLevelILOperation.HLIL_PASS_BY_REF, src, size, source_location=loc) + return self.expr(HighLevelILOperation.HLIL_PASS_BY_REF, src, size=size, source_location=loc) def return_by_ref(self, size: int, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: """ @@ -3619,7 +3659,7 @@ def return_by_ref(self, size: int, dest: ExpressionIndex, loc: Optional['ILSourc :return: The expression ``ref dest`` :rtype: ExpressionIndex """ - return self.expr(HighLevelILOperation.HLIL_RETURN_BY_REF, dest, size, source_location=loc) + return self.expr(HighLevelILOperation.HLIL_RETURN_BY_REF, dest, size=size, source_location=loc) def const(self, size: int, value: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: """ diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 7e8d121219..8244d57192 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -501,7 +501,11 @@ class LowLevelILInstruction(BaseILInstruction): ], LowLevelILOperation.LLIL_FLAG_PHI: [ ("dest", "flag_ssa"), ("src", "flag_ssa_list") ], LowLevelILOperation.LLIL_MEM_PHI: [("dest_memory", "int"), - ("src_memory", "int_list")] + ("src_memory", "int_list")], + LowLevelILOperation.LLIL_ASSERT: [("src", "reg"), ("constraint", "constraint")], + LowLevelILOperation.LLIL_ASSERT_SSA: [("src", "reg_ssa"), ("constraint", "constraint")], + LowLevelILOperation.LLIL_FORCE_VER: [("dest", "reg")], + LowLevelILOperation.LLIL_FORCE_VER_SSA: [("dest", "reg_ssa"), ("src", "reg_ssa")], } @staticmethod @@ -1073,8 +1077,9 @@ def _get_reg_stack_adjust(self, operand_index: int) -> Dict['architecture.Regist for j in range(count.value // 2): reg_stack = operand_list[j * 2] adjust = operand_list[(j*2) + 1] + adjust &= 0xffffffff if adjust & 0x80000000: - adjust |= ~0x80000000 + adjust -= 1 << 32 result[self.function.arch.get_reg_stack_name(reg_stack)] = adjust return result finally: @@ -3123,6 +3128,13 @@ def src(self) -> ILRegister: def constraint(self) -> variable.PossibleValueSet: return self._get_constraint(1) + @property + def detailed_operands(self) -> List[Tuple[str, LowLevelILOperandType, str]]: + return [ + ("src", self.src, "ILRegister"), + ("constraint", self.constraint, "PossibleValueSet"), + ] + @dataclass(frozen=True, repr=False, eq=False) class LowLevelILAssertSsa(LowLevelILInstruction, SSA): @property @@ -3133,12 +3145,25 @@ def src(self) -> SSARegister: def constraint(self) -> variable.PossibleValueSet: return self._get_constraint(2) + @property + def detailed_operands(self) -> List[Tuple[str, LowLevelILOperandType, str]]: + return [ + ("src", self.src, "SSARegister"), + ("constraint", self.constraint, "PossibleValueSet"), + ] + @dataclass(frozen=True, repr=False, eq=False) class LowLevelILForceVer(LowLevelILInstruction): @property def dest(self) -> ILRegister: return self._get_reg(0) + @property + def detailed_operands(self) -> List[Tuple[str, LowLevelILOperandType, str]]: + return [ + ("dest", self.dest, "ILRegister"), + ] + @dataclass(frozen=True, repr=False, eq=False) class LowLevelILForceVerSsa(LowLevelILInstruction, SSA): @property @@ -3149,6 +3174,13 @@ def dest(self) -> SSARegister: def src(self) -> SSARegister: return self._get_reg_ssa(2, 3) + @property + def detailed_operands(self) -> List[Tuple[str, LowLevelILOperandType, str]]: + return [ + ("dest", self.dest, "SSARegister"), + ("src", self.src, "SSARegister"), + ] + ILInstruction:Dict[LowLevelILOperation, LowLevelILInstruction] = { # type: ignore LowLevelILOperation.LLIL_NOP: LowLevelILNop, # [], diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index c2955101b3..269dafc55a 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -216,7 +216,7 @@ class MediumLevelILInstruction(BaseILInstruction): ], MediumLevelILOperation.MLIL_STORE_STRUCT: [("dest", "expr"), ("offset", "int"), ("src", "expr")], - MediumLevelILOperation.MLIL_VAR: [("src", "var")], MediumLevelILOperation.MLIL_VAR_FIELD: [ + MediumLevelILOperation.MLIL_VAR: [("var", "var")], MediumLevelILOperation.MLIL_VAR_FIELD: [ ("src", "var"), ("offset", "int") ], MediumLevelILOperation.MLIL_VAR_SPLIT: [("high", "var"), ("low", "var")], MediumLevelILOperation.MLIL_ADDRESS_OF: [("src", "var")], MediumLevelILOperation.MLIL_PASS_BY_REF: [ @@ -231,7 +231,7 @@ class MediumLevelILInstruction(BaseILInstruction): ("constant", "int"), ("offset", "int") ], MediumLevelILOperation.MLIL_FLOAT_CONST: [("constant", "float")], MediumLevelILOperation.MLIL_IMPORT: [ ("constant", "int") - ], MediumLevelILOperation.MLIL_CONST_DATA: [("constant", "ConstantData")], MediumLevelILOperation.MLIL_CONST_DATA: [ + ], MediumLevelILOperation.MLIL_CONST_DATA: [ ("constant", "ConstantData") ], MediumLevelILOperation.MLIL_ADD: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_ADC: [ ("left", "expr"), ("right", "expr"), ("carry", "expr") @@ -284,9 +284,9 @@ class MediumLevelILInstruction(BaseILInstruction): ], MediumLevelILOperation.MLIL_JUMP: [("dest", "expr")], MediumLevelILOperation.MLIL_JUMP_TO: [ ("dest", "expr"), ("targets", "target_map") ], MediumLevelILOperation.MLIL_RET_HINT: [("dest", "expr")], MediumLevelILOperation.MLIL_CALL: [ - ("output", "expr_list"), ("dest", "expr"), ("params", "expr_list") + ("output", "var_list"), ("dest", "expr"), ("params", "expr_list") ], MediumLevelILOperation.MLIL_CALL_UNTYPED: [ - ("output", "expr_list"), ("dest", "expr"), ("params", "expr"), ("stack", "expr") + ("output", "var_list"), ("dest", "expr"), ("params", "expr_list"), ("stack", "expr") ], MediumLevelILOperation.MLIL_CALL_PARAM: [ ("src", "expr_list") ], MediumLevelILOperation.MLIL_SEPARATE_PARAM_LIST: [ @@ -302,7 +302,7 @@ class MediumLevelILInstruction(BaseILInstruction): ], MediumLevelILOperation.MLIL_RET: [ ("src", "expr_list") ], MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND: [ - ("src", "expr_list") + ("exprs", "expr_list") ], MediumLevelILOperation.MLIL_NORET: [], MediumLevelILOperation.MLIL_IF: [ ("condition", "expr"), ("true", "int"), ("false", "int") ], MediumLevelILOperation.MLIL_GOTO: [("dest", "int")], MediumLevelILOperation.MLIL_CMP_E: [ @@ -329,12 +329,12 @@ class MediumLevelILInstruction(BaseILInstruction): MediumLevelILOperation.MLIL_BOOL_TO_INT: [("src", "expr")], MediumLevelILOperation.MLIL_ADD_OVERFLOW: [ ("left", "expr"), ("right", "expr") ], MediumLevelILOperation.MLIL_SYSCALL: [ - ("output", "expr_list"), ("params", "expr_list") + ("output", "var_list"), ("params", "expr_list") ], MediumLevelILOperation.MLIL_SYSCALL_UNTYPED: [ - ("output", "expr_list"), ("params", "expr"), ("stack", "expr") + ("output", "var_list"), ("params", "expr_list"), ("stack", "expr") ], MediumLevelILOperation.MLIL_TAILCALL: [ - ("output", "expr_list"), ("dest", "expr"), ("params", "expr_list") - ], MediumLevelILOperation.MLIL_TAILCALL_UNTYPED: [("output", "expr_list"), ("dest", "expr"), ("params", "expr"), + ("output", "var_list"), ("dest", "expr"), ("params", "expr_list") + ], MediumLevelILOperation.MLIL_TAILCALL_UNTYPED: [("output", "var_list"), ("dest", "expr"), ("params", "expr_list"), ("stack", "expr")], MediumLevelILOperation.MLIL_BP: [], MediumLevelILOperation.MLIL_TRAP: [("vector", "int")], MediumLevelILOperation.MLIL_INTRINSIC: [ ("output", "var_list"), ("intrinsic", "intrinsic"), ("params", "expr_list") @@ -343,11 +343,12 @@ class MediumLevelILInstruction(BaseILInstruction): ], MediumLevelILOperation.MLIL_MEMORY_INTRINSIC_OUTPUT_SSA: [ ("dest_memory", "int"), ("output", "var_ssa_list") ], MediumLevelILOperation.MLIL_MEMORY_INTRINSIC_SSA: [ - ("output", "expr"), ("intrinsic", "intrinsic"), ("params", "expr_list"), ("src_memory", "int") + ("output", "var_ssa_list"), ("dest_memory", "int"), ("intrinsic", "intrinsic"), ("params", "expr_list"), + ("src_memory", "int") ], MediumLevelILOperation.MLIL_FREE_VAR_SLOT: [ ("dest", "var") ], MediumLevelILOperation.MLIL_FREE_VAR_SLOT_SSA: [ - ("prev", "var_ssa_dest_and_src") + ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src") ], MediumLevelILOperation.MLIL_UNDEF: [], MediumLevelILOperation.MLIL_UNIMPL: [], MediumLevelILOperation.MLIL_UNIMPL_MEM: [("src", "expr")], MediumLevelILOperation.MLIL_FADD: [ ("left", "expr"), ("right", "expr") @@ -389,7 +390,7 @@ class MediumLevelILInstruction(BaseILInstruction): ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src"), ("src", "expr") ], MediumLevelILOperation.MLIL_SET_VAR_ALIASED_FIELD: [ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src"), ("offset", "int"), ("src", "expr") - ], MediumLevelILOperation.MLIL_VAR_SSA: [("src", "var_ssa")], MediumLevelILOperation.MLIL_VAR_SSA_FIELD: [ + ], MediumLevelILOperation.MLIL_VAR_SSA: [("var", "var_ssa")], MediumLevelILOperation.MLIL_VAR_SSA_FIELD: [ ("src", "var_ssa"), ("offset", "int") ], MediumLevelILOperation.MLIL_VAR_ALIASED: [ ("src", "var_ssa") @@ -398,7 +399,7 @@ class MediumLevelILInstruction(BaseILInstruction): ], MediumLevelILOperation.MLIL_VAR_SPLIT_SSA: [ ("high", "var_ssa"), ("low", "var_ssa") ], MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA: [ - ("dest", "var_ssa") + ("var", "var_ssa") ], MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA_FIELD: [ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src"), ("offset", "int") ], MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED: [ @@ -406,20 +407,23 @@ class MediumLevelILInstruction(BaseILInstruction): ], MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED_FIELD: [ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src"), ("offset", "int") ], MediumLevelILOperation.MLIL_CALL_SSA: [ - ("output", "expr"), ("output_dest_memory", "int"), ("dest", "expr"), + ("output", "var_ssa_list"), ("output_dest_memory", "int"), ("dest", "expr"), ("params", "expr_list"), ("src_memory", "int") ], MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA: [ - ("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr") + ("output", "var_ssa_list"), ("output_dest_memory", "int"), ("dest", "expr"), ("params", "expr_list"), + ("params_src_memory", "int"), ("stack", "expr") ], MediumLevelILOperation.MLIL_SYSCALL_SSA: [ - ("output", "expr"), ("params", "expr_list"), + ("output", "var_ssa_list"), ("output_dest_memory", "int"), ("params", "expr_list"), ("src_memory", "int") ], MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA: [ - ("output", "expr"), ("params", "expr"), ("stack", "expr") + ("output", "var_ssa_list"), ("output_dest_memory", "int"), ("params", "expr_list"), + ("params_src_memory", "int"), ("stack", "expr") ], MediumLevelILOperation.MLIL_TAILCALL_SSA: [ - ("output", "expr"), ("output_dest_memory", "int"), + ("output", "var_ssa_list"), ("output_dest_memory", "int"), ("dest", "expr"), ("params", "expr_list"), ("src_memory", "int") ], MediumLevelILOperation.MLIL_TAILCALL_UNTYPED_SSA: [ - ("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr") + ("output", "var_ssa_list"), ("output_dest_memory", "int"), ("dest", "expr"), ("params", "expr_list"), + ("params_src_memory", "int"), ("stack", "expr") ], MediumLevelILOperation.MLIL_CALL_OUTPUT_SSA: [ ("dest_memory", "int"), ("dest", "var_ssa_list") ], MediumLevelILOperation.MLIL_CALL_PARAM_SSA: [ @@ -435,7 +439,11 @@ class MediumLevelILInstruction(BaseILInstruction): ], MediumLevelILOperation.MLIL_VAR_PHI: [ ("dest", "var_ssa"), ("src", "var_ssa_list") ], MediumLevelILOperation.MLIL_MEM_PHI: [("dest_memory", "int"), - ("src_memory", "int_list")] + ("src_memory", "int_list")], + MediumLevelILOperation.MLIL_ASSERT: [("src", "var"), ("constraint", "constraint")], + MediumLevelILOperation.MLIL_ASSERT_SSA: [("src", "var_ssa"), ("constraint", "constraint")], + MediumLevelILOperation.MLIL_FORCE_VER: [("dest", "var"), ("src", "var"), ("reason", "int")], + MediumLevelILOperation.MLIL_FORCE_VER_SSA: [("dest", "var_ssa"), ("src", "var_ssa"), ("reason", "int")] } @staticmethod @@ -1606,6 +1614,14 @@ def dest(self) -> variable.Variable: def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: return [("dest", self.dest, "Variable")] + @property + def vars_read(self) -> List[variable.Variable]: + return [] + + @property + def vars_written(self) -> List[variable.Variable]: + return [self.dest] + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILVarOutputField(MediumLevelILInstruction, SetVar): @@ -1801,6 +1817,14 @@ def var(self) -> SSAVariable: def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: return [("var", self.var, "SSAVariable")] + @property + def vars_read(self) -> List[SSAVariable]: + return [] + + @property + def vars_written(self) -> List[SSAVariable]: + return [self.dest] + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILVarOutputSsaField(MediumLevelILInstruction, SetVar, SSA): @@ -2016,6 +2040,10 @@ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: ("offset", self.offset, "int") ] + @property + def vars_address_taken(self) -> List[variable.Variable]: + return [self.src] + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILExternPtr(MediumLevelILConstBase): @@ -2201,7 +2229,7 @@ class MediumLevelILAddOverflow(MediumLevelILBinaryBase, Arithmetic): @dataclass(frozen=True, repr=False, eq=False) -class MediumLevelILSyscall(MediumLevelILInstruction, Syscall): +class MediumLevelILSyscall(MediumLevelILCallBase, Syscall): @property def output(self) -> List[variable.Variable]: result = [] @@ -2689,6 +2717,17 @@ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: ("src_memory", self.src_memory, "int"), ] + @property + def vars_read(self) -> List[SSAVariable]: + result: List[SSAVariable] = [] + for i in self.params: + result.extend(i.vars_read) # type: ignore + return result + + @property + def vars_written(self) -> List[SSAVariable]: + return self.output + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILSetVarSsaField(MediumLevelILInstruction, SetVar, SSA): @@ -2788,6 +2827,10 @@ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: def vars_read(self) -> List[SSAVariable]: return [self.prev, *self.src.vars_read] # type: ignore # we're guaranteed not to return non-SSAVariables here + @property + def vars_written(self) -> List[SSAVariable]: + return [self.dest] + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILSyscallSsa(MediumLevelILCallBase, Syscall, SSA): @@ -2949,6 +2992,10 @@ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: ('src', self.src, 'MediumLevelILInstruction'), ] + @property + def vars_read(self) -> List[variable.Variable]: + return self.src.vars_read # type: ignore # we're guaranteed not to return non-Variables here + @property def vars_written(self) -> List[variable.Variable]: return [self.high, self.low] @@ -3300,6 +3347,14 @@ def params(self) -> List[MediumLevelILInstruction]: ), "MediumLevelILTailcallUntypedSsa return bad type for 'params'" return inst.src + @property + def params_src_memory(self): + inst = self._get_expr(2) + assert isinstance( + inst, MediumLevelILCallParamSsa + ), "MediumLevelILTailcallUntypedSsa return bad type for 'params_src_memory'" + return inst.src_memory + @property def stack(self) -> MediumLevelILInstruction: return self._get_expr(3) @@ -3311,6 +3366,7 @@ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: ('output_dest_memory', self.output_dest_memory, 'int'), ('dest', self.dest, 'MediumLevelILInstruction'), ('params', self.params, 'List[SSAVariable]'), + ('params_src_memory', self.params_src_memory, 'int'), ('stack', self.stack, 'MediumLevelILInstruction'), ] @@ -3424,6 +3480,13 @@ def src(self) -> variable.Variable: def constraint(self) -> variable.PossibleValueSet: return self._get_constraint(1) + @property + def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: + return [ + ("src", self.src, "Variable"), + ("constraint", self.constraint, "PossibleValueSet"), + ] + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILAssertSsa(MediumLevelILInstruction, SSA): @property @@ -3434,6 +3497,13 @@ def src(self) -> SSAVariable: def constraint(self) -> variable.PossibleValueSet: return self._get_constraint(2) + @property + def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: + return [ + ("src", self.src, "SSAVariable"), + ("constraint", self.constraint, "PossibleValueSet"), + ] + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILForceVer(MediumLevelILInstruction): @property @@ -3448,6 +3518,22 @@ def src(self) -> variable.Variable: def reason(self) -> ForceVersionReason: return ForceVersionReason(self._get_int(2)) + @property + def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: + return [ + ("dest", self.dest, "Variable"), + ("src", self.src, "Variable"), + ("reason", self.reason, "ForceVersionReason"), + ] + + @property + def vars_read(self) -> List[variable.Variable]: + return [self.src] + + @property + def vars_written(self) -> List[variable.Variable]: + return [self.dest] + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILForceVerSsa(MediumLevelILInstruction, SSA): @property @@ -3462,6 +3548,22 @@ def src(self) -> SSAVariable: def reason(self) -> ForceVersionReason: return ForceVersionReason(self._get_int(4)) + @property + def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: + return [ + ("dest", self.dest, "SSAVariable"), + ("src", self.src, "SSAVariable"), + ("reason", self.reason, "ForceVersionReason"), + ] + + @property + def vars_read(self) -> List[SSAVariable]: + return [self.src] + + @property + def vars_written(self) -> List[SSAVariable]: + return [self.dest] + @dataclass(frozen=True, repr=False, eq=False) class MediumLevelILBlockToExpand(MediumLevelILInstruction): @property