diff options
| author | Peter LaFosse <peter@vector35.com> | 2018-09-12 17:03:38 -0400 |
|---|---|---|
| committer | Peter LaFosse <peter@vector35.com> | 2018-09-12 17:03:38 -0400 |
| commit | 74a8547853dd66fe62d2e75b93c1b723eb6f69cf (patch) | |
| tree | 067119496c2beaf0636c955d27291d4620e17c0b | |
| parent | 097a2e4c8849d4938d8a027985ce3816fd9785ed (diff) | |
| parent | 59a2824b1ad36ea5d0520919e86ad779cd97cc8f (diff) | |
Merging with dev
| -rw-r--r-- | basicblock.cpp | 16 | ||||
| -rw-r--r-- | binaryninjaapi.h | 192 | ||||
| -rw-r--r-- | binaryninjacore.h | 236 | ||||
| -rw-r--r-- | binaryview.cpp | 8 | ||||
| -rw-r--r-- | docs/getting-started.md | 14 | ||||
| -rw-r--r-- | flowgraph.cpp | 358 | ||||
| -rw-r--r-- | flowgraphnode.cpp | 206 | ||||
| -rw-r--r-- | function.cpp | 70 | ||||
| -rw-r--r-- | functiongraph.cpp | 224 | ||||
| -rw-r--r-- | functiongraphblock.cpp | 146 | ||||
| -rw-r--r-- | interaction.cpp | 140 | ||||
| -rw-r--r-- | lowlevelil.cpp | 7 | ||||
| -rw-r--r-- | lowlevelilinstruction.cpp | 6 | ||||
| -rw-r--r-- | lowlevelilinstruction.h | 6 | ||||
| -rw-r--r-- | mediumlevelil.cpp | 7 | ||||
| -rw-r--r-- | mediumlevelilinstruction.cpp | 9 | ||||
| -rw-r--r-- | mediumlevelilinstruction.h | 4 | ||||
| -rw-r--r-- | python/__init__.py | 2 | ||||
| -rw-r--r-- | python/basicblock.py | 12 | ||||
| -rw-r--r-- | python/binaryview.py | 7 | ||||
| -rw-r--r-- | python/flowgraph.py | 633 | ||||
| -rw-r--r-- | python/function.py | 437 | ||||
| -rw-r--r-- | python/highlight.py | 10 | ||||
| -rw-r--r-- | python/interaction.py | 173 | ||||
| -rw-r--r-- | python/lowlevelil.py | 14 | ||||
| -rw-r--r-- | python/mainthread.py | 3 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 16 | ||||
| -rw-r--r-- | python/types.py | 2 | ||||
| -rw-r--r-- | type.cpp | 10 |
29 files changed, 2025 insertions, 943 deletions
diff --git a/basicblock.cpp b/basicblock.cpp index 13b3e7a8..9fc8d8aa 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -72,6 +72,21 @@ void DisassemblySettings::SetMaximumSymbolWidth(size_t width) } +DisassemblyTextLine::DisassemblyTextLine() +{ + addr = 0; + instrIndex = BN_INVALID_EXPR; + highlight.style = StandardHighlightColor; + highlight.color = NoHighlightColor; + highlight.mixColor = NoHighlightColor; + highlight.mix = 0; + highlight.r = 0; + highlight.g = 0; + highlight.b = 0; + highlight.alpha = 0; +} + + BasicBlock::BasicBlock(BNBasicBlock* block) { m_object = block; @@ -277,6 +292,7 @@ vector<DisassemblyTextLine> BasicBlock::GetDisassemblyText(DisassemblySettings* DisassemblyTextLine line; line.addr = lines[i].addr; line.instrIndex = lines[i].instrIndex; + line.highlight = lines[i].highlight; line.tokens.reserve(lines[i].count); for (size_t j = 0; j < lines[i].count; j++) { diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 93fa9eda..647d2677 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -54,6 +54,7 @@ namespace BinaryNinja virtual ~RefCountObject() {} RefCountObject* GetObject() { return this; } + static RefCountObject* GetObject(RefCountObject* obj) { return obj; } void AddRef() { @@ -107,6 +108,13 @@ namespace BinaryNinja T* GetObject() const { return m_object; } + static T* GetObject(CoreRefCountObject* obj) + { + if (!obj) + return nullptr; + return obj->GetObject(); + } + void AddRef() { if (m_object && (m_refs != 0)) @@ -164,6 +172,13 @@ namespace BinaryNinja T* GetObject() const { return m_object; } + static T* GetObject(StaticCoreRefCountObject* obj) + { + if (!obj) + return nullptr; + return obj->GetObject(); + } + void AddRef() { AddRefInternal(); @@ -252,32 +267,32 @@ namespace BinaryNinja bool operator==(const T* obj) const { - return m_obj->GetObject() == obj->GetObject(); + return T::GetObject(m_obj) == T::GetObject(obj); } bool operator==(const Ref<T>& obj) const { - return m_obj->GetObject() == obj.m_obj->GetObject(); + return T::GetObject(m_obj) == T::GetObject(obj.m_obj); } bool operator!=(const T* obj) const { - return m_obj->GetObject() != obj->GetObject(); + return T::GetObject(m_obj) != T::GetObject(obj); } bool operator!=(const Ref<T>& obj) const { - return m_obj->GetObject() != obj.m_obj->GetObject(); + return T::GetObject(m_obj) != T::GetObject(obj.m_obj); } bool operator<(const T* obj) const { - return m_obj->GetObject() < obj->GetObject(); + return T::GetObject(m_obj) < T::GetObject(obj); } bool operator<(const Ref<T>& obj) const { - return m_obj->GetObject() < obj.m_obj->GetObject(); + return T::GetObject(m_obj) < T::GetObject(obj.m_obj); } T* GetPtr() const @@ -494,6 +509,8 @@ namespace BinaryNinja class MainThreadActionHandler; class InteractionHandler; class QualifiedName; + class FlowGraph; + class ReportCollection; struct FormInputField; /*! Logs to the error console with the given BNLogLevel. @@ -627,6 +644,8 @@ namespace BinaryNinja const std::string& plainText = ""); void ShowHTMLReport(const std::string& title, const std::string& contents, const std::string& plainText = ""); + void ShowGraphReport(const std::string& title, FlowGraph* graph); + void ShowReportCollection(const std::string& title, ReportCollection* reports); bool GetTextLineInput(std::string& result, const std::string& prompt, const std::string& title); bool GetIntegerInput(int64_t& result, const std::string& prompt, const std::string& title); @@ -940,6 +959,9 @@ namespace BinaryNinja uint64_t addr; size_t instrIndex; std::vector<InstructionTextToken> tokens; + BNHighlightColor highlight; + + DisassemblyTextLine(); }; struct LinearDisassemblyPosition @@ -1321,6 +1343,7 @@ namespace BinaryNinja void ShowPlainTextReport(const std::string& title, const std::string& contents); void ShowMarkdownReport(const std::string& title, const std::string& contents, const std::string& plainText); void ShowHTMLReport(const std::string& title, const std::string& contents, const std::string& plainText); + void ShowGraphReport(const std::string& title, FlowGraph* graph); bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title); bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title, uint64_t currentAddress); @@ -2173,7 +2196,7 @@ namespace BinaryNinja void SetConst(const Confidence<bool>& cnst); void SetVolatile(const Confidence<bool>& vltl); void SetTypeName(const QualifiedName& name); - Confidence<size_t> GetStackAdjustment() const; + Confidence<int64_t> GetStackAdjustment() const; uint64_t GetElementCount() const; uint64_t GetOffset() const; @@ -2214,7 +2237,7 @@ namespace BinaryNinja static Ref<Type> FunctionType(const Confidence<Ref<Type>>& returnValue, const Confidence<Ref<CallingConvention>>& callingConvention, const std::vector<FunctionParameter>& params, const Confidence<bool>& varArg = Confidence<bool>(false, 0), - const Confidence<size_t>& stackAdjust = Confidence<size_t>(0, 0)); + const Confidence<int64_t>& stackAdjust = Confidence<int64_t>(0, 0)); static std::string GenerateAutoTypeId(const std::string& source, const QualifiedName& name); static std::string GenerateAutoDemangledTypeId(const QualifiedName& name); @@ -2441,7 +2464,7 @@ namespace BinaryNinja static PossibleValueSet FromAPIObject(BNPossibleValueSet& value); }; - class FunctionGraph; + class FlowGraph; class MediumLevelILFunction; class Function: public CoreRefCountObject<BNFunction, BNNewFunctionReference, BNFreeFunction> @@ -2452,6 +2475,7 @@ namespace BinaryNinja Function(BNFunction* func); virtual ~Function(); + Ref<BinaryView> GetView() const; Ref<Architecture> GetArchitecture() const; Ref<Platform> GetPlatform() const; uint64_t GetStart() const; @@ -2500,7 +2524,7 @@ namespace BinaryNinja Confidence<Ref<CallingConvention>> GetCallingConvention() const; Confidence<std::vector<Variable>> GetParameterVariables() const; Confidence<bool> HasVariableArguments() const; - Confidence<size_t> GetStackAdjustment() const; + Confidence<int64_t> GetStackAdjustment() const; std::map<uint32_t, Confidence<int32_t>> GetRegisterStackAdjustments() const; Confidence<std::set<uint32_t>> GetClobberedRegisters() const; @@ -2511,7 +2535,7 @@ namespace BinaryNinja void SetAutoParameterVariables(const Confidence<std::vector<Variable>>& vars); void SetAutoHasVariableArguments(const Confidence<bool>& varArgs); void SetAutoCanReturn(const Confidence<bool>& returns); - void SetAutoStackAdjustment(const Confidence<size_t>& stackAdjust); + void SetAutoStackAdjustment(const Confidence<int64_t>& stackAdjust); void SetAutoRegisterStackAdjustments(const std::map<uint32_t, Confidence<int32_t>>& regStackAdjust); void SetAutoClobberedRegisters(const Confidence<std::set<uint32_t>>& clobbered); @@ -2522,14 +2546,14 @@ namespace BinaryNinja void SetParameterVariables(const Confidence<std::vector<Variable>>& vars); void SetHasVariableArguments(const Confidence<bool>& varArgs); void SetCanReturn(const Confidence<bool>& returns); - void SetStackAdjustment(const Confidence<size_t>& stackAdjust); + void SetStackAdjustment(const Confidence<int64_t>& stackAdjust); void SetRegisterStackAdjustments(const std::map<uint32_t, Confidence<int32_t>>& regStackAdjust); void SetClobberedRegisters(const Confidence<std::set<uint32_t>>& clobbered); void ApplyImportedTypes(Symbol* sym); void ApplyAutoDiscoveredType(Type* type); - Ref<FunctionGraph> CreateFunctionGraph(); + Ref<FlowGraph> CreateFunctionGraph(BNFunctionGraphType type, DisassemblySettings* settings = nullptr); std::map<int64_t, std::vector<VariableNameAndType>> GetStackLayout(); void CreateAutoStackVariable(int64_t offset, const Confidence<Ref<Type>>& type, const std::string& name); @@ -2554,20 +2578,21 @@ namespace BinaryNinja std::vector<IndirectBranchInfo> GetIndirectBranches(); std::vector<IndirectBranchInfo> GetIndirectBranchesAt(Architecture* arch, uint64_t addr); - void SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<size_t>& adjust); + void SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<int64_t>& adjust); void SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, const std::map<uint32_t, Confidence<int32_t>>& adjust); void SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack, const Confidence<int32_t>& adjust); - void SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<size_t>& adjust); + void SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<int64_t>& adjust); void SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, const std::map<uint32_t, Confidence<int32_t>>& adjust); void SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack, const Confidence<int32_t>& adjust); - Confidence<size_t> GetCallStackAdjustment(Architecture* arch, uint64_t addr); + Confidence<int64_t> GetCallStackAdjustment(Architecture* arch, uint64_t addr); std::map<uint32_t, Confidence<int32_t>> GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr); Confidence<int32_t> GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack); + bool IsCallInstruction(Architecture* arch, uint64_t addr); std::vector<std::vector<InstructionTextToken>> GetBlockAnnotations(Architecture* arch, uint64_t addr); @@ -2610,6 +2635,10 @@ namespace BinaryNinja BNAnalysisSkipReason GetAnalysisSkipReason(); BNFunctionAnalysisSkipOverride GetAnalysisSkipOverride(); void SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip); + + Ref<FlowGraph> GetUnresolvedStackAdjustmentGraph(); + + void RequestDebugReport(const std::string& name); }; class AdvancedFunctionAnalysisDataRequestor @@ -2626,79 +2655,118 @@ namespace BinaryNinja void SetFunction(Function* func); }; - struct FunctionGraphEdge + class FlowGraphNode; + + struct FlowGraphEdge { BNBranchType type; - Ref<BasicBlock> target; + Ref<FlowGraphNode> target; std::vector<BNPoint> points; bool backEdge; }; - class FunctionGraphBlock: public CoreRefCountObject<BNFunctionGraphBlock, - BNNewFunctionGraphBlockReference, BNFreeFunctionGraphBlock> + class FlowGraphNode: public CoreRefCountObject<BNFlowGraphNode, + BNNewFlowGraphNodeReference, BNFreeFlowGraphNode> { std::vector<DisassemblyTextLine> m_cachedLines; - std::vector<FunctionGraphEdge> m_cachedEdges; + std::vector<FlowGraphEdge> m_cachedEdges; bool m_cachedLinesValid, m_cachedEdgesValid; public: - FunctionGraphBlock(BNFunctionGraphBlock* block); + FlowGraphNode(FlowGraph* graph); + FlowGraphNode(BNFlowGraphNode* node); Ref<BasicBlock> GetBasicBlock() const; - Ref<Architecture> GetArchitecture() const; - uint64_t GetStart() const; - uint64_t GetEnd() const; + void SetBasicBlock(BasicBlock* block); int GetX() const; int GetY() const; int GetWidth() const; int GetHeight() const; const std::vector<DisassemblyTextLine>& GetLines(); - const std::vector<FunctionGraphEdge>& GetOutgoingEdges(); + void SetLines(const std::vector<DisassemblyTextLine>& lines); + const std::vector<FlowGraphEdge>& GetOutgoingEdges(); + void AddOutgoingEdge(BNBranchType type, FlowGraphNode* target); + + BNHighlightColor GetHighlight() const; + void SetHighlight(const BNHighlightColor& color); }; - class FunctionGraph: public RefCountObject + class FlowGraphLayoutRequest: public RefCountObject { - BNFunctionGraph* m_graph; + BNFlowGraphLayoutRequest* m_object; std::function<void()> m_completeFunc; - std::map<BNFunctionGraphBlock*, Ref<FunctionGraphBlock>> m_cachedBlocks; static void CompleteCallback(void* ctxt); public: - FunctionGraph(BNFunctionGraph* graph); - ~FunctionGraph(); + FlowGraphLayoutRequest(FlowGraph* graph, const std::function<void()>& completeFunc); + virtual ~FlowGraphLayoutRequest(); - BNFunctionGraph* GetGraphObject() const { return m_graph; } + BNFlowGraphLayoutRequest* GetObject() const { return m_object; } - Ref<Function> GetFunction() const; + Ref<FlowGraph> GetGraph() const; + bool IsComplete() const; + void Abort(); + }; + + class FlowGraph: public CoreRefCountObject<BNFlowGraph, BNNewFlowGraphReference, BNFreeFlowGraph> + { + std::map<BNFlowGraphNode*, Ref<FlowGraphNode>> m_cachedNodes; + + static void PrepareForLayoutCallback(void* ctxt); + static void PopulateNodesCallback(void* ctxt); + static void CompleteLayoutCallback(void* ctxt); + static BNFlowGraph* UpdateCallback(void* ctxt); + + protected: + FlowGraph(BNFlowGraph* graph); - int GetHorizontalBlockMargin() const; - int GetVerticalBlockMargin() const; - void SetBlockMargins(int horiz, int vert); + void FinishPrepareForLayout(); + virtual void PrepareForLayout(); + virtual void PopulateNodes(); + virtual void CompleteLayout(); - Ref<DisassemblySettings> GetSettings(); + public: + FlowGraph(); + + Ref<Function> GetFunction() const; + void SetFunction(Function* func); + + int GetHorizontalNodeMargin() const; + int GetVerticalNodeMargin() const; + void SetNodeMargins(int horiz, int vert); - void StartLayout(BNFunctionGraphType = NormalFunctionGraph); + Ref<FlowGraphLayoutRequest> StartLayout(const std::function<void()>& func); bool IsLayoutComplete(); - void OnComplete(const std::function<void()>& func); - void Abort(); - std::vector<Ref<FunctionGraphBlock>> GetBlocks(); - bool HasBlocks() const; + std::vector<Ref<FlowGraphNode>> GetNodes(); + Ref<FlowGraphNode> GetNode(size_t i); + bool HasNodes() const; + size_t AddNode(FlowGraphNode* node); int GetWidth() const; int GetHeight() const; - std::vector<Ref<FunctionGraphBlock>> GetBlocksInRegion(int left, int top, int right, int bottom); - - bool IsOptionSet(BNDisassemblyOption option) const; - void SetOption(BNDisassemblyOption option, bool state = true); + std::vector<Ref<FlowGraphNode>> GetNodesInRegion(int left, int top, int right, int bottom); bool IsILGraph() const; bool IsLowLevelILGraph() const; bool IsMediumLevelILGraph() const; Ref<LowLevelILFunction> GetLowLevelILFunction() const; Ref<MediumLevelILFunction> GetMediumLevelILFunction() const; + void SetLowLevelILFunction(LowLevelILFunction* func); + void SetMediumLevelILFunction(MediumLevelILFunction* func); + + void Show(const std::string& title); + + virtual Ref<FlowGraph> Update(); + }; + + class CoreFlowGraph: public FlowGraph + { + public: + CoreFlowGraph(BNFlowGraph* graph); + virtual Ref<FlowGraph> Update() override; }; struct LowLevelILLabel: public BNLowLevelILLabel @@ -2895,7 +2963,7 @@ namespace BinaryNinja ExprId JumpTo(ExprId dest, const std::vector<BNLowLevelILLabel*>& targets, const ILSourceLocation& loc = ILSourceLocation()); ExprId Call(ExprId dest, const ILSourceLocation& loc = ILSourceLocation()); - ExprId CallStackAdjust(ExprId dest, size_t adjust, const std::map<uint32_t, int32_t>& regStackAdjust, + ExprId CallStackAdjust(ExprId dest, int64_t adjust, const std::map<uint32_t, int32_t>& regStackAdjust, const ILSourceLocation& loc = ILSourceLocation()); ExprId TailCall(ExprId dest, const ILSourceLocation& loc = ILSourceLocation()); ExprId CallSSA(const std::vector<SSARegister>& output, ExprId dest, const std::vector<ExprId>& params, @@ -3073,6 +3141,8 @@ namespace BinaryNinja size_t GetMappedMediumLevelILExprIndex(size_t expr) const; static bool IsConstantType(BNLowLevelILOperation type) { return type == LLIL_CONST || type == LLIL_CONST_PTR || type == LLIL_EXTERN_PTR; } + + Ref<FlowGraph> CreateFunctionGraph(DisassemblySettings* settings = nullptr); }; struct MediumLevelILLabel: public BNMediumLevelILLabel @@ -3216,6 +3286,7 @@ namespace BinaryNinja ExprId Jump(ExprId dest, const ILSourceLocation& loc = ILSourceLocation()); ExprId JumpTo(ExprId dest, const std::vector<BNMediumLevelILLabel*>& targets, const ILSourceLocation& loc = ILSourceLocation()); + ExprId ReturnHint(ExprId dest, const ILSourceLocation& loc = ILSourceLocation()); ExprId Call(const std::vector<Variable>& output, ExprId dest, const std::vector<ExprId>& params, const ILSourceLocation& loc = ILSourceLocation()); ExprId CallUntyped(const std::vector<Variable>& output, ExprId dest, const std::vector<Variable>& params, @@ -3406,6 +3477,8 @@ namespace BinaryNinja Confidence<Ref<Type>> GetExprType(const MediumLevelILInstruction& expr); static bool IsConstantType(BNMediumLevelILOperation op) { return op == MLIL_CONST || op == MLIL_CONST_PTR || op == MLIL_EXTERN_PTR; } + + Ref<FlowGraph> CreateFunctionGraph(DisassemblySettings* settings = nullptr); }; class FunctionRecognizer @@ -4009,6 +4082,29 @@ namespace BinaryNinja static FormInputField DirectoryName(const std::string& prompt, const std::string& defaultName = ""); }; + class ReportCollection: public CoreRefCountObject<BNReportCollection, + BNNewReportCollectionReference, BNFreeReportCollection> + { + public: + ReportCollection(); + ReportCollection(BNReportCollection* reports); + + size_t GetCount() const; + BNReportType GetType(size_t i) const; + Ref<BinaryView> GetView(size_t i) const; + std::string GetTitle(size_t i) const; + std::string GetContents(size_t i) const; + std::string GetPlainText(size_t i) const; + Ref<FlowGraph> GetFlowGraph(size_t i) const; + + void AddPlainTextReport(Ref<BinaryView> view, const std::string& title, const std::string& contents); + void AddMarkdownReport(Ref<BinaryView> view, const std::string& title, const std::string& contents, + const std::string& plainText = ""); + void AddHTMLReport(Ref<BinaryView> view, const std::string& title, const std::string& contents, + const std::string& plainText = ""); + void AddGraphReport(Ref<BinaryView> view, const std::string& title, Ref<FlowGraph> graph); + }; + class InteractionHandler { public: @@ -4017,6 +4113,8 @@ namespace BinaryNinja const std::string& plainText); virtual void ShowHTMLReport(Ref<BinaryView> view, const std::string& title, const std::string& contents, const std::string& plainText); + virtual void ShowGraphReport(Ref<BinaryView> view, const std::string& title, Ref<FlowGraph> graph); + virtual void ShowReportCollection(const std::string& title, Ref<ReportCollection> reports); virtual bool GetTextLineInput(std::string& result, const std::string& prompt, const std::string& title) = 0; virtual bool GetIntegerInput(int64_t& result, const std::string& prompt, const std::string& title); diff --git a/binaryninjacore.h b/binaryninjacore.h index 6597b335..984fb43b 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -124,8 +124,9 @@ extern "C" struct BNBasicBlock; struct BNDownloadProvider; struct BNDownloadInstance; - struct BNFunctionGraph; - struct BNFunctionGraphBlock; + struct BNFlowGraph; + struct BNFlowGraphNode; + struct BNFlowGraphLayoutRequest; struct BNSymbol; struct BNTemporaryFile; struct BNLowLevelILFunction; @@ -146,6 +147,7 @@ extern "C" struct BNRepoPlugin; struct BNRepositoryManager; struct BNMetadata; + struct BNReportCollection; struct BNRelocation; struct BNSegment; struct BNSection; @@ -874,6 +876,7 @@ extern "C" MLIL_LOW_PART, MLIL_JUMP, MLIL_JUMP_TO, + MLIL_RET_HINT, // Intermediate stages, does not appear in final forms MLIL_CALL, // Not valid in SSA form (see MLIL_CALL_SSA) MLIL_CALL_UNTYPED, // Not valid in SSA form (see MLIL_CALL_UNTYPED_SSA) MLIL_CALL_OUTPUT, // Only valid within MLIL_CALL, MLIL_SYSCALL, MLIL_TAILCALL family instructions @@ -1275,21 +1278,51 @@ extern "C" float y; }; - struct BNFunctionGraphEdge + struct BNFlowGraphEdge { BNBranchType type; - BNBasicBlock* target; + BNFlowGraphNode* target; BNPoint* points; size_t pointCount; bool backEdge; }; + enum BNHighlightColorStyle + { + StandardHighlightColor = 0, + MixedHighlightColor = 1, + CustomHighlightColor = 2 + }; + + enum BNHighlightStandardColor + { + NoHighlightColor = 0, + BlueHighlightColor = 1, + GreenHighlightColor = 2, + CyanHighlightColor = 3, + RedHighlightColor = 4, + MagentaHighlightColor = 5, + YellowHighlightColor = 6, + OrangeHighlightColor = 7, + WhiteHighlightColor = 8, + BlackHighlightColor = 9 + }; + + struct BNHighlightColor + { + BNHighlightColorStyle style; + BNHighlightStandardColor color; + BNHighlightStandardColor mixColor; + uint8_t mix, r, g, b, alpha; + }; + struct BNDisassemblyTextLine { uint64_t addr; size_t instrIndex; BNInstructionTextToken* tokens; size_t count; + BNHighlightColor highlight; }; struct BNLinearDisassemblyLine @@ -1343,6 +1376,12 @@ extern "C" uint8_t confidence; }; + struct BNOffsetWithConfidence + { + int64_t value; + uint8_t confidence; + }; + struct BNMemberScopeWithConfidence { BNMemberScope value; @@ -1688,35 +1727,6 @@ extern "C" BNMetadata** values; }; - enum BNHighlightColorStyle - { - StandardHighlightColor = 0, - MixedHighlightColor = 1, - CustomHighlightColor = 2 - }; - - enum BNHighlightStandardColor - { - NoHighlightColor = 0, - BlueHighlightColor = 1, - GreenHighlightColor = 2, - CyanHighlightColor = 3, - RedHighlightColor = 4, - MagentaHighlightColor = 5, - YellowHighlightColor = 6, - OrangeHighlightColor = 7, - WhiteHighlightColor = 8, - BlackHighlightColor = 9 - }; - - struct BNHighlightColor - { - BNHighlightColorStyle style; - BNHighlightStandardColor color; - BNHighlightStandardColor mixColor; - uint8_t mix, r, g, b, alpha; - }; - enum BNMessageBoxIcon { InformationIcon, @@ -1778,6 +1788,8 @@ extern "C" const char* plaintext); void (*showHTMLReport)(void* ctxt, BNBinaryView* view, const char* title, const char* contents, const char* plaintext); + void (*showGraphReport)(void* ctxt, BNBinaryView* view, const char* title, BNFlowGraph* graph); + void (*showReportCollection)(void* ctxt, const char* title, BNReportCollection* reports); bool (*getTextLineInput)(void* ctxt, char** result, const char* prompt, const char* title); bool (*getIntegerInput)(void* ctxt, int64_t* result, const char* prompt, const char* title); bool (*getAddressInput)(void* ctxt, uint64_t* result, const char* prompt, const char* title, @@ -1883,6 +1895,23 @@ extern "C" AlwaysSkipFunctionAnalysis }; + enum BNReportType + { + PlainTextReportType, + MarkdownReportType, + HTMLReportType, + FlowGraphReportType + }; + + struct BNCustomFlowGraph + { + void* context; + void (*prepareForLayout)(void* ctxt); + void (*populateNodes)(void* ctxt); + void (*completeLayout)(void* ctxt); + BNFlowGraph* (*update)(void* ctxt); + }; + struct BNRange { uint64_t start; @@ -2462,7 +2491,7 @@ extern "C" BINARYNINJACOREAPI BNParameterVariablesWithConfidence BNGetFunctionParameterVariables(BNFunction* func); BINARYNINJACOREAPI void BNFreeParameterVariables(BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI BNBoolWithConfidence BNFunctionHasVariableArguments(BNFunction* func); - BINARYNINJACOREAPI BNSizeWithConfidence BNGetFunctionStackAdjustment(BNFunction* func); + BINARYNINJACOREAPI BNOffsetWithConfidence BNGetFunctionStackAdjustment(BNFunction* func); BINARYNINJACOREAPI BNRegisterStackAdjustment* BNGetFunctionRegisterStackAdjustments(BNFunction* func, size_t* count); BINARYNINJACOREAPI void BNFreeRegisterStackAdjustments(BNRegisterStackAdjustment* adjustments); BINARYNINJACOREAPI BNRegisterSetWithConfidence BNGetFunctionClobberedRegisters(BNFunction* func); @@ -2474,7 +2503,7 @@ extern "C" BINARYNINJACOREAPI void BNSetAutoFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI void BNSetAutoFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); BINARYNINJACOREAPI void BNSetAutoFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns); - BINARYNINJACOREAPI void BNSetAutoFunctionStackAdjustment(BNFunction* func, BNSizeWithConfidence* stackAdjust); + BINARYNINJACOREAPI void BNSetAutoFunctionStackAdjustment(BNFunction* func, BNOffsetWithConfidence* stackAdjust); BINARYNINJACOREAPI void BNSetAutoFunctionRegisterStackAdjustments(BNFunction* func, BNRegisterStackAdjustment* adjustments, size_t count); BINARYNINJACOREAPI void BNSetAutoFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); @@ -2485,7 +2514,7 @@ extern "C" BINARYNINJACOREAPI void BNSetUserFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars); BINARYNINJACOREAPI void BNSetUserFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs); BINARYNINJACOREAPI void BNSetUserFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns); - BINARYNINJACOREAPI void BNSetUserFunctionStackAdjustment(BNFunction* func, BNSizeWithConfidence* stackAdjust); + BINARYNINJACOREAPI void BNSetUserFunctionStackAdjustment(BNFunction* func, BNOffsetWithConfidence* stackAdjust); BINARYNINJACOREAPI void BNSetUserFunctionRegisterStackAdjustments(BNFunction* func, BNRegisterStackAdjustment* adjustments, size_t count); BINARYNINJACOREAPI void BNSetUserFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs); @@ -2578,9 +2607,9 @@ extern "C" BINARYNINJACOREAPI void BNFreeIndirectBranchList(BNIndirectBranchInfo* branches); BINARYNINJACOREAPI void BNSetAutoCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, - size_t adjust, uint8_t confidence); + int64_t adjust, uint8_t confidence); BINARYNINJACOREAPI void BNSetUserCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, - size_t adjust, uint8_t confidence); + int64_t adjust, uint8_t confidence); BINARYNINJACOREAPI void BNSetAutoCallRegisterStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, BNRegisterStackAdjustment* adjust, size_t count); BINARYNINJACOREAPI void BNSetUserCallRegisterStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, @@ -2590,11 +2619,12 @@ extern "C" BINARYNINJACOREAPI void BNSetUserCallRegisterStackAdjustmentForRegisterStack(BNFunction* func, BNArchitecture* arch, uint64_t addr, uint32_t regStack, int32_t adjust, uint8_t confidence); - BINARYNINJACOREAPI BNSizeWithConfidence BNGetCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr); + BINARYNINJACOREAPI BNOffsetWithConfidence BNGetCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr); BINARYNINJACOREAPI BNRegisterStackAdjustment* BNGetCallRegisterStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr, size_t* count); BINARYNINJACOREAPI BNRegisterStackAdjustment BNGetCallRegisterStackAdjustmentForRegisterStack(BNFunction* func, BNArchitecture* arch, uint64_t addr, uint32_t regStack); + BINARYNINJACOREAPI bool BNIsCallInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr); BINARYNINJACOREAPI BNInstructionTextLine* BNGetFunctionBlockAnnotations(BNFunction* func, BNArchitecture* arch, uint64_t addr, size_t* count); @@ -2698,6 +2728,10 @@ extern "C" BINARYNINJACOREAPI BNPerformanceInfo* BNGetFunctionAnalysisPerformanceInfo(BNFunction* func, size_t* count); BINARYNINJACOREAPI void BNFreeAnalysisPerformanceInfo(BNPerformanceInfo* info, size_t count); + BINARYNINJACOREAPI BNFlowGraph* BNGetUnresolvedStackAdjustmentGraph(BNFunction* func); + + BINARYNINJACOREAPI void BNRequestFunctionDebugReport(BNFunction* func, const char* name); + // Disassembly settings BINARYNINJACOREAPI BNDisassemblySettings* BNCreateDisassemblySettings(void); BINARYNINJACOREAPI BNDisassemblySettings* BNNewDisassemblySettingsReference(BNDisassemblySettings* settings); @@ -2713,56 +2747,73 @@ extern "C" BINARYNINJACOREAPI size_t BNGetDisassemblyMaximumSymbolWidth(BNDisassemblySettings* settings); BINARYNINJACOREAPI void BNSetDisassemblyMaximumSymbolWidth(BNDisassemblySettings* settings, size_t width); - // Function graph - BINARYNINJACOREAPI BNFunctionGraph* BNCreateFunctionGraph(BNFunction* func); - BINARYNINJACOREAPI BNFunctionGraph* BNNewFunctionGraphReference(BNFunctionGraph* graph); - BINARYNINJACOREAPI void BNFreeFunctionGraph(BNFunctionGraph* graph); - BINARYNINJACOREAPI BNFunction* BNGetFunctionForFunctionGraph(BNFunctionGraph* graph); + // Flow graphs + BINARYNINJACOREAPI BNFlowGraph* BNCreateFlowGraph(); + BINARYNINJACOREAPI BNFlowGraph* BNCreateFunctionGraph(BNFunction* func, BNFunctionGraphType type, + BNDisassemblySettings* settings); + BINARYNINJACOREAPI BNFlowGraph* BNCreateLowLevelILFunctionGraph(BNLowLevelILFunction* func, + BNDisassemblySettings* settings); + BINARYNINJACOREAPI BNFlowGraph* BNCreateMediumLevelILFunctionGraph(BNMediumLevelILFunction* func, + BNDisassemblySettings* settings); + BINARYNINJACOREAPI BNFlowGraph* BNCreateCustomFlowGraph(BNCustomFlowGraph* callbacks); + BINARYNINJACOREAPI BNFlowGraph* BNNewFlowGraphReference(BNFlowGraph* graph); + BINARYNINJACOREAPI void BNFreeFlowGraph(BNFlowGraph* graph); + BINARYNINJACOREAPI BNFunction* BNGetFunctionForFlowGraph(BNFlowGraph* graph); + BINARYNINJACOREAPI void BNSetFunctionForFlowGraph(BNFlowGraph* graph, BNFunction* func); - BINARYNINJACOREAPI int BNGetHorizontalFunctionGraphBlockMargin(BNFunctionGraph* graph); - BINARYNINJACOREAPI int BNGetVerticalFunctionGraphBlockMargin(BNFunctionGraph* graph); - BINARYNINJACOREAPI void BNSetFunctionGraphBlockMargins(BNFunctionGraph* graph, int horiz, int vert); + BINARYNINJACOREAPI int BNGetHorizontalFlowGraphNodeMargin(BNFlowGraph* graph); + BINARYNINJACOREAPI int BNGetVerticalFlowGraphNodeMargin(BNFlowGraph* graph); + BINARYNINJACOREAPI void BNSetFlowGraphNodeMargins(BNFlowGraph* graph, int horiz, int vert); - BINARYNINJACOREAPI BNDisassemblySettings* BNGetFunctionGraphSettings(BNFunctionGraph* graph); + BINARYNINJACOREAPI BNFlowGraphLayoutRequest* BNStartFlowGraphLayout(BNFlowGraph* graph, void* ctxt, void (*func)(void* ctxt)); + BINARYNINJACOREAPI bool BNIsFlowGraphLayoutComplete(BNFlowGraph* graph); + BINARYNINJACOREAPI BNFlowGraphLayoutRequest* BNNewFlowGraphLayoutRequestReference(BNFlowGraphLayoutRequest* layout); + BINARYNINJACOREAPI void BNFreeFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* layout); + BINARYNINJACOREAPI bool BNIsFlowGraphLayoutRequestComplete(BNFlowGraphLayoutRequest* layout); + BINARYNINJACOREAPI BNFlowGraph* BNGetGraphForFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* layout); + BINARYNINJACOREAPI void BNAbortFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* graph); + BINARYNINJACOREAPI bool BNIsILFlowGraph(BNFlowGraph* graph); + BINARYNINJACOREAPI bool BNIsLowLevelILFlowGraph(BNFlowGraph* graph); + BINARYNINJACOREAPI bool BNIsMediumLevelILFlowGraph(BNFlowGraph* graph); + BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFlowGraphLowLevelILFunction(BNFlowGraph* graph); + BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetFlowGraphMediumLevelILFunction(BNFlowGraph* graph); + BINARYNINJACOREAPI void BNSetFlowGraphLowLevelILFunction(BNFlowGraph* graph, BNLowLevelILFunction* func); + BINARYNINJACOREAPI void BNSetFlowGraphMediumLevelILFunction(BNFlowGraph* graph, BNMediumLevelILFunction* func); - BINARYNINJACOREAPI void BNStartFunctionGraphLayout(BNFunctionGraph* graph, BNFunctionGraphType type); - BINARYNINJACOREAPI bool BNIsFunctionGraphLayoutComplete(BNFunctionGraph* graph); - BINARYNINJACOREAPI void BNSetFunctionGraphCompleteCallback(BNFunctionGraph* graph, void* ctxt, void (*func)(void* ctxt)); - BINARYNINJACOREAPI void BNAbortFunctionGraph(BNFunctionGraph* graph); - BINARYNINJACOREAPI BNFunctionGraphType BNGetFunctionGraphType(BNFunctionGraph* graph); - BINARYNINJACOREAPI bool BNIsILFunctionGraph(BNFunctionGraph* graph); - BINARYNINJACOREAPI bool BNIsLowLevelILFunctionGraph(BNFunctionGraph* graph); - BINARYNINJACOREAPI bool BNIsMediumLevelILFunctionGraph(BNFunctionGraph* graph); - BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFunctionGraphLowLevelILFunction(BNFunctionGraph* graph); - BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetFunctionGraphMediumLevelILFunction(BNFunctionGraph* graph); + BINARYNINJACOREAPI BNFlowGraphNode** BNGetFlowGraphNodes(BNFlowGraph* graph, size_t* count); + BINARYNINJACOREAPI BNFlowGraphNode* BNGetFlowGraphNode(BNFlowGraph* graph, size_t i); + BINARYNINJACOREAPI BNFlowGraphNode** BNGetFlowGraphNodesInRegion( + BNFlowGraph* graph, int left, int top, int right, int bottom, size_t* count); + BINARYNINJACOREAPI void BNFreeFlowGraphNodeList(BNFlowGraphNode** nodes, size_t count); + BINARYNINJACOREAPI bool BNFlowGraphHasNodes(BNFlowGraph* graph); + BINARYNINJACOREAPI size_t BNAddFlowGraphNode(BNFlowGraph* graph, BNFlowGraphNode* node); - BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocks(BNFunctionGraph* graph, size_t* count); - BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocksInRegion( - BNFunctionGraph* graph, int left, int top, int right, int bottom, size_t* count); - BINARYNINJACOREAPI void BNFreeFunctionGraphBlockList(BNFunctionGraphBlock** blocks, size_t count); - BINARYNINJACOREAPI bool BNFunctionGraphHasBlocks(BNFunctionGraph* graph); + BINARYNINJACOREAPI int BNGetFlowGraphWidth(BNFlowGraph* graph); + BINARYNINJACOREAPI int BNGetFlowGraphHeight(BNFlowGraph* graph); - BINARYNINJACOREAPI int BNGetFunctionGraphWidth(BNFunctionGraph* graph); - BINARYNINJACOREAPI int BNGetFunctionGraphHeight(BNFunctionGraph* graph); + BINARYNINJACOREAPI BNFlowGraphNode* BNCreateFlowGraphNode(BNFlowGraph* graph); + BINARYNINJACOREAPI BNFlowGraphNode* BNNewFlowGraphNodeReference(BNFlowGraphNode* node); + BINARYNINJACOREAPI void BNFreeFlowGraphNode(BNFlowGraphNode* node); - BINARYNINJACOREAPI bool BNIsFunctionGraphOptionSet(BNFunctionGraph* graph, BNDisassemblyOption option); - BINARYNINJACOREAPI void BNSetFunctionGraphOption(BNFunctionGraph* graph, BNDisassemblyOption option, bool state); + BINARYNINJACOREAPI BNBasicBlock* BNGetFlowGraphBasicBlock(BNFlowGraphNode* node); + BINARYNINJACOREAPI void BNSetFlowGraphBasicBlock(BNFlowGraphNode* node, BNBasicBlock* block); + BINARYNINJACOREAPI int BNGetFlowGraphNodeX(BNFlowGraphNode* node); + BINARYNINJACOREAPI int BNGetFlowGraphNodeY(BNFlowGraphNode* node); + BINARYNINJACOREAPI int BNGetFlowGraphNodeWidth(BNFlowGraphNode* node); + BINARYNINJACOREAPI int BNGetFlowGraphNodeHeight(BNFlowGraphNode* node); - BINARYNINJACOREAPI BNFunctionGraphBlock* BNNewFunctionGraphBlockReference(BNFunctionGraphBlock* block); - BINARYNINJACOREAPI void BNFreeFunctionGraphBlock(BNFunctionGraphBlock* block); + BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetFlowGraphNodeLines(BNFlowGraphNode* node, size_t* count); + BINARYNINJACOREAPI void BNSetFlowGraphNodeLines(BNFlowGraphNode* node, BNDisassemblyTextLine* lines, size_t count); + BINARYNINJACOREAPI BNFlowGraphEdge* BNGetFlowGraphNodeOutgoingEdges(BNFlowGraphNode* node, size_t* count); + BINARYNINJACOREAPI void BNFreeFlowGraphNodeOutgoingEdgeList(BNFlowGraphEdge* edges, size_t count); + BINARYNINJACOREAPI void BNAddFlowGraphNodeOutgoingEdge(BNFlowGraphNode* node, BNBranchType type, BNFlowGraphNode* target); - BINARYNINJACOREAPI BNBasicBlock* BNGetFunctionGraphBasicBlock(BNFunctionGraphBlock* block); - BINARYNINJACOREAPI BNArchitecture* BNGetFunctionGraphBlockArchitecture(BNFunctionGraphBlock* block); - BINARYNINJACOREAPI uint64_t BNGetFunctionGraphBlockStart(BNFunctionGraphBlock* block); - BINARYNINJACOREAPI uint64_t BNGetFunctionGraphBlockEnd(BNFunctionGraphBlock* block); - BINARYNINJACOREAPI int BNGetFunctionGraphBlockX(BNFunctionGraphBlock* block); - BINARYNINJACOREAPI int BNGetFunctionGraphBlockY(BNFunctionGraphBlock* block); - BINARYNINJACOREAPI int BNGetFunctionGraphBlockWidth(BNFunctionGraphBlock* block); - BINARYNINJACOREAPI int BNGetFunctionGraphBlockHeight(BNFunctionGraphBlock* block); + BINARYNINJACOREAPI BNHighlightColor BNGetFlowGraphNodeHighlight(BNFlowGraphNode* node); + BINARYNINJACOREAPI void BNSetFlowGraphNodeHighlight(BNFlowGraphNode* node, BNHighlightColor color); - BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetFunctionGraphBlockLines(BNFunctionGraphBlock* block, size_t* count); - BINARYNINJACOREAPI BNFunctionGraphEdge* BNGetFunctionGraphBlockOutgoingEdges(BNFunctionGraphBlock* block, size_t* count); - BINARYNINJACOREAPI void BNFreeFunctionGraphBlockOutgoingEdgeList(BNFunctionGraphEdge* edges, size_t count); + BINARYNINJACOREAPI void BNFinishPrepareForLayout(BNFlowGraph* graph); + + BINARYNINJACOREAPI BNFlowGraph* BNUpdateFlowGraph(BNFlowGraph* graph); // Symbols BINARYNINJACOREAPI BNSymbol* BNCreateSymbol(BNSymbolType type, const char* shortName, const char* fullName, @@ -3073,7 +3124,7 @@ extern "C" BINARYNINJACOREAPI BNType* BNCreateArrayType(BNTypeWithConfidence* type, uint64_t elem); BINARYNINJACOREAPI BNType* BNCreateFunctionType(BNTypeWithConfidence* returnValue, BNCallingConventionWithConfidence* callingConvention, BNFunctionParameter* params, - size_t paramCount, BNBoolWithConfidence* varArg, BNSizeWithConfidence* stackAdjust); + size_t paramCount, BNBoolWithConfidence* varArg, BNOffsetWithConfidence* stackAdjust); BINARYNINJACOREAPI BNType* BNNewTypeReference(BNType* type); BINARYNINJACOREAPI BNType* BNDuplicateType(BNType* type); BINARYNINJACOREAPI char* BNGetTypeAndName(BNType* type, BNQualifiedName* name); @@ -3106,7 +3157,7 @@ extern "C" BINARYNINJACOREAPI void BNTypeSetMemberAccess(BNType* type, BNMemberAccessWithConfidence* access); BINARYNINJACOREAPI void BNTypeSetConst(BNType* type, BNBoolWithConfidence* cnst); BINARYNINJACOREAPI void BNTypeSetVolatile(BNType* type, BNBoolWithConfidence* vltl); - BINARYNINJACOREAPI BNSizeWithConfidence BNGetTypeStackAdjustment(BNType* type); + BINARYNINJACOREAPI BNOffsetWithConfidence BNGetTypeStackAdjustment(BNType* type); BINARYNINJACOREAPI char* BNGetTypeString(BNType* type, BNPlatform* platform); BINARYNINJACOREAPI char* BNGetTypeStringBeforeName(BNType* type, BNPlatform* platform); @@ -3449,6 +3500,8 @@ extern "C" const char* plaintext); BINARYNINJACOREAPI void BNShowHTMLReport(BNBinaryView* view, const char* title, const char* contents, const char* plaintext); + BINARYNINJACOREAPI void BNShowGraphReport(BNBinaryView* view, const char* title, BNFlowGraph* graph); + BINARYNINJACOREAPI void BNShowReportCollection(const char* title, BNReportCollection* reports); BINARYNINJACOREAPI bool BNGetTextLineInput(char** result, const char* prompt, const char* title); BINARYNINJACOREAPI bool BNGetIntegerInput(int64_t* result, const char* prompt, const char* title); BINARYNINJACOREAPI bool BNGetAddressInput(uint64_t* result, const char* prompt, const char* title, @@ -3464,6 +3517,25 @@ extern "C" BINARYNINJACOREAPI BNMessageBoxButtonResult BNShowMessageBox(const char* title, const char* text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); + BINARYNINJACOREAPI BNReportCollection* BNCreateReportCollection(void); + BINARYNINJACOREAPI BNReportCollection* BNNewReportCollectionReference(BNReportCollection* reports); + BINARYNINJACOREAPI void BNFreeReportCollection(BNReportCollection* reports); + BINARYNINJACOREAPI size_t BNGetReportCollectionCount(BNReportCollection* reports); + BINARYNINJACOREAPI BNReportType BNGetReportType(BNReportCollection* reports, size_t i); + BINARYNINJACOREAPI BNBinaryView* BNGetReportView(BNReportCollection* reports, size_t i); + BINARYNINJACOREAPI char* BNGetReportTitle(BNReportCollection* reports, size_t i); + BINARYNINJACOREAPI char* BNGetReportContents(BNReportCollection* reports, size_t i); + BINARYNINJACOREAPI char* BNGetReportPlainText(BNReportCollection* reports, size_t i); + BINARYNINJACOREAPI BNFlowGraph* BNGetReportFlowGraph(BNReportCollection* reports, size_t i); + BINARYNINJACOREAPI void BNAddPlainTextReportToCollection(BNReportCollection* reports, BNBinaryView* view, + const char* title, const char* contents); + BINARYNINJACOREAPI void BNAddMarkdownReportToCollection(BNReportCollection* reports, BNBinaryView* view, + const char* title, const char* contents, const char* plaintext); + BINARYNINJACOREAPI void BNAddHTMLReportToCollection(BNReportCollection* reports, BNBinaryView* view, + const char* title, const char* contents, const char* plaintext); + BINARYNINJACOREAPI void BNAddGraphReportToCollection(BNReportCollection* reports, BNBinaryView* view, + const char* title, BNFlowGraph* graph); + BINARYNINJACOREAPI bool BNDemangleGNU3(BNArchitecture* arch, const char* mangledName, BNType** outType, diff --git a/binaryview.cpp b/binaryview.cpp index a678d23b..e9e8b377 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1739,6 +1739,7 @@ vector<LinearDisassemblyLine> BinaryView::GetPreviousLinearDisassemblyLines(Line line.lineOffset = lines[i].lineOffset; line.contents.addr = lines[i].contents.addr; line.contents.instrIndex = lines[i].contents.instrIndex; + line.contents.highlight = lines[i].contents.highlight; line.contents.tokens.reserve(lines[i].contents.count); for (size_t j = 0; j < lines[i].contents.count; j++) { @@ -1788,6 +1789,7 @@ vector<LinearDisassemblyLine> BinaryView::GetNextLinearDisassemblyLines(LinearDi line.lineOffset = lines[i].lineOffset; line.contents.addr = lines[i].contents.addr; line.contents.instrIndex = lines[i].contents.instrIndex; + line.contents.highlight = lines[i].contents.highlight; line.contents.tokens.reserve(lines[i].contents.count); for (size_t j = 0; j < lines[i].contents.count; j++) { @@ -1980,6 +1982,12 @@ void BinaryView::ShowHTMLReport(const string& title, const string& contents, con } +void BinaryView::ShowGraphReport(const string& title, FlowGraph* graph) +{ + BNShowGraphReport(m_object, title.c_str(), graph->GetObject()); +} + + bool BinaryView::GetAddressInput(uint64_t& result, const string& prompt, const string& title) { uint64_t currentAddress = 0; diff --git a/docs/getting-started.md b/docs/getting-started.md index 5148b9d5..59695147 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -15,11 +15,11 @@ Binaries are installed in the following locations by default: - Linux: Wherever you extract it! (No standard location) !!! Warning "Warning" - Do not put any user content in the install-path of Binary Ninja. The auto-update process of Binary Ninja may replace any files included in these folders. + Do not put any user content in the install-path of Binary Ninja. The auto-update process of Binary Ninja may replace any files included in these folders. ### User Folder -The base locations of user folders are: +The base locations of user folders are: - OS X: `~/Library/Application Support/Binary Ninja` - Linux: `~/.binaryninja` @@ -277,7 +277,15 @@ Settings are stored in the _user_ directory in the file `settings.json`. Each to | pdb | auto-download-pdb | boolean | True | Automatically download pdb files from specified symbol servers | | pdb | symbol-server-list | list(string) | ["http://msdl.microsoft.com/download/symbols"] | List of servers to query for pdb symbols. | | python | interpreter | string | "python27.{dylib,dll,so.1}" | Python interpreter to load if one is not already present when plugins are loaded | - +| arch | x86.disassemblyFlavor | string | "BN_INTEL" | "BN_INTEL", "INTEL", or "AT&T" | +| arch | x86.disassemblySeperator | string | ", " | What to put between operands in disassembly tokens | +| arch | x86.disassemblyLowercase | bool | True | Lowercase opcodes, operands, and registers (False for uppercase) | + "arch" : + { + // "x86.disassemblyFlavor" : "AT&T", + // "x86.disassemblyFlavor" : "BN_INTEL", + "x86.disassemblyLowercase" : true, + "x86.disassemblySeperator" : ", " Below is an example `settings.json` setting various options: ``` { diff --git a/flowgraph.cpp b/flowgraph.cpp new file mode 100644 index 00000000..dc7e628e --- /dev/null +++ b/flowgraph.cpp @@ -0,0 +1,358 @@ +// Copyright (c) 2015-2017 Vector 35 LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace std; + + +FlowGraphLayoutRequest::FlowGraphLayoutRequest(FlowGraph* graph, const std::function<void()>& completeFunc): + m_completeFunc(completeFunc) +{ + m_object = BNStartFlowGraphLayout(graph->GetObject(), this, CompleteCallback); +} + + +FlowGraphLayoutRequest::~FlowGraphLayoutRequest() +{ + // This object is going away, so ensure that any pending completion routines are + // no longer called + Abort(); + + BNFreeFlowGraphLayoutRequest(m_object); +} + + +void FlowGraphLayoutRequest::CompleteCallback(void* ctxt) +{ + FlowGraphLayoutRequest* layout = (FlowGraphLayoutRequest*)ctxt; + layout->m_completeFunc(); +} + + +Ref<FlowGraph> FlowGraphLayoutRequest::GetGraph() const +{ + return new CoreFlowGraph(BNGetGraphForFlowGraphLayoutRequest(m_object)); +} + + +bool FlowGraphLayoutRequest::IsComplete() const +{ + return BNIsFlowGraphLayoutRequestComplete(m_object); +} + + +void FlowGraphLayoutRequest::Abort() +{ + // Must clear the callback with the core before clearing our own function object, as until it + // is cleared in the core it can be called at any time from a different thread. + BNAbortFlowGraphLayoutRequest(m_object); + m_completeFunc = []() {}; +} + + +FlowGraph::FlowGraph() +{ + BNCustomFlowGraph callbacks; + callbacks.context = this; + callbacks.prepareForLayout = PrepareForLayoutCallback; + callbacks.populateNodes = PopulateNodesCallback; + callbacks.completeLayout = CompleteLayoutCallback; + m_object = BNCreateCustomFlowGraph(&callbacks); +} + + +FlowGraph::FlowGraph(BNFlowGraph* graph) +{ + m_object = graph; +} + + +void FlowGraph::PrepareForLayoutCallback(void* ctxt) +{ + FlowGraph* graph = (FlowGraph*)ctxt; + graph->PrepareForLayout(); +} + + +void FlowGraph::PopulateNodesCallback(void* ctxt) +{ + FlowGraph* graph = (FlowGraph*)ctxt; + graph->PopulateNodes(); +} + + +void FlowGraph::CompleteLayoutCallback(void* ctxt) +{ + FlowGraph* graph = (FlowGraph*)ctxt; + graph->CompleteLayout(); +} + + +BNFlowGraph* FlowGraph::UpdateCallback(void* ctxt) +{ + FlowGraph* graph = (FlowGraph*)ctxt; + Ref<FlowGraph> result = graph->Update(); + if (!result) + return nullptr; + return BNNewFlowGraphReference(result->GetObject()); +} + + +void FlowGraph::FinishPrepareForLayout() +{ + BNFinishPrepareForLayout(m_object); +} + + +void FlowGraph::PrepareForLayout() +{ + FinishPrepareForLayout(); +} + + +void FlowGraph::PopulateNodes() +{ +} + + +void FlowGraph::CompleteLayout() +{ +} + + +Ref<Function> FlowGraph::GetFunction() const +{ + BNFunction* func = BNGetFunctionForFlowGraph(m_object); + if (!func) + return nullptr; + return new Function(BNNewFunctionReference(func)); +} + + +void FlowGraph::SetFunction(Function* func) +{ + BNSetFunctionForFlowGraph(m_object, func ? func->GetObject() : nullptr); +} + + +int FlowGraph::GetHorizontalNodeMargin() const +{ + return BNGetHorizontalFlowGraphNodeMargin(m_object); +} + + +int FlowGraph::GetVerticalNodeMargin() const +{ + return BNGetVerticalFlowGraphNodeMargin(m_object); +} + + +void FlowGraph::SetNodeMargins(int horiz, int vert) +{ + BNSetFlowGraphNodeMargins(m_object, horiz, vert); +} + + +Ref<FlowGraphLayoutRequest> FlowGraph::StartLayout(const std::function<void()>& func) +{ + return new FlowGraphLayoutRequest(this, func); +} + + +bool FlowGraph::IsLayoutComplete() +{ + return BNIsFlowGraphLayoutComplete(m_object); +} + + +vector<Ref<FlowGraphNode>> FlowGraph::GetNodes() +{ + size_t count; + BNFlowGraphNode** nodes = BNGetFlowGraphNodes(m_object, &count); + + vector<Ref<FlowGraphNode>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + auto node = m_cachedNodes.find(nodes[i]); + if (node == m_cachedNodes.end()) + { + FlowGraphNode* newNode = new FlowGraphNode(BNNewFlowGraphNodeReference(nodes[i])); + m_cachedNodes[nodes[i]] = newNode; + result.push_back(newNode); + } + else + { + result.push_back(node->second); + } + } + + BNFreeFlowGraphNodeList(nodes, count); + return result; +} + + +Ref<FlowGraphNode> FlowGraph::GetNode(size_t i) +{ + BNFlowGraphNode* node = BNGetFlowGraphNode(m_object, i); + if (!node) + return nullptr; + + auto nodeIter = m_cachedNodes.find(node); + if (nodeIter == m_cachedNodes.end()) + { + FlowGraphNode* newNode = new FlowGraphNode(node); + m_cachedNodes[node] = newNode; + return newNode; + } + else + { + BNFreeFlowGraphNode(node); + return nodeIter->second; + } +} + + +bool FlowGraph::HasNodes() const +{ + return BNFlowGraphHasNodes(m_object); +} + + +size_t FlowGraph::AddNode(FlowGraphNode* node) +{ + m_cachedNodes[node->GetObject()] = node; + return BNAddFlowGraphNode(m_object, node->GetObject()); +} + + +int FlowGraph::GetWidth() const +{ + return BNGetFlowGraphWidth(m_object); +} + + +int FlowGraph::GetHeight() const +{ + return BNGetFlowGraphHeight(m_object); +} + + +vector<Ref<FlowGraphNode>> FlowGraph::GetNodesInRegion(int left, int top, int right, int bottom) +{ + size_t count; + BNFlowGraphNode** nodes = BNGetFlowGraphNodesInRegion(m_object, left, top, right, bottom, &count); + + vector<Ref<FlowGraphNode>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + auto node = m_cachedNodes.find(nodes[i]); + if (node == m_cachedNodes.end()) + { + FlowGraphNode* newNode = new FlowGraphNode(BNNewFlowGraphNodeReference(nodes[i])); + m_cachedNodes[nodes[i]] = newNode; + result.push_back(newNode); + } + else + { + result.push_back(node->second); + } + } + + BNFreeFlowGraphNodeList(nodes, count); + return result; +} + + +bool FlowGraph::IsILGraph() const +{ + return BNIsILFlowGraph(m_object); +} + + +bool FlowGraph::IsLowLevelILGraph() const +{ + return BNIsLowLevelILFlowGraph(m_object); +} + + +bool FlowGraph::IsMediumLevelILGraph() const +{ + return BNIsMediumLevelILFlowGraph(m_object); +} + + +Ref<LowLevelILFunction> FlowGraph::GetLowLevelILFunction() const +{ + BNLowLevelILFunction* func = BNGetFlowGraphLowLevelILFunction(m_object); + if (!func) + return nullptr; + return new LowLevelILFunction(func); +} + + +Ref<MediumLevelILFunction> FlowGraph::GetMediumLevelILFunction() const +{ + BNMediumLevelILFunction* func = BNGetFlowGraphMediumLevelILFunction(m_object); + if (!func) + return nullptr; + return new MediumLevelILFunction(func); +} + + +void FlowGraph::SetLowLevelILFunction(LowLevelILFunction* func) +{ + BNSetFlowGraphLowLevelILFunction(m_object, func ? func->GetObject() : nullptr); +} + + +void FlowGraph::SetMediumLevelILFunction(MediumLevelILFunction* func) +{ + BNSetFlowGraphMediumLevelILFunction(m_object, func ? func->GetObject() : nullptr); +} + + +void FlowGraph::Show(const string& title) +{ + ShowGraphReport(title, this); +} + + +Ref<FlowGraph> FlowGraph::Update() +{ + return nullptr; +} + + +CoreFlowGraph::CoreFlowGraph(BNFlowGraph* graph): FlowGraph(graph) +{ +} + + +Ref<FlowGraph> CoreFlowGraph::Update() +{ + BNFlowGraph* graph = BNUpdateFlowGraph(GetObject()); + if (!graph) + return nullptr; + return new CoreFlowGraph(graph); +} diff --git a/flowgraphnode.cpp b/flowgraphnode.cpp new file mode 100644 index 00000000..60912df1 --- /dev/null +++ b/flowgraphnode.cpp @@ -0,0 +1,206 @@ +// Copyright (c) 2015-2017 Vector 35 LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace std; + + +FlowGraphNode::FlowGraphNode(FlowGraph* graph) +{ + m_object = BNCreateFlowGraphNode(graph->GetObject()); + m_cachedLinesValid = false; + m_cachedEdgesValid = false; +} + + +FlowGraphNode::FlowGraphNode(BNFlowGraphNode* node) +{ + m_object = node; + m_cachedLinesValid = false; + m_cachedEdgesValid = false; +} + + +Ref<BasicBlock> FlowGraphNode::GetBasicBlock() const +{ + BNBasicBlock* block = BNGetFlowGraphBasicBlock(m_object); + if (!block) + return nullptr; + return new BasicBlock(block); +} + + +void FlowGraphNode::SetBasicBlock(BasicBlock* block) +{ + BNSetFlowGraphBasicBlock(m_object, block ? block->GetObject() : nullptr); +} + + +int FlowGraphNode::GetX() const +{ + return BNGetFlowGraphNodeX(m_object); +} + + +int FlowGraphNode::GetY() const +{ + return BNGetFlowGraphNodeY(m_object); +} + + +int FlowGraphNode::GetWidth() const +{ + return BNGetFlowGraphNodeWidth(m_object); +} + + +int FlowGraphNode::GetHeight() const +{ + return BNGetFlowGraphNodeHeight(m_object); +} + + +const vector<DisassemblyTextLine>& FlowGraphNode::GetLines() +{ + if (m_cachedLinesValid) + return m_cachedLines; + + size_t count; + BNDisassemblyTextLine* lines = BNGetFlowGraphNodeLines(m_object, &count); + + vector<DisassemblyTextLine> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + DisassemblyTextLine line; + line.addr = lines[i].addr; + line.instrIndex = lines[i].instrIndex; + line.highlight = lines[i].highlight; + line.tokens.reserve(lines[i].count); + for (size_t j = 0; j < lines[i].count; j++) + { + InstructionTextToken token; + token.type = lines[i].tokens[j].type; + token.text = lines[i].tokens[j].text; + token.value = lines[i].tokens[j].value; + token.size = lines[i].tokens[j].size; + token.operand = lines[i].tokens[j].operand; + token.context = lines[i].tokens[j].context; + token.confidence = lines[i].tokens[j].confidence; + token.address = lines[i].tokens[j].address; + line.tokens.push_back(token); + } + result.push_back(line); + } + + BNFreeDisassemblyTextLines(lines, count); + m_cachedLines = result; + m_cachedLinesValid = true; + return m_cachedLines; +} + + +void FlowGraphNode::SetLines(const vector<DisassemblyTextLine>& lines) +{ + BNDisassemblyTextLine* buf = new BNDisassemblyTextLine[lines.size()]; + for (size_t i = 0; i < lines.size(); i++) + { + const DisassemblyTextLine& line = lines[i]; + buf[i].addr = line.addr; + buf[i].instrIndex = line.instrIndex; + buf[i].highlight = line.highlight; + buf[i].tokens = new BNInstructionTextToken[line.tokens.size()]; + buf[i].count = line.tokens.size(); + for (size_t j = 0; j < line.tokens.size(); j++) + { + const InstructionTextToken& token = line.tokens[j]; + buf[i].tokens[j].type = token.type; + buf[i].tokens[j].text = BNAllocString(token.text.c_str()); + buf[i].tokens[j].value = token.value; + buf[i].tokens[j].size = token.size; + buf[i].tokens[j].operand = token.operand; + buf[i].tokens[j].context = token.context; + buf[i].tokens[j].confidence = token.confidence; + buf[i].tokens[j].address = token.address; + } + } + + BNSetFlowGraphNodeLines(m_object, buf, lines.size()); + + for (size_t i = 0; i < lines.size(); i++) + { + for (size_t j = 0; j < buf[i].count; j++) + BNFreeString(buf[i].tokens[j].text); + delete[] buf[i].tokens; + } + delete[] buf; + + m_cachedLines = lines; + m_cachedLinesValid = true; +} + + +const vector<FlowGraphEdge>& FlowGraphNode::GetOutgoingEdges() +{ + if (m_cachedEdgesValid) + return m_cachedEdges; + + size_t count; + BNFlowGraphEdge* edges = BNGetFlowGraphNodeOutgoingEdges(m_object, &count); + + vector<FlowGraphEdge> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + FlowGraphEdge edge; + edge.type = edges[i].type; + edge.target = edges[i].target ? new FlowGraphNode(BNNewFlowGraphNodeReference(edges[i].target)) : nullptr; + edge.points.insert(edge.points.begin(), &edges[i].points[0], &edges[i].points[edges[i].pointCount]); + edge.backEdge = edges[i].backEdge; + result.push_back(edge); + } + + BNFreeFlowGraphNodeOutgoingEdgeList(edges, count); + m_cachedEdges = result; + m_cachedEdgesValid = true; + return m_cachedEdges; +} + + +void FlowGraphNode::AddOutgoingEdge(BNBranchType type, FlowGraphNode* target) +{ + BNAddFlowGraphNodeOutgoingEdge(m_object, type, target->GetObject()); + m_cachedEdges.clear(); + m_cachedEdgesValid = false; +} + + +BNHighlightColor FlowGraphNode::GetHighlight() const +{ + return BNGetFlowGraphNodeHighlight(m_object); +} + + +void FlowGraphNode::SetHighlight(const BNHighlightColor& color) +{ + BNSetFlowGraphNodeHighlight(m_object, color); +} diff --git a/function.cpp b/function.cpp index e441d1b5..e17166ff 100644 --- a/function.cpp +++ b/function.cpp @@ -120,6 +120,12 @@ Function::~Function() } +Ref<BinaryView> Function::GetView() const +{ + return new BinaryView(BNGetFunctionData(m_object)); +} + + Ref<Platform> Function::GetPlatform() const { return new Platform(BNGetFunctionPlatform(m_object)); @@ -534,10 +540,10 @@ Confidence<bool> Function::HasVariableArguments() const } -Confidence<size_t> Function::GetStackAdjustment() const +Confidence<int64_t> Function::GetStackAdjustment() const { - BNSizeWithConfidence sc = BNGetFunctionStackAdjustment(m_object); - return Confidence<size_t>(sc.value, sc.confidence); + BNOffsetWithConfidence oc = BNGetFunctionStackAdjustment(m_object); + return Confidence<int64_t>(oc.value, oc.confidence); } @@ -639,12 +645,12 @@ void Function::SetAutoCanReturn(const Confidence<bool>& returns) } -void Function::SetAutoStackAdjustment(const Confidence<size_t>& stackAdjust) +void Function::SetAutoStackAdjustment(const Confidence<int64_t>& stackAdjust) { - BNSizeWithConfidence sc; - sc.value = stackAdjust.GetValue(); - sc.confidence = stackAdjust.GetConfidence(); - BNSetAutoFunctionStackAdjustment(m_object, &sc); + BNOffsetWithConfidence oc; + oc.value = stackAdjust.GetValue(); + oc.confidence = stackAdjust.GetConfidence(); + BNSetAutoFunctionStackAdjustment(m_object, &oc); } @@ -753,12 +759,12 @@ void Function::SetCanReturn(const Confidence<bool>& returns) } -void Function::SetStackAdjustment(const Confidence<size_t>& stackAdjust) +void Function::SetStackAdjustment(const Confidence<int64_t>& stackAdjust) { - BNSizeWithConfidence sc; - sc.value = stackAdjust.GetValue(); - sc.confidence = stackAdjust.GetConfidence(); - BNSetUserFunctionStackAdjustment(m_object, &sc); + BNOffsetWithConfidence oc; + oc.value = stackAdjust.GetValue(); + oc.confidence = stackAdjust.GetConfidence(); + BNSetUserFunctionStackAdjustment(m_object, &oc); } @@ -804,10 +810,10 @@ void Function::ApplyAutoDiscoveredType(Type* type) } -Ref<FunctionGraph> Function::CreateFunctionGraph() +Ref<FlowGraph> Function::CreateFunctionGraph(BNFunctionGraphType type, DisassemblySettings* settings) { - BNFunctionGraph* graph = BNCreateFunctionGraph(m_object); - return new FunctionGraph(graph); + BNFlowGraph* graph = BNCreateFunctionGraph(m_object, type, settings ? settings->GetObject() : nullptr); + return new CoreFlowGraph(graph); } @@ -1022,7 +1028,7 @@ vector<IndirectBranchInfo> Function::GetIndirectBranchesAt(Architecture* arch, u } -void Function::SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<size_t>& adjust) +void Function::SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<int64_t>& adjust) { BNSetAutoCallStackAdjustment(m_object, arch->GetObject(), addr, adjust.GetValue(), adjust.GetConfidence()); } @@ -1053,7 +1059,7 @@ void Function::SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t a } -void Function::SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<size_t>& adjust) +void Function::SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<int64_t>& adjust) { BNSetUserCallStackAdjustment(m_object, arch->GetObject(), addr, adjust.GetValue(), adjust.GetConfidence()); } @@ -1084,10 +1090,10 @@ void Function::SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t a } -Confidence<size_t> Function::GetCallStackAdjustment(Architecture* arch, uint64_t addr) +Confidence<int64_t> Function::GetCallStackAdjustment(Architecture* arch, uint64_t addr) { - BNSizeWithConfidence result = BNGetCallStackAdjustment(m_object, arch->GetObject(), addr); - return Confidence<size_t>(result.value, result.confidence); + BNOffsetWithConfidence result = BNGetCallStackAdjustment(m_object, arch->GetObject(), addr); + return Confidence<int64_t>(result.value, result.confidence); } @@ -1112,6 +1118,12 @@ Confidence<int32_t> Function::GetCallRegisterStackAdjustment(Architecture* arch, } +bool Function::IsCallInstruction(Architecture* arch, uint64_t addr) +{ + return BNIsCallInstruction(m_object, arch->GetObject(), addr); +} + + vector<vector<InstructionTextToken>> Function::GetBlockAnnotations(Architecture* arch, uint64_t addr) { size_t count; @@ -1340,6 +1352,7 @@ vector<DisassemblyTextLine> Function::GetTypeTokens(DisassemblySettings* setting DisassemblyTextLine line; line.addr = lines[i].addr; line.instrIndex = lines[i].instrIndex; + line.highlight = lines[i].highlight; line.tokens.reserve(lines[i].count); for (size_t j = 0; j < lines[i].count; j++) { @@ -1392,6 +1405,21 @@ void Function::SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip) } +Ref<FlowGraph> Function::GetUnresolvedStackAdjustmentGraph() +{ + BNFlowGraph* graph = BNGetUnresolvedStackAdjustmentGraph(m_object); + if (!graph) + return nullptr; + return new CoreFlowGraph(graph); +} + + +void Function::RequestDebugReport(const string& name) +{ + BNRequestFunctionDebugReport(m_object, name.c_str()); +} + + AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(Function* func): m_func(func) { if (m_func) diff --git a/functiongraph.cpp b/functiongraph.cpp deleted file mode 100644 index 9948d70e..00000000 --- a/functiongraph.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2015-2017 Vector 35 LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "binaryninjaapi.h" - -using namespace BinaryNinja; -using namespace std; - - -FunctionGraph::FunctionGraph(BNFunctionGraph* graph): m_graph(graph) -{ -} - - -FunctionGraph::~FunctionGraph() -{ - // This object is going away, so ensure that any pending completion routines are - // no longer called - Abort(); - - BNFreeFunctionGraph(m_graph); -} - - -void FunctionGraph::CompleteCallback(void* ctxt) -{ - FunctionGraph* graph = (FunctionGraph*)ctxt; - graph->m_completeFunc(); -} - - -Ref<Function> FunctionGraph::GetFunction() const -{ - return new Function(BNNewFunctionReference(BNGetFunctionForFunctionGraph(m_graph))); -} - - -int FunctionGraph::GetHorizontalBlockMargin() const -{ - return BNGetHorizontalFunctionGraphBlockMargin(m_graph); -} - - -int FunctionGraph::GetVerticalBlockMargin() const -{ - return BNGetVerticalFunctionGraphBlockMargin(m_graph); -} - - -void FunctionGraph::SetBlockMargins(int horiz, int vert) -{ - BNSetFunctionGraphBlockMargins(m_graph, horiz, vert); -} - - -Ref<DisassemblySettings> FunctionGraph::GetSettings() -{ - return new DisassemblySettings(BNGetFunctionGraphSettings(m_graph)); -} - - -void FunctionGraph::StartLayout(BNFunctionGraphType type) -{ - BNStartFunctionGraphLayout(m_graph, type); -} - - -bool FunctionGraph::IsLayoutComplete() -{ - return BNIsFunctionGraphLayoutComplete(m_graph); -} - - -void FunctionGraph::OnComplete(const std::function<void()>& func) -{ - m_completeFunc = func; - BNSetFunctionGraphCompleteCallback(m_graph, this, CompleteCallback); -} - - -void FunctionGraph::Abort() -{ - // Must clear the callback with the core before clearing our own function object, as until it - // is cleared in the core it can be called at any time from a different thread. - BNAbortFunctionGraph(m_graph); - m_completeFunc = []() {}; -} - - -vector<Ref<FunctionGraphBlock>> FunctionGraph::GetBlocks() -{ - size_t count; - BNFunctionGraphBlock** blocks = BNGetFunctionGraphBlocks(m_graph, &count); - - vector<Ref<FunctionGraphBlock>> result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - auto block = m_cachedBlocks.find(blocks[i]); - if (block == m_cachedBlocks.end()) - { - FunctionGraphBlock* newBlock = new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i])); - m_cachedBlocks[blocks[i]] = newBlock; - result.push_back(newBlock); - } - else - { - result.push_back(block->second); - } - } - - BNFreeFunctionGraphBlockList(blocks, count); - return result; -} - - -bool FunctionGraph::HasBlocks() const -{ - return BNFunctionGraphHasBlocks(m_graph); -} - - -int FunctionGraph::GetWidth() const -{ - return BNGetFunctionGraphWidth(m_graph); -} - - -int FunctionGraph::GetHeight() const -{ - return BNGetFunctionGraphHeight(m_graph); -} - - -vector<Ref<FunctionGraphBlock>> FunctionGraph::GetBlocksInRegion(int left, int top, int right, int bottom) -{ - size_t count; - BNFunctionGraphBlock** blocks = BNGetFunctionGraphBlocksInRegion(m_graph, left, top, right, bottom, &count); - - vector<Ref<FunctionGraphBlock>> result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - auto block = m_cachedBlocks.find(blocks[i]); - if (block == m_cachedBlocks.end()) - { - FunctionGraphBlock* newBlock = new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i])); - m_cachedBlocks[blocks[i]] = newBlock; - result.push_back(newBlock); - } - else - { - result.push_back(block->second); - } - } - - BNFreeFunctionGraphBlockList(blocks, count); - return result; -} - - -bool FunctionGraph::IsOptionSet(BNDisassemblyOption option) const -{ - return BNIsFunctionGraphOptionSet(m_graph, option); -} - - -void FunctionGraph::SetOption(BNDisassemblyOption option, bool state) -{ - BNSetFunctionGraphOption(m_graph, option, state); -} - - -bool FunctionGraph::IsILGraph() const -{ - return BNIsILFunctionGraph(m_graph); -} - - -bool FunctionGraph::IsLowLevelILGraph() const -{ - return BNIsLowLevelILFunctionGraph(m_graph); -} - - -bool FunctionGraph::IsMediumLevelILGraph() const -{ - return BNIsMediumLevelILFunctionGraph(m_graph); -} - - -Ref<LowLevelILFunction> FunctionGraph::GetLowLevelILFunction() const -{ - BNLowLevelILFunction* func = BNGetFunctionGraphLowLevelILFunction(m_graph); - if (!func) - return nullptr; - return new LowLevelILFunction(func); -} - - -Ref<MediumLevelILFunction> FunctionGraph::GetMediumLevelILFunction() const -{ - BNMediumLevelILFunction* func = BNGetFunctionGraphMediumLevelILFunction(m_graph); - if (!func) - return nullptr; - return new MediumLevelILFunction(func); -} diff --git a/functiongraphblock.cpp b/functiongraphblock.cpp deleted file mode 100644 index 469fb175..00000000 --- a/functiongraphblock.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2015-2017 Vector 35 LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "binaryninjaapi.h" - -using namespace BinaryNinja; -using namespace std; - - -FunctionGraphBlock::FunctionGraphBlock(BNFunctionGraphBlock* block) -{ - m_object = block; - m_cachedLinesValid = false; - m_cachedEdgesValid = false; -} - - -Ref<BasicBlock> FunctionGraphBlock::GetBasicBlock() const -{ - return new BasicBlock(BNGetFunctionGraphBasicBlock(m_object)); -} - - -Ref<Architecture> FunctionGraphBlock::GetArchitecture() const -{ - return new CoreArchitecture(BNGetFunctionGraphBlockArchitecture(m_object)); -} - - -uint64_t FunctionGraphBlock::GetStart() const -{ - return BNGetFunctionGraphBlockStart(m_object); -} - - -uint64_t FunctionGraphBlock::GetEnd() const -{ - return BNGetFunctionGraphBlockEnd(m_object); -} - - -int FunctionGraphBlock::GetX() const -{ - return BNGetFunctionGraphBlockX(m_object); -} - - -int FunctionGraphBlock::GetY() const -{ - return BNGetFunctionGraphBlockY(m_object); -} - - -int FunctionGraphBlock::GetWidth() const -{ - return BNGetFunctionGraphBlockWidth(m_object); -} - - -int FunctionGraphBlock::GetHeight() const -{ - return BNGetFunctionGraphBlockHeight(m_object); -} - - -const vector<DisassemblyTextLine>& FunctionGraphBlock::GetLines() -{ - if (m_cachedLinesValid) - return m_cachedLines; - - size_t count; - BNDisassemblyTextLine* lines = BNGetFunctionGraphBlockLines(m_object, &count); - - vector<DisassemblyTextLine> result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - DisassemblyTextLine line; - line.addr = lines[i].addr; - line.instrIndex = lines[i].instrIndex; - line.tokens.reserve(lines[i].count); - for (size_t j = 0; j < lines[i].count; j++) - { - InstructionTextToken token; - token.type = lines[i].tokens[j].type; - token.text = lines[i].tokens[j].text; - token.value = lines[i].tokens[j].value; - token.size = lines[i].tokens[j].size; - token.operand = lines[i].tokens[j].operand; - token.context = lines[i].tokens[j].context; - token.confidence = lines[i].tokens[j].confidence; - token.address = lines[i].tokens[j].address; - line.tokens.push_back(token); - } - result.push_back(line); - } - - BNFreeDisassemblyTextLines(lines, count); - m_cachedLines = result; - m_cachedLinesValid = true; - return m_cachedLines; -} - - -const vector<FunctionGraphEdge>& FunctionGraphBlock::GetOutgoingEdges() -{ - if (m_cachedEdgesValid) - return m_cachedEdges; - - size_t count; - BNFunctionGraphEdge* edges = BNGetFunctionGraphBlockOutgoingEdges(m_object, &count); - - vector<FunctionGraphEdge> result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - FunctionGraphEdge edge; - edge.type = edges[i].type; - edge.target = edges[i].target ? new BasicBlock(BNNewBasicBlockReference(edges[i].target)) : nullptr; - edge.points.insert(edge.points.begin(), &edges[i].points[0], &edges[i].points[edges[i].pointCount]); - edge.backEdge = edges[i].backEdge; - result.push_back(edge); - } - - BNFreeFunctionGraphBlockOutgoingEdgeList(edges, count); - m_cachedEdges = result; - m_cachedEdgesValid = true; - return m_cachedEdges; -} diff --git a/interaction.cpp b/interaction.cpp index 2f84c4ec..5650f629 100644 --- a/interaction.cpp +++ b/interaction.cpp @@ -117,6 +117,16 @@ void InteractionHandler::ShowHTMLReport(Ref<BinaryView> view, const string& titl } +void InteractionHandler::ShowGraphReport(Ref<BinaryView>, const std::string&, Ref<FlowGraph>) +{ +} + + +void InteractionHandler::ShowReportCollection(const string&, Ref<ReportCollection>) +{ +} + + bool InteractionHandler::GetIntegerInput(int64_t& result, const string& prompt, const string& title) { while (true) @@ -194,6 +204,21 @@ static void ShowHTMLReportCallback(void* ctxt, BNBinaryView* view, const char* t } +static void ShowGraphReportCallback(void* ctxt, BNBinaryView* view, const char* title, BNFlowGraph* graph) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + handler->ShowGraphReport(view ? new BinaryView(BNNewViewReference(view)) : nullptr, title, + new CoreFlowGraph(BNNewFlowGraphReference(graph))); +} + + +static void ShowReportCollectionCallback(void* ctxt, const char* title, BNReportCollection* reports) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + handler->ShowReportCollection(title, new ReportCollection(BNNewReportCollectionReference(reports))); +} + + static bool GetTextLineInputCallback(void* ctxt, char** result, const char* prompt, const char* title) { InteractionHandler* handler = (InteractionHandler*)ctxt; @@ -360,6 +385,8 @@ void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) cb.showPlainTextReport = ShowPlainTextReportCallback; cb.showMarkdownReport = ShowMarkdownReportCallback; cb.showHTMLReport = ShowHTMLReportCallback; + cb.showGraphReport = ShowGraphReportCallback; + cb.showReportCollection = ShowReportCollectionCallback; cb.getTextLineInput = GetTextLineInputCallback; cb.getIntegerInput = GetIntegerInputCallback; cb.getAddressInput = GetAddressInputCallback; @@ -400,6 +427,22 @@ void BinaryNinja::ShowHTMLReport(const string& title, const string& contents, co } +void BinaryNinja::ShowGraphReport(const string& title, FlowGraph* graph) +{ + Ref<Function> func = graph->GetFunction(); + if (func) + BNShowGraphReport(func->GetView()->GetObject(), title.c_str(), graph->GetObject()); + else + BNShowGraphReport(nullptr, title.c_str(), graph->GetObject()); +} + + +void BinaryNinja::ShowReportCollection(const string& title, ReportCollection* reports) +{ + BNShowReportCollection(title.c_str(), reports->GetObject()); +} + + bool BinaryNinja::GetTextLineInput(string& result, const string& prompt, const string& title) { char* value = nullptr; @@ -553,3 +596,100 @@ BNMessageBoxButtonResult BinaryNinja::ShowMessageBox(const string& title, const { return BNShowMessageBox(title.c_str(), text.c_str(), buttons, icon); } + + +ReportCollection::ReportCollection() +{ + m_object = BNCreateReportCollection(); +} + + +ReportCollection::ReportCollection(BNReportCollection* reports) +{ + m_object = reports; +} + + +size_t ReportCollection::GetCount() const +{ + return BNGetReportCollectionCount(m_object); +} + + +BNReportType ReportCollection::GetType(size_t i) const +{ + return BNGetReportType(m_object, i); +} + + +Ref<BinaryView> ReportCollection::GetView(size_t i) const +{ + BNBinaryView* view = BNGetReportView(m_object, i); + if (!view) + return nullptr; + return new BinaryView(view); +} + + +string ReportCollection::GetTitle(size_t i) const +{ + char* str = BNGetReportTitle(m_object, i); + string result = str; + BNFreeString(str); + return result; +} + + +string ReportCollection::GetContents(size_t i) const +{ + char* str = BNGetReportContents(m_object, i); + string result = str; + BNFreeString(str); + return result; +} + + +string ReportCollection::GetPlainText(size_t i) const +{ + char* str = BNGetReportPlainText(m_object, i); + string result = str; + BNFreeString(str); + return result; +} + + +Ref<FlowGraph> ReportCollection::GetFlowGraph(size_t i) const +{ + BNFlowGraph* graph = BNGetReportFlowGraph(m_object, i); + if (!graph) + return nullptr; + return new CoreFlowGraph(graph); +} + + +void ReportCollection::AddPlainTextReport(Ref<BinaryView> view, const string& title, const string& contents) +{ + BNAddPlainTextReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), contents.c_str()); +} + + +void ReportCollection::AddMarkdownReport(Ref<BinaryView> view, const string& title, const string& contents, + const string& plainText) +{ + BNAddMarkdownReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), contents.c_str(), + plainText.c_str()); +} + + +void ReportCollection::AddHTMLReport(Ref<BinaryView> view, const string& title, const string& contents, + const string& plainText) +{ + BNAddHTMLReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), contents.c_str(), + plainText.c_str()); +} + + +void ReportCollection::AddGraphReport(Ref<BinaryView> view, const string& title, Ref<FlowGraph> graph) +{ + BNAddGraphReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), graph->GetObject()); +} diff --git a/lowlevelil.cpp b/lowlevelil.cpp index 40748327..3e09e085 100644 --- a/lowlevelil.cpp +++ b/lowlevelil.cpp @@ -766,3 +766,10 @@ size_t LowLevelILFunction::GetMappedMediumLevelILExprIndex(size_t expr) const { return BNGetMappedMediumLevelILExprIndex(m_object, expr); } + + +Ref<FlowGraph> LowLevelILFunction::CreateFunctionGraph(DisassemblySettings* settings) +{ + BNFlowGraph* graph = BNCreateLowLevelILFunctionGraph(m_object, settings ? settings->GetObject() : nullptr); + return new CoreFlowGraph(graph); +} diff --git a/lowlevelilinstruction.cpp b/lowlevelilinstruction.cpp index 1522596b..f185b274 100644 --- a/lowlevelilinstruction.cpp +++ b/lowlevelilinstruction.cpp @@ -2510,11 +2510,11 @@ int64_t LowLevelILInstruction::GetVector() const } -size_t LowLevelILInstruction::GetStackAdjustment() const +int64_t LowLevelILInstruction::GetStackAdjustment() const { size_t operandIndex; if (GetOperandIndexForUsage(StackAdjustmentLowLevelOperandUsage, operandIndex)) - return (size_t)GetRawOperandAsInteger(operandIndex); + return GetRawOperandAsInteger(operandIndex); throw LowLevelILInstructionAccessException(); } @@ -3181,7 +3181,7 @@ ExprId LowLevelILFunction::Call(ExprId dest, const ILSourceLocation& loc) } -ExprId LowLevelILFunction::CallStackAdjust(ExprId dest, size_t adjust, +ExprId LowLevelILFunction::CallStackAdjust(ExprId dest, int64_t adjust, const std::map<uint32_t, int32_t>& regStackAdjust, const ILSourceLocation& loc) { vector<size_t> list; diff --git a/lowlevelilinstruction.h b/lowlevelilinstruction.h index 09cae9f4..4a54b8c5 100644 --- a/lowlevelilinstruction.h +++ b/lowlevelilinstruction.h @@ -714,7 +714,7 @@ namespace BinaryNinja template <BNLowLevelILOperation N> int64_t GetConstant() const { return As<N>().GetConstant(); } template <BNLowLevelILOperation N> uint64_t GetOffset() const { return As<N>().GetOffset(); } template <BNLowLevelILOperation N> int64_t GetVector() const { return As<N>().GetVector(); } - template <BNLowLevelILOperation N> size_t GetStackAdjustment() const { return As<N>().GetStackAdjustment(); } + template <BNLowLevelILOperation N> int64_t GetStackAdjustment() const { return As<N>().GetStackAdjustment(); } template <BNLowLevelILOperation N> size_t GetTarget() const { return As<N>().GetTarget(); } template <BNLowLevelILOperation N> size_t GetTrueTarget() const { return As<N>().GetTrueTarget(); } template <BNLowLevelILOperation N> size_t GetFalseTarget() const { return As<N>().GetFalseTarget(); } @@ -779,7 +779,7 @@ namespace BinaryNinja int64_t GetConstant() const; uint64_t GetOffset() const; int64_t GetVector() const; - size_t GetStackAdjustment() const; + int64_t GetStackAdjustment() const; size_t GetTarget() const; size_t GetTrueTarget() const; size_t GetFalseTarget() const; @@ -1112,7 +1112,7 @@ namespace BinaryNinja template <> struct LowLevelILInstructionAccessor<LLIL_CALL_STACK_ADJUST>: public LowLevelILInstructionBase { LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } - size_t GetStackAdjustment() const { return (size_t)GetRawOperandAsInteger(1); } + int64_t GetStackAdjustment() const { return GetRawOperandAsInteger(1); } std::map<uint32_t, int32_t> GetRegisterStackAdjustments() const { return GetRawOperandAsRegisterStackAdjustments(2); } }; template <> struct LowLevelILInstructionAccessor<LLIL_TAILCALL>: public LowLevelILInstructionBase diff --git a/mediumlevelil.cpp b/mediumlevelil.cpp index cac45dd6..2d1fe904 100644 --- a/mediumlevelil.cpp +++ b/mediumlevelil.cpp @@ -738,3 +738,10 @@ Confidence<Ref<Type>> MediumLevelILFunction::GetExprType(const MediumLevelILInst { return GetExprType(expr.exprIndex); } + + +Ref<FlowGraph> MediumLevelILFunction::CreateFunctionGraph(DisassemblySettings* settings) +{ + BNFlowGraph* graph = BNCreateMediumLevelILFunctionGraph(m_object, settings ? settings->GetObject() : nullptr); + return new CoreFlowGraph(graph); +} diff --git a/mediumlevelilinstruction.cpp b/mediumlevelilinstruction.cpp index c7627bd7..08472004 100644 --- a/mediumlevelilinstruction.cpp +++ b/mediumlevelilinstruction.cpp @@ -122,6 +122,7 @@ unordered_map<BNMediumLevelILOperation, vector<MediumLevelILOperandUsage>> {MLIL_ADDRESS_OF_FIELD, {SourceVariableMediumLevelOperandUsage, OffsetMediumLevelOperandUsage}}, {MLIL_JUMP, {DestExprMediumLevelOperandUsage}}, {MLIL_JUMP_TO, {DestExprMediumLevelOperandUsage, TargetListMediumLevelOperandUsage}}, + {MLIL_RET_HINT, {DestExprMediumLevelOperandUsage}}, {MLIL_CALL, {OutputVariablesMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, ParameterExprsMediumLevelOperandUsage}}, {MLIL_CALL_UNTYPED, {OutputVariablesSubExprMediumLevelOperandUsage, DestExprMediumLevelOperandUsage, @@ -1323,6 +1324,7 @@ void MediumLevelILInstruction::VisitExprs(const std::function<bool(const MediumL case MLIL_BOOL_TO_INT: case MLIL_JUMP: case MLIL_JUMP_TO: + case MLIL_RET_HINT: case MLIL_IF: case MLIL_UNIMPL_MEM: case MLIL_LOAD: @@ -1592,6 +1594,7 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest, case MLIL_LOW_PART: case MLIL_BOOL_TO_INT: case MLIL_JUMP: + case MLIL_RET_HINT: case MLIL_UNIMPL_MEM: case MLIL_FSQRT: case MLIL_FNEG: @@ -2506,6 +2509,12 @@ ExprId MediumLevelILFunction::JumpTo(ExprId dest, const vector<BNMediumLevelILLa } +ExprId MediumLevelILFunction::ReturnHint(ExprId dest, const ILSourceLocation& loc) +{ + return AddExprWithLocation(MLIL_RET_HINT, loc, 0, dest); +} + + ExprId MediumLevelILFunction::Call(const vector<Variable>& output, ExprId dest, const vector<ExprId>& params, const ILSourceLocation& loc) { diff --git a/mediumlevelilinstruction.h b/mediumlevelilinstruction.h index ec8a8371..9f4784a1 100644 --- a/mediumlevelilinstruction.h +++ b/mediumlevelilinstruction.h @@ -814,6 +814,10 @@ namespace BinaryNinja MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } MediumLevelILIndexList GetTargetList() const { return GetRawOperandAsIndexList(1); } }; + template <> struct MediumLevelILInstructionAccessor<MLIL_RET_HINT>: public MediumLevelILInstructionBase + { + MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } + }; template <> struct MediumLevelILInstructionAccessor<MLIL_CALL>: public MediumLevelILInstructionBase { diff --git a/python/__init__.py b/python/__init__.py index 947739ca..9f8cbc79 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -96,6 +96,7 @@ import binaryninja._binaryninjacore as core # "pluginmanager", # "setting", # "metadata", +# "flowgraph", # ] from binaryninja.enums import * from binaryninja.databuffer import * @@ -126,6 +127,7 @@ from binaryninja.downloadprovider import * from binaryninja.pluginmanager import * from binaryninja.setting import * from binaryninja.metadata import * +from binaryninja.flowgraph import * def shutdown(): diff --git a/python/basicblock.py b/python/basicblock.py index 11d5a7f4..353771d9 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -245,14 +245,7 @@ class BasicBlock(object): >>> current_basic_block.highlight <color: blue> """ - color = core.BNGetBasicBlockHighlight(self.handle) - if color.style == HighlightColorStyle.StandardHighlightColor: - return highlight.HighlightColor(color=color.color, alpha=color.alpha) - elif color.style == HighlightColorStyle.MixedHighlightColor: - return highlight.HighlightColor(color=color.color, mix_color=color.mixColor, mix=color.mix, alpha=color.alpha) - elif color.style == HighlightColorStyle.CustomHighlightColor: - return highlight.HighlightColor(red=color.r, green=color.g, blue=color.b, alpha=color.alpha) - return highlight.HighlightColor(color=HighlightStandardColor.NoHighlightColor) + return highlight.HighlightColor._from_core_struct(core.BNGetBasicBlockHighlight(self.handle)) @highlight.setter def highlight(self, value): @@ -345,6 +338,7 @@ class BasicBlock(object): il_instr = self.il_function[lines[i].instrIndex] else: il_instr = None + color = highlight.HighlightColor._from_core_struct(lines[i].highlight) tokens = [] for j in range(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -356,7 +350,7 @@ class BasicBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(binaryninja.function.DisassemblyTextLine(addr, tokens, il_instr)) + result.append(binaryninja.function.DisassemblyTextLine(tokens, addr, il_instr, color)) core.BNFreeDisassemblyTextLines(lines, count.value) return result diff --git a/python/binaryview.py b/python/binaryview.py index 8d44872b..f7ead7a6 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -36,6 +36,7 @@ from binaryninja import databuffer from binaryninja import basicblock from binaryninja import lineardisassembly from binaryninja import metadata +from binaryninja import highlight # 2-3 compatibility from binaryninja import range @@ -3147,6 +3148,7 @@ class BinaryView(object): func = binaryninja.function.Function(self, core.BNNewFunctionReference(lines[i].function)) if lines[i].block: block = basicblock.BasicBlock(self, core.BNNewBasicBlockReference(lines[i].block)) + color = highlight.HighlightColor._from_core_struct(lines[i].contents.highlight) addr = lines[i].contents.addr tokens = [] for j in range(0, lines[i].contents.count): @@ -3159,7 +3161,7 @@ class BinaryView(object): confidence = lines[i].contents.tokens[j].confidence address = lines[i].contents.tokens[j].address tokens.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - contents = binaryninja.function.DisassemblyTextLine(addr, tokens) + contents = binaryninja.function.DisassemblyTextLine(tokens, addr, color = color) result.append(lineardisassembly.LinearDisassemblyLine(lines[i].type, func, block, lines[i].lineOffset, contents)) func = None @@ -3538,6 +3540,9 @@ class BinaryView(object): def show_html_report(self, title, contents, plaintext = ""): core.BNShowHTMLReport(self.handle, title, contents, plaintext) + def show_graph_report(self, title, graph): + core.BNShowHTMLReport(self.handle, title, graph.handle) + def get_address_input(self, prompt, title, current_address = None): if current_address is None: current_address = self.file.offset diff --git a/python/flowgraph.py b/python/flowgraph.py new file mode 100644 index 00000000..4d551c83 --- /dev/null +++ b/python/flowgraph.py @@ -0,0 +1,633 @@ +# Copyright (c) 2018 Vector 35 LLC +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import ctypes +import threading +import traceback + +# Binary Ninja components +import binaryninja +from binaryninja.enums import (BranchType, InstructionTextTokenType, HighlightStandardColor) +from binaryninja import _binaryninjacore as core +from binaryninja import function +from binaryninja import binaryview +from binaryninja import lowlevelil +from binaryninja import mediumlevelil +from binaryninja import basicblock +from binaryninja import log +from binaryninja import highlight + +# 2-3 compatibility +from binaryninja import range + + +class FlowGraphEdge(object): + def __init__(self, branch_type, source, target, points, back_edge): + self.type = BranchType(branch_type) + self.source = source + self.target = target + self.points = points + self.back_edge = back_edge + + def __repr__(self): + return "<%s: %s>" % (self.type.name, repr(self.target)) + + +class FlowGraphNode(object): + def __init__(self, graph, handle = None): + if handle is None: + handle = core.BNCreateFlowGraphNode(graph.handle) + self.handle = handle + self.graph = graph + + def __del__(self): + core.BNFreeFlowGraphNode(self.handle) + + def __eq__(self, value): + if not isinstance(value, FlowGraphNode): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, FlowGraphNode): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + + @property + def basic_block(self): + """Basic block associated with this part of the flow graph (read-only)""" + block = core.BNGetFlowGraphBasicBlock(self.handle) + if not block: + return None + func_handle = core.BNGetBasicBlockFunction(block) + if not func_handle: + core.BNFreeBasicBlock(block) + return None + + view = binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle)) + func = function.Function(view, func_handle) + + if core.BNIsLowLevelILBasicBlock(block): + block = lowlevelil.LowLevelILBasicBlock(view, block, + lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func)) + elif core.BNIsMediumLevelILBasicBlock(block): + block = mediumlevelil.MediumLevelILBasicBlock(view, block, + mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func)) + else: + block = basicblock.BasicBlock(view, block) + return block + + @property + def x(self): + """Flow graph block X (read-only)""" + return core.BNGetFlowGraphNodeX(self.handle) + + @property + def y(self): + """Flow graph block Y (read-only)""" + return core.BNGetFlowGraphNodeY(self.handle) + + @property + def width(self): + """Flow graph block width (read-only)""" + return core.BNGetFlowGraphNodeWidth(self.handle) + + @property + def height(self): + """Flow graph block height (read-only)""" + return core.BNGetFlowGraphNodeHeight(self.handle) + + @property + def lines(self): + """Flow graph block list of text lines""" + count = ctypes.c_ulonglong() + lines = core.BNGetFlowGraphNodeLines(self.handle, count) + block = self.basic_block + result = [] + for i in range(0, count.value): + addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and (block is not None) and hasattr(block, 'il_function'): + il_instr = block.il_function[lines[i].instrIndex] + else: + il_instr = None + color = highlight.HighlightColor._from_core_struct(lines[i].highlight) + tokens = [] + for j in range(0, lines[i].count): + token_type = InstructionTextTokenType(lines[i].tokens[j].type) + text = lines[i].tokens[j].text + value = lines[i].tokens[j].value + size = lines[i].tokens[j].size + operand = lines[i].tokens[j].operand + context = lines[i].tokens[j].context + confidence = lines[i].tokens[j].confidence + address = lines[i].tokens[j].address + tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) + result.append(function.DisassemblyTextLine(tokens, addr, il_instr, color)) + core.BNFreeDisassemblyTextLines(lines, count.value) + return result + + @lines.setter + def lines(self, lines): + if isinstance(lines, str): + lines = lines.split('\n') + line_buf = (core.BNDisassemblyTextLine * len(lines))() + for i in range(0, len(lines)): + line = lines[i] + if isinstance(line, str): + line = function.DisassemblyTextLine([function.InstructionTextToken(InstructionTextTokenType.TextToken, line)]) + if not isinstance(line, function.DisassemblyTextLine): + line = function.DisassemblyTextLine(line) + if line.address is None: + if len(line.tokens) > 0: + line_buf[i].addr = line.tokens[0].address + else: + line_buf[i].addr = 0 + else: + line_buf[i].addr = line.address + if line.il_instruction is not None: + line_buf[i].instrIndex = line.il_instruction.instr_index + else: + line_buf[i].instrIndex = 0xffffffffffffffff + color = line.highlight + if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") + if isinstance(color, HighlightStandardColor): + color = highlight.HighlightColor(color) + line_buf[i].highlight = color._get_core_struct() + line_buf[i].count = len(line.tokens) + line_buf[i].tokens = (core.BNInstructionTextToken * len(line.tokens))() + for j in range(0, len(line.tokens)): + line_buf[i].tokens[j].type = line.tokens[j].type + line_buf[i].tokens[j].text = line.tokens[j].text + line_buf[i].tokens[j].value = line.tokens[j].value + line_buf[i].tokens[j].size = line.tokens[j].size + line_buf[i].tokens[j].operand = line.tokens[j].operand + line_buf[i].tokens[j].context = line.tokens[j].context + line_buf[i].tokens[j].confidence = line.tokens[j].confidence + line_buf[i].tokens[j].address = line.tokens[j].address + core.BNSetFlowGraphNodeLines(self.handle, line_buf, len(lines)) + + @property + def outgoing_edges(self): + """Flow graph block list of outgoing edges (read-only)""" + count = ctypes.c_ulonglong() + edges = core.BNGetFlowGraphNodeOutgoingEdges(self.handle, count) + result = [] + for i in range(0, count.value): + branch_type = BranchType(edges[i].type) + target = edges[i].target + if target: + target = FlowGraphNode(self.graph, core.BNNewFlowGraphNodeReference(target)) + points = [] + for j in range(0, edges[i].pointCount): + points.append((edges[i].points[j].x, edges[i].points[j].y)) + result.append(FlowGraphEdge(branch_type, self, target, points, edges[i].backEdge)) + core.BNFreeFlowGraphNodeOutgoingEdgeList(edges, count.value) + return result + + @property + def highlight(self): + """Gets or sets the highlight color for the node + + :Example: + >>> g = FlowGraph() + >>> node = FlowGraphNode(g) + >>> node.highlight = HighlightStandardColor.BlueHighlightColor + >>> node.highlight + <color: blue> + """ + return highlight.HighlightColor._from_core_struct(core.BNGetFlowGraphNodeHighlight(self.handle)) + + @highlight.setter + def highlight(self, color): + if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") + if isinstance(color, HighlightStandardColor): + color = highlight.HighlightColor(color) + core.BNSetFlowGraphNodeHighlight(self.handle, color._get_core_struct()) + + def __repr__(self): + block = self.basic_block + if block: + arch = block.arch + if arch: + return "<graph node: %s@%#x-%#x>" % (arch.name, block.start, block.end) + else: + return "<graph node: %#x-%#x>" % (block.start, block.end) + return "<graph node>" + + def __iter__(self): + count = ctypes.c_ulonglong() + lines = core.BNGetFlowGraphNodeLines(self.handle, count) + block = self.basic_block + try: + for i in range(0, count.value): + addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and (block is not None) and hasattr(block, 'il_function'): + il_instr = block.il_function[lines[i].instrIndex] + else: + il_instr = None + tokens = [] + for j in range(0, lines[i].count): + token_type = InstructionTextTokenType(lines[i].tokens[j].type) + text = lines[i].tokens[j].text + value = lines[i].tokens[j].value + size = lines[i].tokens[j].size + operand = lines[i].tokens[j].operand + context = lines[i].tokens[j].context + confidence = lines[i].tokens[j].confidence + address = lines[i].tokens[j].address + tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) + yield function.DisassemblyTextLine(tokens, addr, il_instr) + finally: + core.BNFreeDisassemblyTextLines(lines, count.value) + + def add_outgoing_edge(self, edge_type, target): + """ + ``add_outgoing_edge`` connects two flow graph nodes with an edge. + + :param BranchType edge_type: Type of edge to add + :param FlowGraphNode target: Target node object + """ + core.BNAddFlowGraphNodeOutgoingEdge(self.handle, edge_type, target.handle) + + +class FlowGraphLayoutRequest(object): + def __init__(self, graph, callback = None): + self.on_complete = callback + self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._complete) + self.handle = core.BNStartFlowGraphLayout(graph.handle, None, self._cb) + + def __del__(self): + self.abort() + core.BNFreeFlowGraphLayoutRequest(self.handle) + + def _complete(self, ctxt): + try: + if self.on_complete is not None: + self.on_complete() + except: + log.log_error(traceback.format_exc()) + + @property + def complete(self): + """Whether flow graph layout is complete (read-only)""" + return core.BNIsFlowGraphLayoutRequestComplete(self.handle) + + @property + def graph(self): + """Flow graph that is being processed (read-only)""" + return CoreFlowGraph(core.BNGetGraphForFlowGraphLayoutRequest(self.handle)) + + def abort(self): + core.BNAbortFlowGraphLayoutRequest(self.handle) + self.on_complete = None + + +class FlowGraph(object): + """ + ``class FlowGraph`` implements a directed flow graph to be shown in the UI. This class allows plugins to + create custom flow graphs and render them in the UI using the flow graph report API. + + An example of creating a flow graph and presenting it in the UI: + + >>> graph = FlowGraph() + >>> node_a = FlowGraphNode(graph) + >>> node_a.lines = ["Node A"] + >>> node_b = FlowGraphNode(graph) + >>> node_b.lines = ["Node B"] + >>> node_c = FlowGraphNode(graph) + >>> node_c.lines = ["Node C"] + >>> graph.append(node_a) + 0 + >>> graph.append(node_b) + 1 + >>> graph.append(node_c) + 2 + >>> node_a.add_outgoing_edge(BranchType.UnconditionalBranch, node_b) + >>> node_a.add_outgoing_edge(BranchType.UnconditionalBranch, node_c) + >>> show_graph_report("Custom Graph", graph) + + .. note:: In the current implementation, only graphs that have a single start node where all other nodes are \ + reachable from outgoing edges can be rendered correctly. This describes the natural limitations of a control \ + flow graph, which is what the rendering logic was designed for. Graphs that have nodes that are only reachable \ + from incoming edges, or graphs that have disjoint subgraphs will not render correctly. This will be fixed \ + in a future version. + """ + def __init__(self, handle = None): + if handle is None: + self._ext_cb = core.BNCustomFlowGraph() + self._ext_cb.context = 0 + self._ext_cb.prepareForLayout = self._ext_cb.prepareForLayout.__class__(self._prepare_for_layout) + self._ext_cb.populateNodes = self._ext_cb.populateNodes.__class__(self._populate_nodes) + self._ext_cb.completeLayout = self._ext_cb.completeLayout.__class__(self._complete_layout) + self._ext_cb.update = self._ext_cb.update.__class__(self._update) + handle = core.BNCreateCustomFlowGraph(self._ext_cb) + self.handle = handle + + def __del__(self): + core.BNFreeFlowGraph(self.handle) + + def __eq__(self, value): + if not isinstance(value, FlowGraph): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, FlowGraph): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + + def _prepare_for_layout(self, ctxt): + try: + self.prepare_for_layout() + except: + log.log_error(traceback.format_exc()) + + def _populate_nodes(self, ctxt): + try: + self.populate_nodes() + except: + log.log_error(traceback.format_exc()) + + def _complete_layout(self, ctxt): + try: + self.complete_layout() + except: + log.log_error(traceback.format_exc()) + + def _update(self, ctxt): + try: + graph = self.update() + if graph is None: + return None + return core.BNNewFlowGraphReference(graph.handle) + except: + log.log_error(traceback.format_exc()) + return None + + def finish_prepare_for_layout(self): + """ + ``finish_prepare_for_layout`` signals that preparations for rendering a graph are complete. + This method should only be called by a ``prepare_for_layout`` reimplementation. + """ + core.BNFinishPrepareForLayout(self.handle) + + def prepare_for_layout(self): + """ + ``prepare_for_layout`` can be overridden by subclasses to handling preparations that must take + place before a flow graph is rendered, such as waiting for a function to finish analysis. If + this function is overridden, the ``finish_prepare_for_layout`` method must be called once + preparations are completed. + """ + self.finish_prepare_for_layout() + + def populate_nodes(self): + """ + ``prepare_for_layout`` can be overridden by subclasses to create nodes in a graph when a flow + graph needs to be rendered. This will happen on a worker thread and will not block the UI. + """ + pass + + def complete_layout(self): + """ + ``complete_layout`` can be overridden by subclasses and is called when a graph layout is completed. + """ + pass + + @property + def function(self): + """Function for a flow graph""" + func = core.BNGetFunctionForFlowGraph(self.handle) + if func is None: + return None + return function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), func) + + @function.setter + def function(self, func): + if func is not None: + func = func.handle + core.BNSetFunctionForFlowGraph(self.handle, func) + + @property + def complete(self): + """Whether flow graph layout is complete (read-only)""" + return core.BNIsFlowGraphLayoutComplete(self.handle) + + @property + def nodes(self): + """List of nodes in graph (read-only)""" + count = ctypes.c_ulonglong() + blocks = core.BNGetFlowGraphNodes(self.handle, count) + result = [] + for i in range(0, count.value): + result.append(FlowGraphNode(self, core.BNNewFlowGraphNodeReference(blocks[i]))) + core.BNFreeFlowGraphNodeList(blocks, count.value) + return result + + @property + def has_nodes(self): + """Whether the flow graph has at least one node (read-only)""" + return core.BNFlowGraphHasNodes(self.handle) + + @property + def width(self): + """Flow graph width (read-only)""" + return core.BNGetFlowGraphWidth(self.handle) + + @property + def height(self): + """Flow graph height (read-only)""" + return core.BNGetFlowGraphHeight(self.handle) + + @property + def horizontal_block_margin(self): + return core.BNGetHorizontalFlowGraphBlockMargin(self.handle) + + @horizontal_block_margin.setter + def horizontal_block_margin(self, value): + core.BNSetFlowGraphBlockMargins(self.handle, value, self.vertical_block_margin) + + @property + def vertical_block_margin(self): + return core.BNGetVerticalFlowGraphBlockMargin(self.handle) + + @vertical_block_margin.setter + def vertical_block_margin(self, value): + core.BNSetFlowGraphBlockMargins(self.handle, self.horizontal_block_margin, value) + + @property + def is_il(self): + return core.BNIsILFlowGraph(self.handle) + + @property + def is_low_level_il(self): + return core.BNIsLowLevelILFlowGraph(self.handle) + + @property + def is_medium_level_il(self): + return core.BNIsMediumLevelILFlowGraph(self.handle) + + @property + def il_function(self): + if self.is_low_level_il: + il_func = core.BNGetFlowGraphLowLevelILFunction(self.handle) + if not il_func: + return None + function = self.function + if function is None: + return None + return lowlevelil.LowLevelILFunction(function.arch, il_func, function) + if self.is_medium_level_il: + il_func = core.BNGetFlowGraphMediumLevelILFunction(self.handle) + if not il_func: + return None + function = self.function + if function is None: + return None + return mediumlevelil.MediumLevelILFunction(function.arch, il_func, function) + return None + + @il_function.setter + def il_function(self, func): + if isinstance(func, lowlevelil.LowLevelILFunction): + core.BNSetFlowGraphLowLevelILFunction(self.handle, func.handle) + core.BNSetFlowGraphMediumLevelILFunction(self.handle, None) + elif isinstance(func, mediumlevelil.MediumLevelILFunction): + core.BNSetFlowGraphLowLevelILFunction(self.handle, None) + core.BNSetFlowGraphMediumLevelILFunction(self.handle, func.handle) + elif func is None: + core.BNSetFlowGraphLowLevelILFunction(self.handle, None) + core.BNSetFlowGraphMediumLevelILFunction(self.handle, None) + else: + raise TypeError("expected IL function for setting il_function property") + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + def __repr__(self): + function = self.function + if function is None: + return "<flow graph>" + return "<graph of %s>" % repr(function) + + def __iter__(self): + count = ctypes.c_ulonglong() + nodes = core.BNGetFlowGraphNodes(self.handle, count) + try: + for i in range(0, count.value): + yield FlowGraphNode(self, core.BNNewFlowGraphNodeReference(nodes[i])) + finally: + core.BNFreeFlowGraphNodeList(nodes, count.value) + + def layout(self, callback = None): + """ + ``layout`` starts rendering a graph for display. Once a layout is complete, each node will contain + coordinates and extents that can be used to render a graph with minimum additional computation. + This function does not wait for the graph to be ready to display, but a callback can be provided + to signal when the graph is ready. + + :param callable() callback: Function to be called when the graph is ready to display + :return: Pending flow graph layout request object + :rtype: FlowGraphLayoutRequest + """ + return FlowGraphLayoutRequest(self, callback) + + def _wait_complete(self): + self._wait_cond.acquire() + self._wait_cond.notify() + self._wait_cond.release() + + def layout_and_wait(self): + """ + ``layout_and_wait`` starts rendering a graph for display, and waits for the graph to be ready to + display. After this function returns, each node will contain coordinates and extents that can be + used to render a graph with minimum additional computation. + + Do not use this API on the UI thread (use ``layout`` with a callback instead). + """ + self._wait_cond = threading.Condition() + request = self.layout(self._wait_complete) + + self._wait_cond.acquire() + while not request.complete: + self._wait_cond.wait() + self._wait_cond.release() + + def get_nodes_in_region(self, left, top, right, bottom): + count = ctypes.c_ulonglong() + nodes = core.BNGetFlowGraphNodesInRegion(self.handle, left, top, right, bottom, count) + result = [] + for i in range(0, count.value): + result.append(FlowGraphNode(self, core.BNNewFlowGraphNodeReference(nodes[i]))) + core.BNFreeFlowGraphNodeList(nodes, count.value) + return result + + def append(self, node): + """ + ``append`` adds a node to a flow graph. + + :param FlowGraphNode node: Node to add + :return: Index of node + :rtype: int + """ + return core.BNAddFlowGraphNode(self.handle, node.handle) + + def __getitem__(self, i): + node = core.BNGetFlowGraphNode(self.handle, i) + if node is None: + return None + return FlowGraphNode(self, node) + + def show(self, title): + """ + ``show`` displays the graph in a new tab in the UI. + + :param str title: Title to show in the new tab + """ + binaryninja.interaction.show_graph_report(title, self) + + def update(self): + """ + ``update`` can be overridden by subclasses to allow a graph to be updated after it has been + presented in the UI. This will automatically occur if the function referenced by the ``function`` + property has been updated. + + Return a new ``FlowGraph`` object with the new information if updates are desired. If the graph + does not need updating, ``None`` can be returned to leave the graph in its current state. + + :return: Updated graph, or ``None`` + :rtype: FlowGraph + """ + return None + + +class CoreFlowGraph(FlowGraph): + def __init__(self, handle): + super(CoreFlowGraph, self).__init__(handle) + + def update(self): + graph = core.BNUpdateFlowGraph(self.handle) + if not graph: + return None + return CoreFlowGraph(graph) diff --git a/python/function.py b/python/function.py index 0589a5e2..6da86196 100644 --- a/python/function.py +++ b/python/function.py @@ -704,13 +704,13 @@ class Function(object): @stack_adjustment.setter def stack_adjustment(self, value): - sc = core.BNSizeWithConfidence() - sc.value = int(value) + oc = core.BNOffsetWithConfidence() + oc.value = int(value) if hasattr(value, 'confidence'): - sc.confidence = value.confidence + oc.confidence = value.confidence else: - sc.confidence = types.max_confidence - core.BNSetUserFunctionStackAdjustment(self.handle, sc) + oc.confidence = types.max_confidence + core.BNSetUserFunctionStackAdjustment(self.handle, oc) @property def reg_stack_adjustments(self): @@ -847,6 +847,14 @@ class Function(object): def analysis_skip_override(self, override): core.BNSetFunctionAnalysisSkipOverride(self.handle, override) + @property + def unresolved_stack_adjustment_graph(self): + """Flow graph of unresolved stack adjustments (read-only)""" + graph = core.BNGetUnresolvedStackAdjustmentGraph(self.handle) + if not graph: + return None + return binaryninja.flowgraph.CoreFlowGraph(graph) + def __iter__(self): count = ctypes.c_ulonglong() blocks = core.BNGetFunctionBasicBlockList(self.handle, count) @@ -1111,8 +1119,12 @@ class Function(object): core.BNFreeRegisterList(flags) return result - def create_graph(self): - return FunctionGraph(self._view, core.BNCreateFunctionGraph(self.handle)) + def create_graph(self, graph_type = FunctionGraphType.NormalFunctionGraph, settings = None): + if settings is not None: + settings_obj = settings.handle + else: + settings_obj = None + return binaryninja.flowgraph.CoreFlowGraph(core.BNCreateFunctionGraph(self.handle, graph_type, settings_obj)) def apply_imported_types(self, sym): core.BNApplyImportedTypes(self.handle, sym.handle) @@ -1250,13 +1262,13 @@ class Function(object): core.BNSetAutoFunctionCanReturn(self.handle, bc) def set_auto_stack_adjustment(self, value): - sc = core.BNSizeWithConfidence() - sc.value = int(value) + oc = core.BNOffsetWithConfidence() + oc.value = int(value) if hasattr(value, 'confidence'): - sc.confidence = value.confidence + oc.confidence = value.confidence else: - sc.confidence = types.max_confidence - core.BNSetAutoFunctionStackAdjustment(self.handle, sc) + oc.confidence = types.max_confidence + core.BNSetAutoFunctionStackAdjustment(self.handle, oc) def set_auto_reg_stack_adjustments(self, value): adjust = (core.BNRegisterStackAdjustment * len(value))() @@ -1466,6 +1478,7 @@ class Function(object): result = [] for i in range(0, count.value): addr = lines[i].addr + color = highlight.HighlightColor._from_core_struct(lines[i].highlight) tokens = [] for j in range(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -1477,7 +1490,7 @@ class Function(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(DisassemblyTextLine(addr, tokens)) + result.append(DisassemblyTextLine(tokens, addr, color = color)) core.BNFreeDisassemblyTextLines(lines, count.value) return result @@ -1573,6 +1586,15 @@ class Function(object): result = types.RegisterStackAdjustmentWithConfidence(adjust.adjustment, confidence = adjust.confidence) return result + def is_call_instruction(self, addr, arch=None): + if arch is None: + arch = self.arch + return core.BNIsCallInstruction(self.handle, arch.handle, addr) + + def request_debug_report(self, name): + core.BNRequestFunctionDebugReport(self.handle, name) + self.view.update_analysis() + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): @@ -1603,10 +1625,18 @@ class AdvancedFunctionAnalysisDataRequestor(object): class DisassemblyTextLine(object): - def __init__(self, addr, tokens, il_instr = None): - self.address = addr + def __init__(self, tokens, address = None, il_instr = None, color = None): + self.address = address self.tokens = tokens self.il_instruction = il_instr + if color is None: + self.highlight = highlight.HighlightColor() + else: + if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") + if isinstance(color, HighlightStandardColor): + color = highlight.HighlightColor(color) + self.highlight = color def __str__(self): result = "" @@ -1615,192 +1645,11 @@ class DisassemblyTextLine(object): return result def __repr__(self): + if self.address is None: + return str(self) return "<%#x: %s>" % (self.address, str(self)) -class FunctionGraphEdge(object): - def __init__(self, branch_type, source, target, points, back_edge): - self.type = BranchType(branch_type) - self.source = source - self.target = target - self.points = points - self.back_edge = back_edge - - def __repr__(self): - return "<%s: %s>" % (self.type.name, repr(self.target)) - - -class FunctionGraphBlock(object): - def __init__(self, handle, graph): - self.handle = handle - self.graph = graph - - def __del__(self): - core.BNFreeFunctionGraphBlock(self.handle) - - def __eq__(self, value): - if not isinstance(value, FunctionGraphBlock): - return False - return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) - - def __ne__(self, value): - if not isinstance(value, FunctionGraphBlock): - return True - return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) - - @property - def basic_block(self): - """Basic block associated with this part of the function graph (read-only)""" - block = core.BNGetFunctionGraphBasicBlock(self.handle) - func_handle = core.BNGetBasicBlockFunction(block) - if func_handle is None: - core.BNFreeBasicBlock(block) - return None - - view = binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle)) - func = Function(view, func_handle) - - if core.BNIsLowLevelILBasicBlock(block): - block = binaryninja.lowlevelil.LowLevelILBasicBlock(view, block, - lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func)) - elif core.BNIsMediumLevelILBasicBlock(block): - block = binaryninja.mediumlevelil.MediumLevelILBasicBlock(view, block, - mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func)) - else: - block = binaryninja.basicblock.BasicBlock(view, block) - return block - - @property - def arch(self): - """Function graph block architecture (read-only)""" - arch = core.BNGetFunctionGraphBlockArchitecture(self.handle) - if arch is None: - return None - return binaryninja.architecture.CoreArchitecture._from_cache(arch) - - @property - def start(self): - """Function graph block start (read-only)""" - return core.BNGetFunctionGraphBlockStart(self.handle) - - @property - def end(self): - """Function graph block end (read-only)""" - return core.BNGetFunctionGraphBlockEnd(self.handle) - - @property - def x(self): - """Function graph block X (read-only)""" - return core.BNGetFunctionGraphBlockX(self.handle) - - @property - def y(self): - """Function graph block Y (read-only)""" - return core.BNGetFunctionGraphBlockY(self.handle) - - @property - def width(self): - """Function graph block width (read-only)""" - return core.BNGetFunctionGraphBlockWidth(self.handle) - - @property - def height(self): - """Function graph block height (read-only)""" - return core.BNGetFunctionGraphBlockHeight(self.handle) - - @property - def lines(self): - """Function graph block list of lines (read-only)""" - count = ctypes.c_ulonglong() - lines = core.BNGetFunctionGraphBlockLines(self.handle, count) - block = self.basic_block - result = [] - for i in range(0, count.value): - addr = lines[i].addr - if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'): - il_instr = block.il_function[lines[i].instrIndex] - else: - il_instr = None - tokens = [] - for j in range(0, lines[i].count): - token_type = InstructionTextTokenType(lines[i].tokens[j].type) - text = lines[i].tokens[j].text - value = lines[i].tokens[j].value - size = lines[i].tokens[j].size - operand = lines[i].tokens[j].operand - context = lines[i].tokens[j].context - confidence = lines[i].tokens[j].confidence - address = lines[i].tokens[j].address - tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(DisassemblyTextLine(addr, tokens, il_instr)) - core.BNFreeDisassemblyTextLines(lines, count.value) - return result - - @property - def outgoing_edges(self): - """Function graph block list of outgoing edges (read-only)""" - count = ctypes.c_ulonglong() - edges = core.BNGetFunctionGraphBlockOutgoingEdges(self.handle, count) - result = [] - for i in range(0, count.value): - branch_type = BranchType(edges[i].type) - target = edges[i].target - if target: - func = core.BNGetBasicBlockFunction(target) - if func is None: - core.BNFreeBasicBlock(target) - target = None - else: - target = binaryninja.basicblock.BasicBlock(binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func)), - core.BNNewBasicBlockReference(target)) - core.BNFreeFunction(func) - points = [] - for j in range(0, edges[i].pointCount): - points.append((edges[i].points[j].x, edges[i].points[j].y)) - result.append(FunctionGraphEdge(branch_type, self, target, points, edges[i].backEdge)) - core.BNFreeFunctionGraphBlockOutgoingEdgeList(edges, count.value) - return result - - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - - def __repr__(self): - arch = self.arch - if arch: - return "<graph block: %s@%#x-%#x>" % (arch.name, self.start, self.end) - else: - return "<graph block: %#x-%#x>" % (self.start, self.end) - - def __iter__(self): - count = ctypes.c_ulonglong() - lines = core.BNGetFunctionGraphBlockLines(self.handle, count) - block = self.basic_block - try: - for i in range(0, count.value): - addr = lines[i].addr - if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'): - il_instr = block.il_function[lines[i].instrIndex] - else: - il_instr = None - tokens = [] - for j in range(0, lines[i].count): - token_type = InstructionTextTokenType(lines[i].tokens[j].type) - text = lines[i].tokens[j].text - value = lines[i].tokens[j].value - size = lines[i].tokens[j].size - operand = lines[i].tokens[j].operand - context = lines[i].tokens[j].context - confidence = lines[i].tokens[j].confidence - address = lines[i].tokens[j].address - tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - yield DisassemblyTextLine(addr, tokens, il_instr) - finally: - core.BNFreeDisassemblyTextLines(lines, count.value) - - class DisassemblySettings(object): def __init__(self, handle = None): if handle is None: @@ -1838,198 +1687,6 @@ class DisassemblySettings(object): core.BNSetDisassemblySettingsOption(self.handle, option, state) -_pending_function_graph_completion_events = {} -class FunctionGraph(object): - def __init__(self, view, handle): - self.view = view - self.handle = handle - self._on_complete = None - self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._complete) - - def __del__(self): - self.abort() - core.BNFreeFunctionGraph(self.handle) - - def __eq__(self, value): - if not isinstance(value, FunctionGraph): - return False - return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) - - def __ne__(self, value): - if not isinstance(value, FunctionGraph): - return True - return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) - - @property - def function(self): - """Function for a function graph (read-only)""" - func = core.BNGetFunctionForFunctionGraph(self.handle) - if func is None: - return None - return Function(self.view, func) - - @property - def complete(self): - """Whether function graph layout is complete (read-only)""" - return core.BNIsFunctionGraphLayoutComplete(self.handle) - - @property - def type(self): - """Function graph type (read-only)""" - return FunctionGraphType(core.BNGetFunctionGraphType(self.handle)) - - @property - def blocks(self): - """List of basic blocks in function (read-only)""" - count = ctypes.c_ulonglong() - blocks = core.BNGetFunctionGraphBlocks(self.handle, count) - result = [] - for i in range(0, count.value): - result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)) - core.BNFreeFunctionGraphBlockList(blocks, count.value) - return result - - @property - def has_blocks(self): - """Whether the function graph has at least one block (read-only)""" - return core.BNFunctionGraphHasBlocks(self.handle) - - @property - def width(self): - """Function graph width (read-only)""" - return core.BNGetFunctionGraphWidth(self.handle) - - @property - def height(self): - """Function graph height (read-only)""" - return core.BNGetFunctionGraphHeight(self.handle) - - @property - def horizontal_block_margin(self): - return core.BNGetHorizontalFunctionGraphBlockMargin(self.handle) - - @horizontal_block_margin.setter - def horizontal_block_margin(self, value): - core.BNSetFunctionGraphBlockMargins(self.handle, value, self.vertical_block_margin) - - @property - def vertical_block_margin(self): - return core.BNGetVerticalFunctionGraphBlockMargin(self.handle) - - @vertical_block_margin.setter - def vertical_block_margin(self, value): - core.BNSetFunctionGraphBlockMargins(self.handle, self.horizontal_block_margin, value) - - @property - def settings(self): - return DisassemblySettings(core.BNGetFunctionGraphSettings(self.handle)) - - @property - def is_il(self): - return core.BNIsILFunctionGraph(self.handle) - - @property - def is_low_level_il(self): - return core.BNIsLowLevelILFunctionGraph(self.handle) - - @property - def is_medium_level_il(self): - return core.BNIsMediumLevelILFunctionGraph(self.handle) - - @property - def il_function(self): - if self.is_low_level_il: - il_func = core.BNGetFunctionGraphLowLevelILFunction(self.handle) - if not il_func: - return None - return binaryninja.lowlevelil.LowLevelILFunction(self.function.arch, il_func, self.function) - if self.is_medium_level_il: - il_func = core.BNGetFunctionGraphMediumLevelILFunction(self.handle) - if not il_func: - return None - return binaryninja.mediumlevelil.MediumLevelILFunction(self.function.arch, il_func, self.function) - return None - - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - - def __repr__(self): - return "<graph of %s>" % repr(self.function) - - def __iter__(self): - count = ctypes.c_ulonglong() - blocks = core.BNGetFunctionGraphBlocks(self.handle, count) - try: - for i in range(0, count.value): - yield FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self) - finally: - core.BNFreeFunctionGraphBlockList(blocks, count.value) - - def _complete(self, ctxt): - try: - if self._on_complete is not None: - self._on_complete() - global _pending_function_graph_completion_events - if id(self) in _pending_function_graph_completion_events: - del _pending_function_graph_completion_events[id(self)] - except: - log.log_error(traceback.format_exc()) - - def layout(self, graph_type = FunctionGraphType.NormalFunctionGraph): - if isinstance(graph_type, str): - graph_type = FunctionGraphType[graph_type] - core.BNStartFunctionGraphLayout(self.handle, graph_type) - - def _wait_complete(self): - self._wait_cond.acquire() - self._wait_cond.notify() - self._wait_cond.release() - - def layout_and_wait(self, graph_type=FunctionGraphType.NormalFunctionGraph): - self._wait_cond = threading.Condition() - self.on_complete(self._wait_complete) - self.layout(graph_type) - - self._wait_cond.acquire() - while not self.complete: - self._wait_cond.wait() - self._wait_cond.release() - - def on_complete(self, callback): - global _pending_function_graph_completion_events - _pending_function_graph_completion_events[id(self)] = self - self._on_complete = callback - core.BNSetFunctionGraphCompleteCallback(self.handle, None, self._cb) - - def abort(self): - core.BNAbortFunctionGraph(self.handle) - global _pending_function_graph_completion_events - if id(self) in _pending_function_graph_completion_events: - del _pending_function_graph_completion_events[id(self)] - - def get_blocks_in_region(self, left, top, right, bottom): - count = ctypes.c_ulonglong() - blocks = core.BNGetFunctionGraphBlocksInRegion(self.handle, left, top, right, bottom, count) - result = [] - for i in range(0, count.value): - result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)) - core.BNFreeFunctionGraphBlockList(blocks, count.value) - return result - - def is_option_set(self, option): - if isinstance(option, str): - option = DisassemblyOption[option] - return core.BNIsFunctionGraphOptionSet(self.handle, option) - - def set_option(self, option, state = True): - if isinstance(option, str): - option = DisassemblyOption[option] - core.BNSetFunctionGraphOption(self.handle, option, state) - - class RegisterInfo(object): def __init__(self, full_width_reg, size, offset=0, extend=ImplicitRegisterExtend.NoExtend, index=None): self.full_width_reg = full_width_reg diff --git a/python/highlight.py b/python/highlight.py index 55246a9a..502caa80 100644 --- a/python/highlight.py +++ b/python/highlight.py @@ -110,3 +110,13 @@ class HighlightColor(object): result.b = self.blue return result + + @staticmethod + def _from_core_struct(color): + if color.style == HighlightColorStyle.StandardHighlightColor: + return HighlightColor(color=color.color, alpha=color.alpha) + elif color.style == HighlightColorStyle.MixedHighlightColor: + return HighlightColor(color=color.color, mix_color=color.mixColor, mix=color.mix, alpha=color.alpha) + elif color.style == HighlightColorStyle.CustomHighlightColor: + return HighlightColor(red=color.r, green=color.g, blue=color.b, alpha=color.alpha) + return HighlightColor(color=HighlightStandardColor.NoHighlightColor) diff --git a/python/interaction.py b/python/interaction.py index 49b4e024..e53312cf 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -23,8 +23,10 @@ import traceback # Binary Ninja components from binaryninja import _binaryninjacore as core -from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult +from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult, ReportType from binaryninja import binaryview +from binaryninja import log +from binaryninja import flowgraph # 2-3 compatibility from binaryninja import range @@ -255,6 +257,8 @@ class InteractionHandler(object): self._cb.showPlainTextReport = self._cb.showPlainTextReport.__class__(self._show_plain_text_report) self._cb.showMarkdownReport = self._cb.showMarkdownReport.__class__(self._show_markdown_report) self._cb.showHTMLReport = self._cb.showHTMLReport.__class__(self._show_html_report) + self._cb.showGraphReport = self._cb.showGraphReport.__class__(self._show_graph_report) + self._cb.showReportCollection = self._cb.showReportCollection.__class__(self._show_report_collection) self._cb.getTextLineInput = self._cb.getTextLineInput.__class__(self._get_text_line_input) self._cb.getIntegerInput = self._cb.getIntegerInput.__class__(self._get_int_input) self._cb.getAddressInput = self._cb.getAddressInput.__class__(self._get_address_input) @@ -299,6 +303,22 @@ class InteractionHandler(object): except: log.log_error(traceback.format_exc()) + def _show_graph_report(self, ctxt, view, title, graph): + try: + if view: + view = binaryview.BinaryView(handle = core.BNNewViewReference(view)) + else: + view = None + self.show_graph_report(view, title, flowgraph.CoreFlowGraph(core.BNNewFlowGraphReference(graph))) + except: + log.log_error(traceback.format_exc()) + + def _show_report_collection(self, ctxt, title, reports): + try: + self.show_report_collection(title, ReportCollection(core.BNNewReportCollectionReference(reports))) + except: + log.log_error(traceback.format_exc()) + def _get_text_line_input(self, ctxt, result, prompt, title): try: value = self.get_text_line_input(prompt, title) @@ -432,6 +452,12 @@ class InteractionHandler(object): if len(plaintext) != 0: self.show_plain_text_report(view, title, plaintext) + def show_graph_report(self, view, title, graph): + pass + + def show_report_collection(self, title, reports): + pass + def get_text_line_input(self, prompt, title): return None @@ -467,6 +493,123 @@ class InteractionHandler(object): return MessageBoxButtonResult.CancelButton +class PlainTextReport(object): + def __init__(self, title, contents, view = None): + self.view = view + self.title = title + self.contents = contents + + def __repr__(self): + return "<plain text report: %s>" % self.title + + def __str__(self): + return self.contents + + +class MarkdownReport(object): + def __init__(self, title, contents, plaintext = "", view = None): + self.view = view + self.title = title + self.contents = contents + self.plaintext = plaintext + + def __repr__(self): + return "<markdown report: %s>" % self.title + + def __str__(self): + return self.contents + + +class HTMLReport(object): + def __init__(self, title, contents, plaintext = "", view = None): + self.view = view + self.title = title + self.contents = contents + self.plaintext = plaintext + + def __repr__(self): + return "<html report: %s>" % self.title + + def __str__(self): + return self.contents + + +class FlowGraphReport(object): + def __init__(self, title, graph, view = None): + self.view = view + self.title = title + self.graph = graph + + def __repr__(self): + return "<graph report: %s>" % self.title + + +class ReportCollection(object): + def __init__(self, handle = None): + if handle is None: + self.handle = core.BNCreateReportCollection() + else: + self.handle = handle + + def __len__(self): + return core.BNGetReportCollectionCount(self.handle) + + def _report_from_index(self, i): + report_type = core.BNGetReportType(self.handle, i) + title = core.BNGetReportTitle(self.handle, i) + view = core.BNGetReportView(self.handle, i) + if view: + view = binaryview.BinaryView(handle = view) + else: + view = None + if report_type == ReportType.PlainTextReportType: + contents = core.BNGetReportContents(self.handle, i) + return PlainTextReport(title, contents, view) + elif report_type == ReportType.MarkdownReportType: + contents = core.BNGetReportContents(self.handle, i) + plaintext = core.BNGetReportPlainText(self.handle, i) + return MarkdownReport(title, contents, plaintext, view) + elif report_type == ReportType.HTMLReportType: + contents = core.BNGetReportContents(self.handle, i) + plaintext = core.BNGetReportPlainText(self.handle, i) + return HTMLReport(title, contents, plaintext, view) + elif report_type == ReportType.FlowGraphReportType: + graph = flowgraph.CoreFlowGraph(core.BNGetReportFlowGraph(self.handle, i)) + return FlowGraphReport(title, graph, view) + raise TypeError("invalid report type %s" % repr(report_type)) + + def __getitem__(self, i): + if isinstance(i, slice) or isinstance(i, tuple): + raise IndexError("expected integer report index") + if (i < 0) or (i >= len(self)): + raise IndexError("index out of range") + return self._report_from_index(i) + + def __iter__(self): + count = len(self) + for i in xrange(0, count): + yield self._report_from_index(i) + + def __repr__(self): + return "<reports: %s>" % repr(list(self)) + + def append(self, report): + if report.view is None: + view = None + else: + view = report.view.handle + if isinstance(report, PlainTextReport): + core.BNAddPlainTextReportToCollection(self.handle, view, report.title, report.contents) + elif isinstance(report, MarkdownReport): + core.BNAddMarkdownReportToCollection(self.handle, view, report.title, report.contents, report.plaintext) + elif isinstance(report, HTMLReport): + core.BNAddHTMLReportToCollection(self.handle, view, report.title, report.contents, report.plaintext) + elif isinstance(report, FlowGraphReport): + core.BNAddGraphReportToCollection(self.handle, view, report.title, report.graph.handle) + else: + raise TypeError("expected report object") + + def markdown_to_html(contents): """ ``markdown_to_html`` converts the provided markdown to HTML. @@ -533,6 +676,34 @@ def show_html_report(title, contents, plaintext=""): core.BNShowHTMLReport(None, title, contents, plaintext) +def show_graph_report(title, graph): + """ + ``show_graph_report`` displays a flow graph in UI applications. + + Note: This API function will have no effect outside the UI. + + :param FlowGraph graph: Flow graph to display + :rtype: None + """ + func = graph.function + if func is None: + core.BNShowGraphReport(None, title, graph.handle) + else: + core.BNShowGraphReport(func.view.handle, title, graph.handle) + + +def show_report_collection(title, reports): + """ + ``show_report_collection`` displays mulitple reports in UI applications. + + Note: This API function will have no effect outside the UI. + + :param ReportCollection reports: Reports to display + :rtype: None + """ + core.BNShowReportCollection(title, reports.handle) + + def get_text_line_input(prompt, title): """ ``get_text_line_input`` prompts the user to input a string with the given prompt and title. diff --git a/python/lowlevelil.py b/python/lowlevelil.py index f7f8926c..3d330aa9 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -366,6 +366,7 @@ class LowLevelILInstruction(object): name, operand_type = operand if operand_type == "int": value = instr.operands[i] + value = (value & ((1 << 63) - 1)) - (value & (1 << 63)) elif operand_type == "float": if instr.size == 4: value = struct.unpack("f", struct.pack("I", instr.operands[i] & 0xffffffff))[0] @@ -734,9 +735,9 @@ class LowLevelILFunction(object): if handle is not None: self.handle = core.handle_of_type(handle, core.BNLowLevelILFunction) else: - func_handle = None - if self.source_function is not None: - func_handle = self.source_function.handle + if self.source_function is None: + raise ValueError("IL functions must be created with an associated function") + func_handle = self.source_function.handle self.handle = core.BNCreateLowLevelILFunction(arch.handle, func_handle) def __del__(self): @@ -2365,6 +2366,13 @@ class LowLevelILFunction(object): return None return result + def create_graph(self, settings = None): + if settings is not None: + settings_obj = settings.handle + else: + settings_obj = None + return binaryninja.flowgraph.CoreFlowGraph(core.BNCreateLowLevelILFunctionGraph(self.handle, settings_obj)) + class LowLevelILBasicBlock(basicblock.BasicBlock): def __init__(self, view, handle, owner): diff --git a/python/mainthread.py b/python/mainthread.py index 5b0cd53c..c63e3ff8 100644 --- a/python/mainthread.py +++ b/python/mainthread.py @@ -21,13 +21,14 @@ # Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja import scriptingprovider +from binaryninja import plugin def execute_on_main_thread(func): action = scriptingprovider._ThreadActionContext(func) obj = core.BNExecuteOnMainThread(0, action.callback) if obj: - return scriptingprovider.MainThreadAction(obj) + return plugin.MainThreadAction(obj) return None diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index a506767c..93c45dcc 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -22,6 +22,7 @@ import ctypes import struct # Binary Ninja components +import binaryninja from binaryninja import _binaryninjacore as core from binaryninja.enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence from binaryninja import basicblock #required for MediumLevelILBasicBlock argument @@ -129,6 +130,7 @@ class MediumLevelILInstruction(object): MediumLevelILOperation.MLIL_LOW_PART: [("src", "expr")], MediumLevelILOperation.MLIL_JUMP: [("dest", "expr")], MediumLevelILOperation.MLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")], + MediumLevelILOperation.MLIL_RET_HINT: [("dest", "expr")], MediumLevelILOperation.MLIL_CALL: [("output", "var_list"), ("dest", "expr"), ("params", "expr_list")], MediumLevelILOperation.MLIL_CALL_UNTYPED: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")], MediumLevelILOperation.MLIL_CALL_OUTPUT: [("dest", "var_list")], @@ -230,6 +232,7 @@ class MediumLevelILInstruction(object): name, operand_type = operand if operand_type == "int": value = instr.operands[i] + value = (value & ((1 << 63) - 1)) - (value & (1 << 63)) elif operand_type == "float": if instr.size == 4: value = struct.unpack("f", struct.pack("I", instr.operands[i] & 0xffffffff))[0] @@ -615,9 +618,9 @@ class MediumLevelILFunction(object): if handle is not None: self.handle = core.handle_of_type(handle, core.BNMediumLevelILFunction) else: - func_handle = None - if self.source_function is not None: - func_handle = self.source_function.handle + if self.source_function is None: + raise ValueError("IL functions must be created with an associated function") + func_handle = self.source_function.handle self.handle = core.BNCreateMediumLevelILFunction(arch.handle, func_handle) def __del__(self): @@ -938,6 +941,13 @@ class MediumLevelILFunction(object): return None return result + def create_graph(self, settings = None): + if settings is not None: + settings_obj = settings.handle + else: + settings_obj = None + return binaryninja.flowgraph.CoreFlowGraph(core.BNCreateMediumLevelILFunctionGraph(self.handle, settings_obj)) + class MediumLevelILBasicBlock(basicblock.BasicBlock): def __init__(self, view, handle, owner): diff --git a/python/types.py b/python/types.py index b78b7109..38d7b846 100644 --- a/python/types.py +++ b/python/types.py @@ -626,7 +626,7 @@ class Type(object): elif not isinstance(stack_adjust, SizeWithConfidence): stack_adjust = SizeWithConfidence(stack_adjust) - stack_adjust_conf = core.BNSizeWithConfidence() + stack_adjust_conf = core.BNOffsetWithConfidence() stack_adjust_conf.value = stack_adjust.value stack_adjust_conf.confidence = stack_adjust.confidence @@ -604,10 +604,10 @@ uint64_t Type::GetOffset() const } -Confidence<size_t> Type::GetStackAdjustment() const +Confidence<int64_t> Type::GetStackAdjustment() const { - BNSizeWithConfidence result = BNGetTypeStackAdjustment(m_object); - return Confidence<size_t>(result.value, result.confidence); + BNOffsetWithConfidence result = BNGetTypeStackAdjustment(m_object); + return Confidence<int64_t>(result.value, result.confidence); } @@ -823,7 +823,7 @@ Ref<Type> Type::ArrayType(const Confidence<Ref<Type>>& type, uint64_t elem) Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue, const Confidence<Ref<CallingConvention>>& callingConvention, const std::vector<FunctionParameter>& params, const Confidence<bool>& varArg, - const Confidence<size_t>& stackAdjust) + const Confidence<int64_t>& stackAdjust) { BNTypeWithConfidence returnValueConf; returnValueConf.type = returnValue->GetObject(); @@ -849,7 +849,7 @@ Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue, varArgConf.value = varArg.GetValue(); varArgConf.confidence = varArg.GetConfidence(); - BNSizeWithConfidence stackAdjustConf; + BNOffsetWithConfidence stackAdjustConf; stackAdjustConf.value = stackAdjust.GetValue(); stackAdjustConf.confidence = stackAdjust.GetConfidence(); |
