From efa3a367885c9510bb6280788241dae6f48a42bb Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 24 Feb 2020 19:42:56 -0500 Subject: Adding SSA support for HLIL --- binaryninjaapi.h | 28 ++++++- binaryninjacore.h | 42 ++++++++-- highlevelil.cpp | 144 +++++++++++++++++++++++++++++++- highlevelilinstruction.cpp | 196 ++++++++++++++++++++++++++++++++++++++++---- highlevelilinstruction.h | 46 +++++++++-- linearviewobject.cpp | 7 ++ python/highlevelil.py | 149 ++++++++++++++++++++++++++++++++- python/lineardisassembly.py | 6 ++ 8 files changed, 584 insertions(+), 34 deletions(-) diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 4339ad6f..91fe0d63 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -4052,9 +4052,15 @@ __attribute__ ((format (printf, 1, 2))) ExprId If(ExprId condition, ExprId trueExpr, ExprId falseExpr, const ILSourceLocation& loc = ILSourceLocation()); ExprId While(ExprId condition, ExprId loopExpr, const ILSourceLocation& loc = ILSourceLocation()); + ExprId WhileSSA(ExprId conditionPhi, ExprId condition, ExprId loopExpr, + const ILSourceLocation& loc = ILSourceLocation()); ExprId DoWhile(ExprId loopExpr, ExprId condition, const ILSourceLocation& loc = ILSourceLocation()); + ExprId DoWhileSSA(ExprId loopExpr, ExprId conditionPhi, ExprId condition, + const ILSourceLocation& loc = ILSourceLocation()); ExprId For(ExprId initExpr, ExprId condition, ExprId updateExpr, ExprId loopExpr, const ILSourceLocation& loc = ILSourceLocation()); + ExprId ForSSA(ExprId initExpr, ExprId conditionPhi, ExprId condition, ExprId updateExpr, + ExprId loopExpr, const ILSourceLocation& loc = ILSourceLocation()); ExprId Switch(ExprId condition, ExprId defaultExpr, const std::vector& cases, const ILSourceLocation& loc = ILSourceLocation()); ExprId Case(const std::vector& condition, ExprId expr, @@ -4227,9 +4233,10 @@ __attribute__ ((format (printf, 1, 2))) ExprId AddSSAVariableList(const std::vector& vars); BNHighLevelILInstruction GetRawExpr(size_t i) const; + BNHighLevelILInstruction GetRawNonASTExpr(size_t i) const; HighLevelILInstruction operator[](size_t i); HighLevelILInstruction GetInstruction(size_t i); - HighLevelILInstruction GetExpr(size_t i); + HighLevelILInstruction GetExpr(size_t i, bool asFullAst = true); size_t GetIndexForInstruction(size_t i) const; size_t GetInstructionForExpr(size_t expr) const; size_t GetInstructionCount() const; @@ -4238,6 +4245,24 @@ __attribute__ ((format (printf, 1, 2))) std::vector> GetBasicBlocks() const; Ref GetBasicBlockForInstruction(size_t i) const; + Ref GetSSAForm() const; + Ref GetNonSSAForm() const; + size_t GetSSAInstructionIndex(size_t instr) const; + size_t GetNonSSAInstructionIndex(size_t instr) const; + size_t GetSSAExprIndex(size_t instr) const; + size_t GetNonSSAExprIndex(size_t instr) const; + + size_t GetSSAVarDefinition(const SSAVariable& var) const; + size_t GetSSAMemoryDefinition(size_t version) const; + std::set GetSSAVarUses(const SSAVariable& var) const; + std::set GetSSAMemoryUses(size_t version) const; + bool IsSSAVarLive(const SSAVariable& var) const; + + std::set GetVariableDefinitions(const Variable& var) const; + std::set GetVariableUses(const Variable& var) const; + size_t GetSSAVarVersionAtInstruction(const Variable& var, size_t instr) const; + size_t GetSSAMemoryVersionAtInstruction(size_t instr) const; + Ref GetMediumLevelIL() const; size_t GetMediumLevelILExprIndex(size_t expr) const; @@ -5249,6 +5274,7 @@ __attribute__ ((format (printf, 1, 2))) static Ref CreateMappedMediumLevelIL(BinaryView* view, DisassemblySettings* settings); static Ref CreateMappedMediumLevelILSSAForm(BinaryView* view, DisassemblySettings* settings); static Ref CreateHighLevelIL(BinaryView* view, DisassemblySettings* settings); + static Ref CreateHighLevelILSSAForm(BinaryView* view, DisassemblySettings* settings); }; class LinearViewCursor: public CoreRefCountObject& vars) BNHighLevelILInstruction HighLevelILFunction::GetRawExpr(size_t i) const { - return BNGetHighLevelILByIndex(m_object, i); + return BNGetHighLevelILByIndex(m_object, i, true); +} + + +BNHighLevelILInstruction HighLevelILFunction::GetRawNonASTExpr(size_t i) const +{ + return BNGetHighLevelILByIndex(m_object, i, false); } @@ -175,13 +181,15 @@ HighLevelILInstruction HighLevelILFunction::operator[](size_t i) HighLevelILInstruction HighLevelILFunction::GetInstruction(size_t i) { size_t expr = GetIndexForInstruction(i); - return HighLevelILInstruction(this, GetRawExpr(expr), expr); + return HighLevelILInstruction(this, GetRawNonASTExpr(expr), expr, false, i); } -HighLevelILInstruction HighLevelILFunction::GetExpr(size_t i) +HighLevelILInstruction HighLevelILFunction::GetExpr(size_t i, bool asFullAst) { - return HighLevelILInstruction(this, GetRawExpr(i), i); + if (asFullAst) + return HighLevelILInstruction(this, GetRawExpr(i), i, true, GetInstructionForExpr(i)); + return HighLevelILInstruction(this, GetRawNonASTExpr(i), i, false, GetInstructionForExpr(i)); } @@ -233,6 +241,134 @@ Ref HighLevelILFunction::GetBasicBlockForInstruction(size_t i) const } +Ref HighLevelILFunction::GetSSAForm() const +{ + BNHighLevelILFunction* func = BNGetHighLevelILSSAForm(m_object); + if (!func) + return nullptr; + return new HighLevelILFunction(func); +} + + +Ref HighLevelILFunction::GetNonSSAForm() const +{ + BNHighLevelILFunction* func = BNGetHighLevelILNonSSAForm(m_object); + if (!func) + return nullptr; + return new HighLevelILFunction(func); +} + + +size_t HighLevelILFunction::GetSSAInstructionIndex(size_t instr) const +{ + return BNGetHighLevelILSSAInstructionIndex(m_object, instr); +} + + +size_t HighLevelILFunction::GetNonSSAInstructionIndex(size_t instr) const +{ + return BNGetHighLevelILNonSSAInstructionIndex(m_object, instr); +} + + +size_t HighLevelILFunction::GetSSAExprIndex(size_t expr) const +{ + return BNGetHighLevelILSSAExprIndex(m_object, expr); +} + + +size_t HighLevelILFunction::GetNonSSAExprIndex(size_t expr) const +{ + return BNGetHighLevelILNonSSAExprIndex(m_object, expr); +} + + +size_t HighLevelILFunction::GetSSAVarDefinition(const SSAVariable& var) const +{ + return BNGetHighLevelILSSAVarDefinition(m_object, &var.var, var.version); +} + + +size_t HighLevelILFunction::GetSSAMemoryDefinition(size_t version) const +{ + return BNGetHighLevelILSSAMemoryDefinition(m_object, version); +} + + +set HighLevelILFunction::GetSSAVarUses(const SSAVariable& var) const +{ + size_t count; + size_t* instrs = BNGetHighLevelILSSAVarUses(m_object, &var.var, var.version, &count); + + set result; + for (size_t i = 0; i < count; i++) + result.insert(instrs[i]); + + BNFreeILInstructionList(instrs); + return result; +} + + +set HighLevelILFunction::GetSSAMemoryUses(size_t version) const +{ + size_t count; + size_t* instrs = BNGetHighLevelILSSAMemoryUses(m_object, version, &count); + + set result; + for (size_t i = 0; i < count; i++) + result.insert(instrs[i]); + + BNFreeILInstructionList(instrs); + return result; +} + + +bool HighLevelILFunction::IsSSAVarLive(const SSAVariable& var) const +{ + return BNIsHighLevelILSSAVarLive(m_object, &var.var, var.version); +} + + +set HighLevelILFunction::GetVariableDefinitions(const Variable& var) const +{ + size_t count; + size_t* instrs = BNGetHighLevelILVariableDefinitions(m_object, &var, &count); + + set result; + for (size_t i = 0; i < count; i++) + result.insert(instrs[i]); + + BNFreeILInstructionList(instrs); + return result; +} + + +set HighLevelILFunction::GetVariableUses(const Variable& var) const +{ + size_t count; + size_t* instrs = BNGetHighLevelILVariableUses(m_object, &var, &count); + + set result; + for (size_t i = 0; i < count; i++) + result.insert(instrs[i]); + + BNFreeILInstructionList(instrs); + return result; +} + + +size_t HighLevelILFunction::GetSSAVarVersionAtInstruction(const Variable& var, size_t instr) const +{ + return BNGetHighLevelILSSAVarVersionAtILInstruction(m_object, &var, instr); +} + + +size_t HighLevelILFunction::GetSSAMemoryVersionAtInstruction(size_t instr) const +{ + return BNGetHighLevelILSSAMemoryVersionAtILInstruction(m_object, instr); +} + + Ref HighLevelILFunction::GetMediumLevelIL() const { BNMediumLevelILFunction* result = BNGetMediumLevelILForHighLevelILFunction(m_object); diff --git a/highlevelilinstruction.cpp b/highlevelilinstruction.cpp index 609b7f77..610c9e63 100644 --- a/highlevelilinstruction.cpp +++ b/highlevelilinstruction.cpp @@ -46,6 +46,7 @@ unordered_map {CarryExprHighLevelOperandUsage, ExprHighLevelOperand}, {IndexExprHighLevelOperandUsage, ExprHighLevelOperand}, {ConditionExprHighLevelOperandUsage, ExprHighLevelOperand}, + {ConditionPhiExprHighLevelOperandUsage, ExprHighLevelOperand}, {TrueExprHighLevelOperandUsage, ExprHighLevelOperand}, {FalseExprHighLevelOperandUsage, ExprHighLevelOperand}, {LoopExprHighLevelOperandUsage, ExprHighLevelOperand}, @@ -86,9 +87,16 @@ unordered_map> {HLIL_IF, {ConditionExprHighLevelOperandUsage, TrueExprHighLevelOperandUsage, FalseExprHighLevelOperandUsage}}, {HLIL_WHILE, {ConditionExprHighLevelOperandUsage, LoopExprHighLevelOperandUsage}}, + {HLIL_WHILE_SSA, {ConditionPhiExprHighLevelOperandUsage, + ConditionExprHighLevelOperandUsage, LoopExprHighLevelOperandUsage}}, {HLIL_DO_WHILE, {LoopExprHighLevelOperandUsage, ConditionExprHighLevelOperandUsage}}, + {HLIL_DO_WHILE_SSA, {LoopExprHighLevelOperandUsage, ConditionPhiExprHighLevelOperandUsage, + ConditionExprHighLevelOperandUsage}}, {HLIL_FOR, {InitExprHighLevelOperandUsage, ConditionExprHighLevelOperandUsage, UpdateExprHighLevelOperandUsage, LoopExprHighLevelOperandUsage}}, + {HLIL_FOR_SSA, {InitExprHighLevelOperandUsage, ConditionPhiExprHighLevelOperandUsage, + ConditionExprHighLevelOperandUsage, UpdateExprHighLevelOperandUsage, + LoopExprHighLevelOperandUsage}}, {HLIL_SWITCH, {ConditionExprHighLevelOperandUsage, DefaultExprHighLevelOperandUsage, CasesHighLevelOperandUsage}}, {HLIL_CASE, {ValueExprsHighLevelOperandUsage, TrueExprHighLevelOperandUsage}}, @@ -394,12 +402,20 @@ HighLevelILIndexList::operator vector() const const HighLevelILInstruction HighLevelILInstructionList::ListIterator::operator*() { - return HighLevelILInstruction(pos.GetFunction(), pos.GetFunction()->GetRawExpr((size_t)*pos), (size_t)*pos); + if (ast) + { + return HighLevelILInstruction(pos.GetFunction(), pos.GetFunction()->GetRawExpr((size_t)*pos), + (size_t)*pos, true, instructionIndex); + } + return HighLevelILInstruction(pos.GetFunction(), pos.GetFunction()->GetRawNonASTExpr((size_t)*pos), + (size_t)*pos, false, instructionIndex); } HighLevelILInstructionList::HighLevelILInstructionList(HighLevelILFunction* func, - const BNHighLevelILInstruction& instr, size_t count): m_list(func, instr, count) + const BNHighLevelILInstruction& instr, size_t count, bool asFullAst, + size_t instructionIndex): m_list(func, instr, count), m_ast(asFullAst), + m_instructionIndex(instructionIndex) { } @@ -408,6 +424,8 @@ HighLevelILInstructionList::const_iterator HighLevelILInstructionList::begin() c { const_iterator result; result.pos = m_list.begin(); + result.ast = m_ast; + result.instructionIndex = m_instructionIndex; return result; } @@ -416,6 +434,8 @@ HighLevelILInstructionList::const_iterator HighLevelILInstructionList::end() con { const_iterator result; result.pos = m_list.end(); + result.ast = m_ast; + result.instructionIndex = m_instructionIndex; return result; } @@ -661,7 +681,7 @@ HighLevelILInstruction::HighLevelILInstruction() HighLevelILInstruction::HighLevelILInstruction(HighLevelILFunction* func, - const BNHighLevelILInstruction& instr, size_t expr) + const BNHighLevelILInstruction& instr, size_t expr, bool asFullAst, size_t instrIdx) { operation = instr.operation; sourceOperand = instr.sourceOperand; @@ -675,6 +695,8 @@ HighLevelILInstruction::HighLevelILInstruction(HighLevelILFunction* func, parent = instr.parent; function = func; exprIndex = expr; + instructionIndex = instrIdx; + ast = asFullAst; } @@ -691,6 +713,8 @@ HighLevelILInstruction::HighLevelILInstruction(const HighLevelILInstructionBase& address = instr.address; function = instr.function; exprIndex = instr.exprIndex; + instructionIndex = instr.instructionIndex; + ast = instr.ast; parent = instr.parent; } @@ -721,7 +745,13 @@ size_t HighLevelILInstructionBase::GetRawOperandAsIndex(size_t operand) const HighLevelILInstruction HighLevelILInstructionBase::GetRawOperandAsExpr(size_t operand) const { - return HighLevelILInstruction(function, function->GetRawExpr(operands[operand]), operands[operand]); + if (ast) + { + return HighLevelILInstruction(function, function->GetRawExpr(operands[operand]), + operands[operand], true, instructionIndex); + } + return HighLevelILInstruction(function, function->GetRawNonASTExpr(operands[operand]), + operands[operand], false, instructionIndex); } @@ -739,7 +769,8 @@ SSAVariable HighLevelILInstructionBase::GetRawOperandAsSSAVariable(size_t operan HighLevelILInstructionList HighLevelILInstructionBase::GetRawOperandAsExprList(size_t operand) const { - return HighLevelILInstructionList(function, function->GetRawExpr(operands[operand + 1]), operands[operand]); + return HighLevelILInstructionList(function, function->GetRawExpr(operands[operand + 1]), + operands[operand], ast, instructionIndex); } @@ -865,6 +896,30 @@ HighLevelILInstruction HighLevelILInstructionBase::GetInstruction() const } +HighLevelILInstruction HighLevelILInstructionBase::AsAST() const +{ + return function->GetExpr(exprIndex, true); +} + + +HighLevelILInstruction HighLevelILInstructionBase::AsNonAST() const +{ + return function->GetExpr(exprIndex, false); +} + + +bool HighLevelILInstructionBase::HasParent() const +{ + return parent != BN_INVALID_EXPR; +} + + +HighLevelILInstruction HighLevelILInstructionBase::GetParent() const +{ + return function->GetExpr(parent, true); +} + + void HighLevelILInstruction::VisitExprs(const std::function& func) const { stack toProcess; @@ -873,7 +928,7 @@ void HighLevelILInstruction::VisitExprs(const std::functionGetExpr(toProcess.top()); + HighLevelILInstruction cur = function->GetExpr(toProcess.top(), ast); toProcess.pop(); if (!func(cur)) continue; @@ -885,29 +940,58 @@ void HighLevelILInstruction::VisitExprs(const std::functionexprIndex); break; case HLIL_IF: - toProcess.push(cur.GetFalseExpr().exprIndex); - toProcess.push(cur.GetTrueExpr().exprIndex); + if (ast) + { + toProcess.push(cur.GetFalseExpr().exprIndex); + toProcess.push(cur.GetTrueExpr().exprIndex); + } toProcess.push(cur.GetConditionExpr().exprIndex); break; case HLIL_WHILE: - toProcess.push(cur.GetLoopExpr().exprIndex); + if (ast) + toProcess.push(cur.GetLoopExpr().exprIndex); toProcess.push(cur.GetConditionExpr().exprIndex); break; + case HLIL_WHILE_SSA: + if (ast) + toProcess.push(cur.GetLoopExpr().exprIndex); + toProcess.push(cur.GetConditionExpr().exprIndex); + toProcess.push(cur.GetConditionPhiExpr().exprIndex); + break; case HLIL_DO_WHILE: toProcess.push(cur.GetConditionExpr().exprIndex); - toProcess.push(cur.GetLoopExpr().exprIndex); + if (ast) + toProcess.push(cur.GetLoopExpr().exprIndex); + break; + case HLIL_DO_WHILE_SSA: + toProcess.push(cur.GetConditionExpr().exprIndex); + toProcess.push(cur.GetConditionPhiExpr().exprIndex); + if (ast) + toProcess.push(cur.GetLoopExpr().exprIndex); break; case HLIL_FOR: - toProcess.push(cur.GetLoopExpr().exprIndex); + if (ast) + toProcess.push(cur.GetLoopExpr().exprIndex); toProcess.push(cur.GetUpdateExpr().exprIndex); toProcess.push(cur.GetConditionExpr().exprIndex); toProcess.push(cur.GetInitExpr().exprIndex); break; + case HLIL_FOR_SSA: + if (ast) + toProcess.push(cur.GetLoopExpr().exprIndex); + toProcess.push(cur.GetUpdateExpr().exprIndex); + toProcess.push(cur.GetConditionExpr().exprIndex); + toProcess.push(cur.GetConditionPhiExpr().exprIndex); + toProcess.push(cur.GetInitExpr().exprIndex); + break; case HLIL_SWITCH: - exprs = cur.GetCases(); - for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) - toProcess.push(i->exprIndex); - toProcess.push(cur.GetDefaultExpr().exprIndex); + if (ast) + { + exprs = cur.GetCases(); + for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) + toProcess.push(i->exprIndex); + toProcess.push(cur.GetDefaultExpr().exprIndex); + } toProcess.push(cur.GetConditionExpr().exprIndex); break; case HLIL_CASE: @@ -1120,13 +1204,27 @@ ExprId HighLevelILInstruction::CopyTo(HighLevelILFunction* dest, case HLIL_WHILE: return dest->While(subExprHandler(GetConditionExpr()), subExprHandler(GetLoopExpr()), *this); + case HLIL_WHILE_SSA: + return dest->WhileSSA(subExprHandler(GetConditionPhiExpr()), + subExprHandler(GetConditionExpr()), + subExprHandler(GetLoopExpr()), *this); case HLIL_DO_WHILE: return dest->DoWhile(subExprHandler(GetLoopExpr()), subExprHandler(GetConditionExpr()), *this); + case HLIL_DO_WHILE_SSA: + return dest->DoWhileSSA(subExprHandler(GetLoopExpr()), + subExprHandler(GetConditionPhiExpr()), + subExprHandler(GetConditionExpr()), *this); case HLIL_FOR: return dest->For(subExprHandler(GetInitExpr()), subExprHandler(GetConditionExpr()), subExprHandler(GetUpdateExpr()), subExprHandler(GetLoopExpr()), *this); + case HLIL_FOR_SSA: + return dest->ForSSA(subExprHandler(GetInitExpr()), + subExprHandler(GetConditionPhiExpr()), + subExprHandler(GetConditionExpr()), + subExprHandler(GetUpdateExpr()), + subExprHandler(GetLoopExpr()), *this); case HLIL_SWITCH: for (auto& i : GetCases()) params.push_back(subExprHandler(i)); @@ -1387,12 +1485,32 @@ bool HighLevelILInstruction::operator<(const HighLevelILInstruction& other) cons if (other.GetConditionExpr() < GetConditionExpr()) return false; return GetLoopExpr() < other.GetLoopExpr(); + case HLIL_WHILE_SSA: + if (GetConditionPhiExpr() < other.GetConditionPhiExpr()) + return true; + if (other.GetConditionPhiExpr() < GetConditionPhiExpr()) + return false; + if (GetConditionExpr() < other.GetConditionExpr()) + return true; + if (other.GetConditionExpr() < GetConditionExpr()) + return false; + return GetLoopExpr() < other.GetLoopExpr(); case HLIL_DO_WHILE: if (GetLoopExpr() < other.GetLoopExpr()) return true; if (other.GetLoopExpr() < GetLoopExpr()) return false; return GetConditionExpr() < other.GetConditionExpr(); + case HLIL_DO_WHILE_SSA: + if (GetLoopExpr() < other.GetLoopExpr()) + return true; + if (other.GetLoopExpr() < GetLoopExpr()) + return false; + if (GetConditionPhiExpr() < other.GetConditionPhiExpr()) + return true; + if (other.GetConditionPhiExpr() < GetConditionPhiExpr()) + return false; + return GetConditionExpr() < other.GetConditionExpr(); case HLIL_FOR: if (GetInitExpr() < other.GetInitExpr()) return true; @@ -1407,6 +1525,24 @@ bool HighLevelILInstruction::operator<(const HighLevelILInstruction& other) cons if (other.GetUpdateExpr() < GetUpdateExpr()) return false; return GetLoopExpr() < other.GetLoopExpr(); + case HLIL_FOR_SSA: + if (GetInitExpr() < other.GetInitExpr()) + return true; + if (other.GetInitExpr() < GetInitExpr()) + return false; + if (GetConditionPhiExpr() < other.GetConditionPhiExpr()) + return true; + if (other.GetConditionPhiExpr() < GetConditionPhiExpr()) + return false; + if (GetConditionExpr() < other.GetConditionExpr()) + return true; + if (other.GetConditionExpr() < GetConditionExpr()) + return false; + if (GetUpdateExpr() < other.GetUpdateExpr()) + return true; + if (other.GetUpdateExpr() < GetUpdateExpr()) + return false; + return GetLoopExpr() < other.GetLoopExpr(); case HLIL_SWITCH: if (GetConditionExpr() < other.GetConditionExpr()) return true; @@ -1946,6 +2082,15 @@ HighLevelILInstruction HighLevelILInstruction::GetConditionExpr() const } +HighLevelILInstruction HighLevelILInstruction::GetConditionPhiExpr() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(ConditionPhiExprHighLevelOperandUsage, operandIndex)) + return GetRawOperandAsExpr(operandIndex); + throw HighLevelILInstructionAccessException(); +} + + HighLevelILInstruction HighLevelILInstruction::GetTrueExpr() const { size_t operandIndex; @@ -2187,12 +2332,26 @@ ExprId HighLevelILFunction::While(ExprId condition, ExprId loopExpr, const ILSou } +ExprId HighLevelILFunction::WhileSSA(ExprId conditionPhi, ExprId condition, ExprId loopExpr, + const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_WHILE_SSA, loc, 0, conditionPhi, condition, loopExpr); +} + + ExprId HighLevelILFunction::DoWhile(ExprId loopExpr, ExprId condition, const ILSourceLocation& loc) { return AddExprWithLocation(HLIL_DO_WHILE, loc, 0, loopExpr, condition); } +ExprId HighLevelILFunction::DoWhileSSA(ExprId loopExpr, ExprId conditionPhi, ExprId condition, + const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_DO_WHILE_SSA, loc, 0, loopExpr, conditionPhi, condition); +} + + ExprId HighLevelILFunction::For(ExprId initExpr, ExprId condition, ExprId updateExpr, ExprId loopExpr, const ILSourceLocation& loc) { @@ -2200,6 +2359,13 @@ ExprId HighLevelILFunction::For(ExprId initExpr, ExprId condition, ExprId update } +ExprId HighLevelILFunction::ForSSA(ExprId initExpr, ExprId conditionPhi, ExprId condition, + ExprId updateExpr, ExprId loopExpr, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_FOR_SSA, loc, 0, initExpr, conditionPhi, condition, updateExpr, loopExpr); +} + + ExprId HighLevelILFunction::Switch(ExprId condition, ExprId defaultExpr, const std::vector& cases, const ILSourceLocation& loc) { diff --git a/highlevelilinstruction.h b/highlevelilinstruction.h index 967bafec..aa872e67 100644 --- a/highlevelilinstruction.h +++ b/highlevelilinstruction.h @@ -77,6 +77,7 @@ namespace BinaryNinja CarryExprHighLevelOperandUsage, IndexExprHighLevelOperandUsage, ConditionExprHighLevelOperandUsage, + ConditionPhiExprHighLevelOperandUsage, TrueExprHighLevelOperandUsage, FalseExprHighLevelOperandUsage, LoopExprHighLevelOperandUsage, @@ -214,8 +215,9 @@ namespace BinaryNinja { struct ListIterator { - size_t instructionIndex; HighLevelILIntegerList::const_iterator pos; + bool ast; + size_t instructionIndex; bool operator==(const ListIterator& a) const { return pos == a.pos; } bool operator!=(const ListIterator& a) const { return pos != a.pos; } bool operator<(const ListIterator& a) const { return pos < a.pos; } @@ -224,11 +226,14 @@ namespace BinaryNinja }; HighLevelILIntegerList m_list; + bool m_ast; + size_t m_instructionIndex; public: typedef ListIterator const_iterator; - HighLevelILInstructionList(HighLevelILFunction* func, const BNHighLevelILInstruction& instr, size_t count); + HighLevelILInstructionList(HighLevelILFunction* func, const BNHighLevelILInstruction& instr, + size_t count, bool asFullAst, size_t instructionIndex); const_iterator begin() const; const_iterator end() const; @@ -272,7 +277,8 @@ namespace BinaryNinja #else Ref function; #endif - size_t exprIndex; + size_t exprIndex, instructionIndex; + bool ast; static std::unordered_map operandTypeForUsage; static std::unordered_map HighLevelILInstructionAccessor& As() { @@ -359,7 +371,8 @@ namespace BinaryNinja struct HighLevelILInstruction: public HighLevelILInstructionBase { HighLevelILInstruction(); - HighLevelILInstruction(HighLevelILFunction* func, const BNHighLevelILInstruction& instr, size_t expr); + HighLevelILInstruction(HighLevelILFunction* func, const BNHighLevelILInstruction& instr, + size_t expr, bool asFullAst, size_t instructionIndex); HighLevelILInstruction(const HighLevelILInstructionBase& instr); void VisitExprs(const std::function& func) const; @@ -383,6 +396,7 @@ namespace BinaryNinja template HighLevelILInstruction GetRightExpr() const { return As().GetRightExpr(); } template HighLevelILInstruction GetCarryExpr() const { return As().GetCarryExpr(); } template HighLevelILInstruction GetIndexExpr() const { return As().GetIndexExpr(); } + template HighLevelILInstruction GetConditionPhiExpr() const { return As().GetConditionPhiExpr(); } template HighLevelILInstruction GetConditionExpr() const { return As().GetConditionExpr(); } template HighLevelILInstruction GetTrueExpr() const { return As().GetTrueExpr(); } template HighLevelILInstruction GetFalseExpr() const { return As().GetFalseExpr(); } @@ -410,6 +424,7 @@ namespace BinaryNinja template size_t GetDestMemoryVersion() const { return As().GetDestMemoryVersion(); } template void SetSSAVersion(size_t version) { As().SetSSAVersion(version); } + template void SetDestSSAVersion(size_t version) { As().SetDestSSAVersion(version); } template void SetParameterExprs(const std::vector& params) { As().SetParameterExprs(params); } template void SetParameterExprs(const std::vector& params) { As().SetParameterExprs(params); } template void SetSourceExprs(const std::vector& params) { As().SetSourceExprs(params); } @@ -439,6 +454,7 @@ namespace BinaryNinja HighLevelILInstruction GetCarryExpr() const; HighLevelILInstruction GetIndexExpr() const; HighLevelILInstruction GetConditionExpr() const; + HighLevelILInstruction GetConditionPhiExpr() const; HighLevelILInstruction GetTrueExpr() const; HighLevelILInstruction GetFalseExpr() const; HighLevelILInstruction GetLoopExpr() const; @@ -563,11 +579,23 @@ namespace BinaryNinja HighLevelILInstruction GetConditionExpr() const { return GetRawOperandAsExpr(0); } HighLevelILInstruction GetLoopExpr() const { return GetRawOperandAsExpr(1); } }; + template <> struct HighLevelILInstructionAccessor: public HighLevelILInstructionBase + { + HighLevelILInstruction GetConditionPhiExpr() const { return GetRawOperandAsExpr(0); } + HighLevelILInstruction GetConditionExpr() const { return GetRawOperandAsExpr(1); } + HighLevelILInstruction GetLoopExpr() const { return GetRawOperandAsExpr(2); } + }; template <> struct HighLevelILInstructionAccessor: public HighLevelILInstructionBase { HighLevelILInstruction GetLoopExpr() const { return GetRawOperandAsExpr(0); } HighLevelILInstruction GetConditionExpr() const { return GetRawOperandAsExpr(1); } }; + template <> struct HighLevelILInstructionAccessor: public HighLevelILInstructionBase + { + HighLevelILInstruction GetLoopExpr() const { return GetRawOperandAsExpr(0); } + HighLevelILInstruction GetConditionPhiExpr() const { return GetRawOperandAsExpr(1); } + HighLevelILInstruction GetConditionExpr() const { return GetRawOperandAsExpr(2); } + }; template <> struct HighLevelILInstructionAccessor: public HighLevelILInstructionBase { HighLevelILInstruction GetInitExpr() const { return GetRawOperandAsExpr(0); } @@ -575,6 +603,14 @@ namespace BinaryNinja HighLevelILInstruction GetUpdateExpr() const { return GetRawOperandAsExpr(2); } HighLevelILInstruction GetLoopExpr() const { return GetRawOperandAsExpr(3); } }; + template <> struct HighLevelILInstructionAccessor: public HighLevelILInstructionBase + { + HighLevelILInstruction GetInitExpr() const { return GetRawOperandAsExpr(0); } + HighLevelILInstruction GetConditionPhiExpr() const { return GetRawOperandAsExpr(1); } + HighLevelILInstruction GetConditionExpr() const { return GetRawOperandAsExpr(2); } + HighLevelILInstruction GetUpdateExpr() const { return GetRawOperandAsExpr(3); } + HighLevelILInstruction GetLoopExpr() const { return GetRawOperandAsExpr(4); } + }; template <> struct HighLevelILInstructionAccessor: public HighLevelILInstructionBase { HighLevelILInstruction GetConditionExpr() const { return GetRawOperandAsExpr(0); } @@ -614,7 +650,7 @@ namespace BinaryNinja { SSAVariable GetDestSSAVariable() const { return GetRawOperandAsSSAVariable(0); } void SetDestSSAVersion(size_t version) { UpdateRawOperand(1, version); } - HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(1); } + HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(2); } }; template <> struct HighLevelILInstructionAccessor: public HighLevelILInstructionBase { diff --git a/linearviewobject.cpp b/linearviewobject.cpp index b12038d7..1a563b9e 100644 --- a/linearviewobject.cpp +++ b/linearviewobject.cpp @@ -260,3 +260,10 @@ Ref LinearViewObject::CreateHighLevelIL(BinaryView* view, Disa return new LinearViewObject(BNCreateLinearViewHighLevelIL(view->GetObject(), settings ? settings->GetObject() : nullptr)); } + + +Ref LinearViewObject::CreateHighLevelILSSAForm(BinaryView* view, DisassemblySettings* settings) +{ + return new LinearViewObject(BNCreateLinearViewHighLevelILSSAForm(view->GetObject(), + settings ? settings->GetObject() : nullptr)); +} diff --git a/python/highlevelil.py b/python/highlevelil.py index b31bc0cc..6565253d 100644 --- a/python/highlevelil.py +++ b/python/highlevelil.py @@ -83,8 +83,11 @@ class HighLevelILInstruction(object): HighLevelILOperation.HLIL_BLOCK: [("body", "expr_list")], HighLevelILOperation.HLIL_IF: [("condition", "expr"), ("true", "expr"), ("false", "expr")], HighLevelILOperation.HLIL_WHILE: [("condition", "expr"), ("body", "expr")], + HighLevelILOperation.HLIL_WHILE_SSA: [("condition_phi", "expr"), ("condition", "expr"), ("body", "expr")], HighLevelILOperation.HLIL_DO_WHILE: [("body", "expr"), ("condition", "expr")], + HighLevelILOperation.HLIL_DO_WHILE_SSA: [("body", "expr"), ("condition_phi", "expr"), ("condition", "expr")], HighLevelILOperation.HLIL_FOR: [("init", "expr"), ("condition", "expr"), ("update", "expr"), ("body", "expr")], + HighLevelILOperation.HLIL_FOR_SSA: [("init", "expr"), ("condition_phi", "expr"), ("condition", "expr"), ("update", "expr"), ("body", "expr")], HighLevelILOperation.HLIL_SWITCH: [("condition", "expr"), ("default", "expr"), ("cases", "expr_list")], HighLevelILOperation.HLIL_CASE: [("values", "expr_list"), ("body", "expr")], HighLevelILOperation.HLIL_BREAK: [], @@ -198,10 +201,14 @@ class HighLevelILInstruction(object): HighLevelILOperation.HLIL_FCMP_UO: [("left", "expr"), ("right", "expr")] } - def __init__(self, func, expr_index, as_ast = True): - instr = core.BNGetHighLevelILByIndex(func.handle, expr_index) + def __init__(self, func, expr_index, as_ast = True, instr_index = None): + instr = core.BNGetHighLevelILByIndex(func.handle, expr_index, as_ast) self._function = func self._expr_index = expr_index + if instr_index is None: + self._instr_index = core.BNGetHighLevelILInstructionForExpr(func.handle, expr_index) + else: + self._instr_index = instr_index self._operation = HighLevelILOperation(instr.operation) self._size = instr.size self._address = instr.address @@ -383,7 +390,7 @@ class HighLevelILInstruction(object): @property def non_ast(self): """This expression without full AST printing (read-only)""" - if self._as_ast: + if not self._as_ast: return self return HighLevelILInstruction(self._function, self._expr_index, False) @@ -438,6 +445,28 @@ class HighLevelILInstruction(object): return None return HighLevelILInstruction(self._function, self._parent, self._as_ast) + @property + def instr_index(self): + """ """ + return self._instr_index + + @property + def instr(self): + """High level IL instruction that contains this expression""" + return self._function[self._instr_index] + + @property + def ssa_form(self): + """SSA form of expression (read-only)""" + return HighLevelILInstruction(self._function.ssa_form, + core.BNGetHighLevelILSSAExprIndex(self._function.handle, self._expr_index), self._as_ast) + + @property + def non_ssa_form(self): + """Non-SSA form of expression (read-only)""" + return HighLevelILInstruction(self._function.non_ssa_form, + core.BNGetHighLevelILNonSSAExprIndex(self._function.handle, self._expr_index), self._as_ast) + @property def medium_level_il(self): """Medium level IL form of this expression""" @@ -489,6 +518,18 @@ class HighLevelILInstruction(object): return function.RegisterValue() return mlil.get_possible_values(options) + @property + def ssa_memory_version(self): + """Version of active memory contents in SSA form for this instruction""" + return core.BNGetHighLevelILSSAMemoryVersionAtILInstruction(self._function.handle, self._instr_index) + + def get_ssa_var_version(self, var): + var_data = core.BNVariable() + var_data.type = var.source_type + var_data.index = var.index + var_data.storage = var.storage + return core.BNGetHighLevelILSSAVarVersionAtILInstruction(self._function.handle, var_data, self._instr_index) + class HighLevelILExpr(object): """ @@ -597,6 +638,106 @@ class HighLevelILFunction(object): for i in block: yield i + @property + def ssa_form(self): + """High level IL in SSA form (read-only)""" + result = core.BNGetHighLevelILSSAForm(self.handle) + if not result: + return None + return HighLevelILFunction(self._arch, result, self._source_function) + + @property + def non_ssa_form(self): + """High level IL in non-SSA (default) form (read-only)""" + result = core.BNGetHighLevelILNonSSAForm(self.handle) + if not result: + return None + return HighLevelILFunction(self._arch, result, self._source_function) + + def get_ssa_instruction_index(self, instr): + return core.BNGetHighLevelILSSAInstructionIndex(self.handle, instr) + + def get_non_ssa_instruction_index(self, instr): + return core.BNGetHighLevelILNonSSAInstructionIndex(self.handle, instr) + + def get_ssa_var_definition(self, ssa_var): + var_data = core.BNVariable() + var_data.type = ssa_var.var.source_type + var_data.index = ssa_var.var.index + var_data.storage = ssa_var.var.storage + result = core.BNGetHighLevelILSSAVarDefinition(self.handle, var_data, ssa_var.version) + if result >= core.BNGetHighLevelILExprCount(self.handle): + return None + return HighLevelILInstruction(self, result) + + def get_ssa_memory_definition(self, version): + result = core.BNGetHighLevelILSSAMemoryDefinition(self.handle, version) + if result >= core.BNGetHighLevelILExprCount(self.handle): + return None + return HighLevelILInstruction(self, result) + + def get_ssa_var_uses(self, ssa_var): + count = ctypes.c_ulonglong() + var_data = core.BNVariable() + var_data.type = ssa_var.var.source_type + var_data.index = ssa_var.var.index + var_data.storage = ssa_var.var.storage + instrs = core.BNGetHighLevelILSSAVarUses(self.handle, var_data, ssa_var.version, count) + result = [] + for i in range(0, count.value): + result.append(HighLevelILInstruction(self, instrs[i])) + core.BNFreeILInstructionList(instrs) + return result + + def get_ssa_memory_uses(self, version): + count = ctypes.c_ulonglong() + instrs = core.BNGetHighLevelILSSAMemoryUses(self.handle, version, count) + result = [] + for i in range(0, count.value): + result.append(HighLevelILInstruction(self, instrs[i])) + core.BNFreeILInstructionList(instrs) + return result + + def is_ssa_var_live(self, ssa_var): + """ + ``is_ssa_var_live`` determines if ``ssa_var`` is live at any point in the function + + :param SSAVariable ssa_var: the SSA variable to query + :return: whether the variable is live at any point in the function + :rtype: bool + """ + var_data = core.BNVariable() + var_data.type = ssa_var.var.source_type + var_data.index = ssa_var.var.index + var_data.storage = ssa_var.var.storage + return core.BNIsHighLevelILSSAVarLive(self.handle, var_data, ssa_var.version) + + def get_var_definitions(self, var): + count = ctypes.c_ulonglong() + var_data = core.BNVariable() + var_data.type = var.source_type + var_data.index = var.index + var_data.storage = var.storage + instrs = core.BNGetHighLevelILVariableDefinitions(self.handle, var_data, count) + result = [] + for i in range(0, count.value): + result.append(HighLevelILInstruction(self, instrs[i])) + core.BNFreeILInstructionList(instrs) + return result + + def get_var_uses(self, var): + count = ctypes.c_ulonglong() + var_data = core.BNVariable() + var_data.type = var.source_type + var_data.index = var.index + var_data.storage = var.storage + instrs = core.BNGetHighLevelILVariableUses(self.handle, var_data, count) + result = [] + for i in range(0, count.value): + result.append(HighLevelILInstruction(self, instrs[i])) + core.BNFreeILInstructionList(instrs) + return result + def __setattr__(self, name, value): try: object.__setattr__(self, name, value) @@ -616,7 +757,7 @@ class HighLevelILFunction(object): return i if (i < 0) or (i >= len(self)): raise IndexError("index out of range") - return HighLevelILInstruction(self, core.BNGetHighLevelILIndexForInstruction(self.handle, i), False) + return HighLevelILInstruction(self, core.BNGetHighLevelILIndexForInstruction(self.handle, i), False, i) def __setitem__(self, i, j): raise IndexError("instruction modification not implemented") diff --git a/python/lineardisassembly.py b/python/lineardisassembly.py index 10124bad..4435acdc 100644 --- a/python/lineardisassembly.py +++ b/python/lineardisassembly.py @@ -306,6 +306,12 @@ class LinearViewObject(object): settings = settings.handle return LinearViewObject(core.BNCreateLinearViewHighLevelIL(view.handle, settings)) + @classmethod + def hlil_ssa_form(cls, view, settings = None): + if settings is not None: + settings = settings.handle + return LinearViewObject(core.BNCreateLinearViewHighLevelILSSAForm(view.handle, settings)) + class LinearViewCursor(object): def __init__(self, root_object, handle = None): -- cgit v1.3.1