diff options
| author | Xusheng <xusheng@vector35.com> | 2020-11-16 17:51:46 +0800 |
|---|---|---|
| committer | Xusheng <xusheng@vector35.com> | 2021-02-17 12:05:47 +0800 |
| commit | d9b1df165f9daad6a5229718ecd0ee50a5ef6bf1 (patch) | |
| tree | 6307b8c16c80f8203bdb96ebc3d54a8d9f10b3bf | |
| parent | b651141704a555cf0b6c53152ab0f70d011ec8af (diff) | |
add support for type xref and variable xref
| -rw-r--r-- | architecture.cpp | 6 | ||||
| -rw-r--r-- | binaryninjaapi.h | 76 | ||||
| -rw-r--r-- | binaryninjacore.h | 86 | ||||
| -rw-r--r-- | binaryview.cpp | 222 | ||||
| -rw-r--r-- | docs/about/open-source.md | 5 | ||||
| -rw-r--r-- | function.cpp | 198 | ||||
| -rw-r--r-- | highlevelil.cpp | 7 | ||||
| -rw-r--r-- | python/binaryview.py | 252 | ||||
| -rw-r--r-- | python/function.py | 459 | ||||
| -rw-r--r-- | python/types.py | 84 | ||||
| m--------- | suite/binaries | 0 | ||||
| -rwxr-xr-x | suite/generator.py | 26 | ||||
| -rw-r--r-- | suite/testcommon.py | 88 | ||||
| -rw-r--r-- | type.cpp | 32 | ||||
| -rw-r--r-- | ui/commands.h | 5 | ||||
| -rw-r--r-- | ui/flowgraphwidget.h | 4 | ||||
| -rw-r--r-- | ui/linearview.h | 4 | ||||
| -rw-r--r-- | ui/tokenizedtextview.h | 4 | ||||
| -rw-r--r-- | ui/typeview.h | 7 | ||||
| -rw-r--r-- | ui/viewframe.h | 43 | ||||
| -rw-r--r-- | ui/xreflist.h | 148 |
21 files changed, 1719 insertions, 37 deletions
diff --git a/architecture.cpp b/architecture.cpp index 7a3e44c4..f64c87d6 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -2253,6 +2253,12 @@ DisassemblyTextRenderer::DisassemblyTextRenderer(MediumLevelILFunction* func, Di } +DisassemblyTextRenderer::DisassemblyTextRenderer(HighLevelILFunction* func, DisassemblySettings* settings) +{ + m_object = BNCreateHighLevelILDisassemblyTextRenderer(func->GetObject(), settings ? settings->GetObject() : nullptr); +} + + DisassemblyTextRenderer::DisassemblyTextRenderer(BNDisassemblyTextRenderer* renderer) { m_object = renderer; diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 5be370c0..eac2f6b8 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1072,6 +1072,7 @@ __attribute__ ((format (printf, 1, 2))) virtual bool operator==(const NameList& other) const; virtual bool operator!=(const NameList& other) const; virtual bool operator<(const NameList& other) const; + virtual bool operator>(const NameList& other) const; virtual NameList operator+(const NameList& other) const; @@ -1166,6 +1167,26 @@ __attribute__ ((format (printf, 1, 2))) static Ref<Symbol> ImportedFunctionFromImportAddressSymbol(Symbol* sym, uint64_t addr); }; + // TODO: This describes how the xref source references the target + enum ReferenceType + { + UnspecifiedReferenceType = 0x0, + ReadReferenceType = 0x1, + WriteReferenceType = 0x2, + ExecuteReferenceType = 0x4, + + // A type is referenced by a data variable + DataVariableReferenceType = 0x8, + + // A type is referenced by another type + DirectTypeReferenceType = 0x10, + IndirectTypeReferenceType = 0x20, + }; + + // ReferenceSource describes code reference source; TypeReferenceSource describes type reference source. + // When we query references, code references return vector<ReferenceSource>, data references return vector<uint64_t>, + // type references return vector<TypeReferenceSource>. + struct ReferenceSource { Ref<Function> func; @@ -1173,6 +1194,22 @@ __attribute__ ((format (printf, 1, 2))) uint64_t addr; }; + struct ILReferenceSource + { + Ref<Function> func; + Ref<Architecture> arch; + uint64_t addr; + BNFunctionGraphType type; + size_t exprId; + }; + + struct TypeReferenceSource + { + QualifiedName name; + uint64_t offset; + BNTypeReferenceType type; + }; + struct InstructionTextToken { enum @@ -1573,6 +1610,7 @@ __attribute__ ((format (printf, 1, 2))) Ref<Function> GetAnalysisFunction(Platform* platform, uint64_t addr); Ref<Function> GetRecentAnalysisFunctionForAddress(uint64_t addr); std::vector<Ref<Function>> GetAnalysisFunctionsForAddress(uint64_t addr); + std::vector<Ref<Function>> GetAnalysisFunctionsContainingAddress(uint64_t addr); Ref<Function> GetAnalysisEntryPoint(); Ref<BasicBlock> GetRecentBasicBlockForAddress(uint64_t addr); @@ -1591,6 +1629,21 @@ __attribute__ ((format (printf, 1, 2))) void AddUserDataReference(uint64_t fromAddr, uint64_t toAddr); void RemoveUserDataReference(uint64_t fromAddr, uint64_t toAddr); + // References to type + std::vector<ReferenceSource> GetCodeReferencesForType(const QualifiedName& type); + std::vector<uint64_t> GetDataReferencesForType(const QualifiedName& type); + std::vector<TypeReferenceSource> GetTypeReferencesForType(const QualifiedName& type); + + // References to type field + std::vector<ReferenceSource> GetCodeReferencesForTypeField(const QualifiedName& type, uint64_t offset); + std::vector<uint64_t> GetDataReferencesForTypeField(const QualifiedName& type, uint64_t offset); + std::vector<TypeReferenceSource> GetTypeReferencesForTypeField(const QualifiedName& type, uint64_t offset); + + std::vector<TypeReferenceSource> GetCodeReferencesForTypeFrom(ReferenceSource src); + std::vector<TypeReferenceSource> GetCodeReferencesForTypeFrom(ReferenceSource src, uint64_t len); + std::vector<TypeReferenceSource> GetCodeReferencesForTypeFieldFrom(ReferenceSource src); + std::vector<TypeReferenceSource> GetCodeReferencesForTypeFieldFrom(ReferenceSource src, uint64_t len); + std::vector<uint64_t> GetCallees(ReferenceSource addr); std::vector<ReferenceSource> GetCallers(uint64_t addr); @@ -2492,6 +2545,12 @@ __attribute__ ((format (printf, 1, 2))) static Variable FromIdentifier(uint64_t id); }; + struct VariableReferenceSource + { + Variable var; + ILReferenceSource source; + }; + struct FunctionParameter { std::string name; @@ -2610,6 +2669,9 @@ __attribute__ ((format (printf, 1, 2))) Ref<Type> WithReplacedStructure(Structure* from, Structure* to); Ref<Type> WithReplacedEnumeration(Enumeration* from, Enumeration* to); Ref<Type> WithReplacedNamedTypeReference(NamedTypeReference* from, NamedTypeReference* to); + + bool AddTypeMemberTokens(BinaryView* data, std::vector<InstructionTextToken>& tokens, int64_t offset, + std::vector<std::string>& nameList, size_t size = 0, bool indirect = false); }; class TypeBuilder @@ -3043,6 +3105,10 @@ __attribute__ ((format (printf, 1, 2))) void AddUserCodeReference(Architecture* fromArch, uint64_t fromAddr, uint64_t toAddr); void RemoveUserCodeReference(Architecture* fromArch, uint64_t fromAddr, uint64_t toAddr); + void AddUserTypeReference(Architecture* fromArch, uint64_t fromAddr, const QualifiedName& name); + void RemoveUserTypeReference(Architecture* fromArch, uint64_t fromAddr, const QualifiedName& name); + void AddUserTypeFieldReference(Architecture* fromArch, uint64_t fromAddr, const QualifiedName& name, uint64_t offset); + void RemoveUserTypeFieldReference(Architecture* fromArch, uint64_t fromAddr, const QualifiedName& name, uint64_t offset); Ref<LowLevelILFunction> GetLowLevelIL() const; Ref<LowLevelILFunction> GetLowLevelILIfAvailable() const; @@ -3060,6 +3126,14 @@ __attribute__ ((format (printf, 1, 2))) std::vector<StackVariableReference> GetStackVariablesReferencedByInstruction(Architecture* arch, uint64_t addr); std::vector<BNConstantReference> GetConstantsReferencedByInstruction(Architecture* arch, uint64_t addr); + std::vector<ILReferenceSource> GetMediumLevelILVariableReferences(const Variable& var); + std::vector<VariableReferenceSource> GetMediumLevelILVariableReferencesFrom(Architecture* arch, uint64_t addr); + std::vector<VariableReferenceSource> GetMediumLevelILVariableReferencesInRange(Architecture* arch, uint64_t addr, uint64_t len); + + std::vector<ILReferenceSource> GetHighLevelILVariableReferences(const Variable& var); + std::vector<VariableReferenceSource> GetHighLevelILVariableReferencesFrom(Architecture* arch, uint64_t addr); + std::vector<VariableReferenceSource> GetHighLevelILVariableReferencesInRange(Architecture* arch, uint64_t addr, uint64_t len); + Ref<LowLevelILFunction> GetLiftedIL() const; Ref<LowLevelILFunction> GetLiftedILIfAvailable() const; size_t GetLiftedILForInstruction(Architecture* arch, uint64_t addr); @@ -4379,6 +4453,7 @@ __attribute__ ((format (printf, 1, 2))) std::vector<DisassemblyTextLine> GetExprText(ExprId expr, bool asFullAst = true); std::vector<DisassemblyTextLine> GetExprText(const HighLevelILInstruction& instr, bool asFullAst = true); + std::vector<DisassemblyTextLine> GetInstructionText(size_t i, bool asFullAst = true); Confidence<Ref<Type>> GetExprType(size_t expr); Confidence<Ref<Type>> GetExprType(const HighLevelILInstruction& expr); @@ -5309,6 +5384,7 @@ __attribute__ ((format (printf, 1, 2))) DisassemblyTextRenderer(Function* func, DisassemblySettings* settings = nullptr); DisassemblyTextRenderer(LowLevelILFunction* func, DisassemblySettings* settings = nullptr); DisassemblyTextRenderer(MediumLevelILFunction* func, DisassemblySettings* settings = nullptr); + DisassemblyTextRenderer(HighLevelILFunction* func, DisassemblySettings* settings = nullptr); DisassemblyTextRenderer(BNDisassemblyTextRenderer* renderer); Ref<Function> GetFunction() const; diff --git a/binaryninjacore.h b/binaryninjacore.h index c64adc23..b6cefa1d 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1727,6 +1727,45 @@ extern "C" uint64_t addr; }; + struct BNILReferenceSource + { + BNFunction* func; + BNArchitecture* arch; + uint64_t addr; + BNFunctionGraphType type; + size_t exprId; + }; + + struct BNVariableReferenceSource + { + BNVariable var; + BNILReferenceSource source; + }; + + struct BNTypeField + { + BNQualifiedName name; + uint64_t offset; + }; + + // This describes how a type is referenced + enum BNTypeReferenceType + { + // Type A contains type B + DirectTypeReferenceType, + // All other cases, e.g., type A contains a pointer to type B + IndirectTypeReferenceType, + // The nature of the reference is unknown + UnknownTypeReferenceType + }; + + struct BNTypeReferenceSource + { + BNQualifiedName name; + uint64_t offset; + BNTypeReferenceType type; + }; + enum BNTagTypeType { UserTagType, @@ -3071,6 +3110,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNFunction* BNGetAnalysisFunction(BNBinaryView* view, BNPlatform* platform, uint64_t addr); BINARYNINJACOREAPI BNFunction* BNGetRecentAnalysisFunctionForAddress(BNBinaryView* view, uint64_t addr); BINARYNINJACOREAPI BNFunction** BNGetAnalysisFunctionsForAddress(BNBinaryView* view, uint64_t addr, size_t* count); + BINARYNINJACOREAPI BNFunction** BNGetAnalysisFunctionsContainingAddress(BNBinaryView* view, uint64_t addr, size_t* count); BINARYNINJACOREAPI BNFunction* BNGetAnalysisEntryPoint(BNBinaryView* view); BINARYNINJACOREAPI char* BNGetGlobalCommentForAddress(BNBinaryView* view, uint64_t addr); @@ -3097,6 +3137,13 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI void BNAddUserCodeReference(BNFunction* func, BNArchitecture* fromArch, uint64_t fromAddr, uint64_t toAddr); BINARYNINJACOREAPI void BNRemoveUserCodeReference(BNFunction* func, BNArchitecture* fromArch, uint64_t fromAddr, uint64_t toAddr); + BINARYNINJACOREAPI void BNAddUserTypeReference(BNFunction* func, BNArchitecture* fromArch, uint64_t fromAddr, BNQualifiedName* name); + BINARYNINJACOREAPI void BNRemoveUserTypeReference(BNFunction* func, BNArchitecture* fromArch, uint64_t fromAddr, BNQualifiedName* name); + BINARYNINJACOREAPI void BNAddUserTypeFieldReference(BNFunction* func, BNArchitecture* fromArch, uint64_t fromAddr, + BNQualifiedName* name, uint64_t offset); + BINARYNINJACOREAPI void BNRemoveUserTypeFieldReference(BNFunction* func, BNArchitecture* fromArch, uint64_t fromAddr, + BNQualifiedName* name, uint64_t offset); + BINARYNINJACOREAPI BNBasicBlock* BNNewBasicBlockReference(BNBasicBlock* block); BINARYNINJACOREAPI void BNFreeBasicBlock(BNBasicBlock* block); BINARYNINJACOREAPI BNBasicBlock** BNGetFunctionBasicBlockList(BNFunction* func, size_t* count); @@ -3275,6 +3322,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNReferenceSource* BNGetCodeReferencesInRange(BNBinaryView* view, uint64_t addr, uint64_t len, size_t* count); BINARYNINJACOREAPI void BNFreeCodeReferences(BNReferenceSource* refs, size_t count); + BINARYNINJACOREAPI void BNFreeILReferences(BNILReferenceSource* refs, size_t count); BINARYNINJACOREAPI uint64_t* BNGetCodeReferencesFrom(BNBinaryView* view, BNReferenceSource* src, size_t* count); BINARYNINJACOREAPI uint64_t* BNGetCodeReferencesFromInRange(BNBinaryView* view, BNReferenceSource* src, uint64_t len, size_t* count); @@ -3286,6 +3334,26 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI void BNRemoveUserDataReference(BNBinaryView* view, uint64_t fromAddr, uint64_t toAddr); BINARYNINJACOREAPI void BNFreeDataReferences(uint64_t* refs); + BINARYNINJACOREAPI void BNFreeTypeReferences(BNTypeReferenceSource* refs, size_t count); + + // References to type + BINARYNINJACOREAPI BNReferenceSource* BNGetCodeReferencesForType(BNBinaryView* view, BNQualifiedName* type, size_t* count); + BINARYNINJACOREAPI uint64_t* BNGetDataReferencesForType(BNBinaryView* view, BNQualifiedName* type, size_t* count); + BINARYNINJACOREAPI BNTypeReferenceSource* BNGetTypeReferencesForType(BNBinaryView* view, BNQualifiedName* type, size_t* count); + + // References to type field + BINARYNINJACOREAPI BNReferenceSource* BNGetCodeReferencesForTypeField(BNBinaryView* view, + BNQualifiedName* type, uint64_t offset, size_t* count); + BINARYNINJACOREAPI uint64_t* BNGetDataReferencesForTypeField(BNBinaryView* view, + BNQualifiedName* type, uint64_t offset, size_t* count); + BINARYNINJACOREAPI BNTypeReferenceSource* BNGetTypeReferencesForTypeField(BNBinaryView* view, + BNQualifiedName* type, uint64_t offset, size_t* count); + + BINARYNINJACOREAPI BNTypeReferenceSource* BNGetCodeReferencesForTypeFrom(BNBinaryView* view, BNReferenceSource* addr, size_t* count); + BINARYNINJACOREAPI BNTypeReferenceSource* BNGetCodeReferencesForTypeFromInRange(BNBinaryView* view, BNReferenceSource* addr, uint64_t len, size_t* count); + BINARYNINJACOREAPI BNTypeReferenceSource* BNGetCodeReferencesForTypeFieldsFrom(BNBinaryView* view, BNReferenceSource* addr, size_t* count); + BINARYNINJACOREAPI BNTypeReferenceSource* BNGetCodeReferencesForTypeFieldsFromInRange(BNBinaryView* view, BNReferenceSource* addr, uint64_t len, size_t* count); + BINARYNINJACOREAPI void BNRegisterGlobalFunctionRecognizer(BNFunctionRecognizer* rec); BINARYNINJACOREAPI bool BNGetStringAtAddress(BNBinaryView* view, uint64_t addr, BNStringReference* strRef); @@ -3621,6 +3689,21 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI void BNRequestFunctionDebugReport(BNFunction* func, const char* name); + BINARYNINJACOREAPI BNILReferenceSource* BNGetMediumLevelILVariableReferences(BNFunction* func, BNVariable* var, size_t * count); + BINARYNINJACOREAPI BNVariableReferenceSource* BNGetMediumLevelILVariableReferencesFrom(BNFunction* func, BNArchitecture* arch, + uint64_t address, size_t* count); + BINARYNINJACOREAPI BNVariableReferenceSource* BNGetMediumLevelILVariableReferencesInRange(BNFunction* func, BNArchitecture* arch, + uint64_t address, uint64_t len, size_t* count); + + BINARYNINJACOREAPI BNILReferenceSource* BNGetHighLevelILVariableReferences(BNFunction* func, BNVariable* var, size_t * count); + BINARYNINJACOREAPI BNVariableReferenceSource* BNGetHighLevelILVariableReferencesFrom(BNFunction* func, BNArchitecture* arch, + uint64_t address, size_t* count); + BINARYNINJACOREAPI BNVariableReferenceSource* BNGetHighLevelILVariableReferencesInRange(BNFunction* func, BNArchitecture* arch, + uint64_t address, uint64_t len, size_t* count); + + BINARYNINJACOREAPI void BNFreeVariableList(BNVariable* vars); + BINARYNINJACOREAPI void BNFreeVariableReferenceSourceList(BNVariableReferenceSource* vars, size_t count); + // Disassembly settings BINARYNINJACOREAPI BNDisassemblySettings* BNCreateDisassemblySettings(void); BINARYNINJACOREAPI BNDisassemblySettings* BNNewDisassemblySettingsReference(BNDisassemblySettings* settings); @@ -4247,6 +4330,9 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNType* BNTypeWithReplacedEnumeration(BNType* type, BNEnumeration* from, BNEnumeration* to); BINARYNINJACOREAPI BNType* BNTypeWithReplacedNamedTypeReference(BNType* type, BNNamedTypeReference* from, BNNamedTypeReference* to); + BINARYNINJACOREAPI bool BNAddTypeMemberTokens(BNType* type, BNBinaryView* data, BNInstructionTextToken** tokens, size_t* tokenCount, + int64_t offset, char*** nameList, size_t* nameCount, size_t size, bool indirect); + BINARYNINJACOREAPI BNQualifiedName BNTypeBuilderGetTypeName(BNTypeBuilder* nt); BINARYNINJACOREAPI void BNTypeBuilderSetTypeName(BNTypeBuilder* type, BNQualifiedName* name); BINARYNINJACOREAPI BNTypeClass BNGetTypeBuilderClass(BNTypeBuilder* type); diff --git a/binaryview.cpp b/binaryview.cpp index d6417352..86878f8c 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1683,6 +1683,21 @@ vector<Ref<Function>> BinaryView::GetAnalysisFunctionsForAddress(uint64_t addr) } +vector<Ref<Function>> BinaryView::GetAnalysisFunctionsContainingAddress(uint64_t addr) +{ + size_t count; + BNFunction** list = BNGetAnalysisFunctionsContainingAddress(m_object, addr, &count); + + vector<Ref<Function>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new Function(BNNewFunctionReference(list[i]))); + + BNFreeFunctionList(list, count); + return result; +} + + Ref<Function> BinaryView::GetAnalysisEntryPoint() { BNFunction* func = BNGetAnalysisEntryPoint(m_object); @@ -1847,6 +1862,213 @@ void BinaryView::RemoveUserDataReference(uint64_t fromAddr, uint64_t toAddr) } +vector<ReferenceSource> BinaryView::GetCodeReferencesForType(const QualifiedName& type) +{ + size_t count; + + BNQualifiedName nameObj = type.GetAPIObject(); + BNReferenceSource* refs = BNGetCodeReferencesForType(m_object, &nameObj, &count); + QualifiedName::FreeAPIObject(&nameObj); + + vector<ReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + ReferenceSource src; + src.func = new Function(BNNewFunctionReference(refs[i].func)); + src.arch = new CoreArchitecture(refs[i].arch); + src.addr = refs[i].addr; + result.push_back(src); + } + + BNFreeCodeReferences(refs, count); + return result; +} + + +vector<uint64_t> BinaryView::GetDataReferencesForType(const QualifiedName& type) +{ + size_t count; + BNQualifiedName nameObj = type.GetAPIObject(); + uint64_t* refs = BNGetDataReferencesForType(m_object, &nameObj, &count); + QualifiedName::FreeAPIObject(&nameObj); + + vector<uint64_t> result(refs, &refs[count]); + BNFreeDataReferences(refs); + return result; +} + + +vector<TypeReferenceSource> BinaryView::GetTypeReferencesForType(const QualifiedName& type) +{ + size_t count; + + BNQualifiedName nameObj = type.GetAPIObject(); + BNTypeReferenceSource* refs = BNGetTypeReferencesForType(m_object, &nameObj, &count); + QualifiedName::FreeAPIObject(&nameObj); + + vector<TypeReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + TypeReferenceSource src; + src.name = QualifiedName::FromAPIObject(&refs[i].name); + src.offset = refs[i].offset; + src.type = refs[i].type; + result.push_back(src); + } + + BNFreeTypeReferences(refs, count); + return result; +} + + +vector<ReferenceSource> BinaryView::GetCodeReferencesForTypeField(const QualifiedName& type, uint64_t offset) +{ + size_t count; + BNQualifiedName nameObj = type.GetAPIObject(); + BNReferenceSource* refs = BNGetCodeReferencesForTypeField(m_object, &nameObj, offset, &count); + QualifiedName::FreeAPIObject(&nameObj); + + vector<ReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + ReferenceSource src; + src.func = new Function(BNNewFunctionReference(refs[i].func)); + src.arch = new CoreArchitecture(refs[i].arch); + src.addr = refs[i].addr; + result.push_back(src); + } + + BNFreeCodeReferences(refs, count); + return result; +} + + +vector<uint64_t> BinaryView::GetDataReferencesForTypeField(const QualifiedName& type, uint64_t offset) +{ + size_t count; + BNQualifiedName nameObj = type.GetAPIObject(); + uint64_t* refs = BNGetDataReferencesForTypeField(m_object, &nameObj, offset, &count); + QualifiedName::FreeAPIObject(&nameObj); + + vector<uint64_t> result(refs, &refs[count]); + BNFreeDataReferences(refs); + return result; +} + + +vector<TypeReferenceSource> BinaryView::GetTypeReferencesForTypeField(const QualifiedName& type, uint64_t offset) +{ + size_t count; + BNQualifiedName nameObj = type.GetAPIObject(); + BNTypeReferenceSource* refs = BNGetTypeReferencesForTypeField(m_object, &nameObj, offset, &count); + QualifiedName::FreeAPIObject(&nameObj); + + vector<TypeReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + TypeReferenceSource src; + src.name = QualifiedName::FromAPIObject(&refs[i].name); + src.offset = refs[i].offset; + src.type = refs[i].type; + result.push_back(src); + } + + BNFreeTypeReferences(refs, count); + return result; +} + + +vector<TypeReferenceSource> BinaryView::GetCodeReferencesForTypeFrom(ReferenceSource src) +{ + size_t count; + BNReferenceSource _src{ src.func->m_object, src.arch->m_object, src.addr }; + BNTypeReferenceSource* refs = BNGetCodeReferencesForTypeFrom(m_object, &_src, &count); + + vector<TypeReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + TypeReferenceSource src; + src.name = QualifiedName::FromAPIObject(&refs[i].name); + src.offset = refs[i].offset; + src.type = refs[i].type; + result.push_back(src); + } + + BNFreeTypeReferences(refs, count); + return result; +} + + +vector<TypeReferenceSource> BinaryView::GetCodeReferencesForTypeFrom(ReferenceSource src, uint64_t len) +{ + size_t count; + BNReferenceSource _src{ src.func->m_object, src.arch->m_object, src.addr }; + BNTypeReferenceSource* refs = BNGetCodeReferencesForTypeFromInRange(m_object, &_src, len, &count); + + vector<TypeReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + TypeReferenceSource src; + src.name = QualifiedName::FromAPIObject(&refs[i].name); + src.offset = refs[i].offset; + src.type = refs[i].type; + result.push_back(src); + } + + BNFreeTypeReferences(refs, count); + return result; +} + +vector<TypeReferenceSource> BinaryView::GetCodeReferencesForTypeFieldFrom(ReferenceSource src) +{ + size_t count; + BNReferenceSource _src{ src.func->m_object, src.arch->m_object, src.addr }; + BNTypeReferenceSource* refs = BNGetCodeReferencesForTypeFieldsFrom(m_object, &_src, &count); + + vector<TypeReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + TypeReferenceSource src; + src.name = QualifiedName::FromAPIObject(&refs[i].name); + src.offset = refs[i].offset; + src.type = refs[i].type; + result.push_back(src); + } + + BNFreeTypeReferences(refs, count); + return result; +} + + +vector<TypeReferenceSource> BinaryView::GetCodeReferencesForTypeFieldFrom(ReferenceSource src, uint64_t len) +{ + size_t count; + BNReferenceSource _src{ src.func->m_object, src.arch->m_object, src.addr }; + BNTypeReferenceSource* refs = BNGetCodeReferencesForTypeFieldsFromInRange(m_object, &_src, len, &count); + + vector<TypeReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + TypeReferenceSource src; + src.name = QualifiedName::FromAPIObject(&refs[i].name); + src.offset = refs[i].offset; + src.type = refs[i].type; + result.push_back(src); + } + + BNFreeTypeReferences(refs, count); + return result; +} + + vector<uint64_t> BinaryView::GetCallees(ReferenceSource callSite) { size_t count; diff --git a/docs/about/open-source.md b/docs/about/open-source.md index 0aaee432..d7e782bb 100644 --- a/docs/about/open-source.md +++ b/docs/about/open-source.md @@ -21,6 +21,7 @@ The previous tools are used in the generation of our documentation, but are not - [libxcb] ([libxcb license] - MIT) - [sourcecodepro] ([sourcecodepro license] - SIL open font license) - [rlcompleter] ([python license] - Python Software Foundation License 2) + - [QCheckboxCombo] ([QCheckboxCombo License] - MIT) * Core - [discount] ([discount license] - BSD) @@ -124,4 +125,6 @@ Please note that we offer no support for running Binary Ninja with modified Qt l [curl license]: https://github.com/curl/curl/blob/master/COPYING [curl]: https://github.com/curl/curl [nom license]: https://github.com/Geal/nom/blob/master/LICENSE -[nom]: https://github.com/Geal/nom
\ No newline at end of file +[nom]: https://github.com/Geal/nom +[QCheckboxCombo]: https://github.com/CuriousCrow/QCheckboxCombo +[QCheckboxCombo License]: https://github.com/CuriousCrow/QCheckboxCombo/blob/master/LICENSE
\ No newline at end of file diff --git a/function.cpp b/function.cpp index 50799191..b671f283 100644 --- a/function.cpp +++ b/function.cpp @@ -289,6 +289,34 @@ void Function::RemoveUserCodeReference(Architecture* fromArch, uint64_t fromAddr } +void Function::AddUserTypeReference(Architecture* fromArch, uint64_t fromAddr, const QualifiedName& name) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + BNAddUserTypeReference(m_object, fromArch->GetObject(), fromAddr, &nameObj); +} + + +void Function::RemoveUserTypeReference(Architecture* fromArch, uint64_t fromAddr, const QualifiedName& name) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + BNRemoveUserTypeReference(m_object, fromArch->GetObject(), fromAddr, &nameObj); +} + + +void Function::AddUserTypeFieldReference(Architecture* fromArch, uint64_t fromAddr, const QualifiedName& name, uint64_t offset) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + BNAddUserTypeFieldReference(m_object, fromArch->GetObject(), fromAddr, &nameObj, offset); +} + + +void Function::RemoveUserTypeFieldReference(Architecture* fromArch, uint64_t fromAddr, const QualifiedName& name, uint64_t offset) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + BNRemoveUserTypeFieldReference(m_object, fromArch->GetObject(), fromAddr, &nameObj, offset); +} + + Ref<LowLevelILFunction> Function::GetLowLevelIL() const { return new LowLevelILFunction(BNGetFunctionLowLevelIL(m_object)); @@ -1971,6 +1999,176 @@ void Function::SetVariableDeadStoreElimination(const Variable& var, BNDeadStoreE } +vector<ILReferenceSource> Function::GetMediumLevelILVariableReferences(const Variable& var) +{ + size_t count; + + BNVariable varData; + varData.type = var.type; + varData.index = var.index; + varData.storage = var.storage; + + BNILReferenceSource* refs = BNGetMediumLevelILVariableReferences(m_object, &varData, &count); + + vector<ILReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + ILReferenceSource src; + src.func = new Function(BNNewFunctionReference(refs[i].func)); + src.arch = new CoreArchitecture(refs[i].arch); + src.addr = refs[i].addr; + src.type = refs[i].type; + src.exprId = refs[i].exprId; + result.push_back(src); + } + + BNFreeILReferences(refs, count); + return result; +} + + +vector<VariableReferenceSource> Function::GetMediumLevelILVariableReferencesFrom(Architecture* arch, uint64_t addr) +{ + size_t count; + BNVariableReferenceSource* refs = BNGetMediumLevelILVariableReferencesFrom(m_object, arch->GetObject(), addr, &count); + + vector<VariableReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + VariableReferenceSource src; + src.var.index = refs[i].var.index; + src.var.storage = refs[i].var.storage; + src.var.type = refs[i].var.type; + + src.source.func = new Function(BNNewFunctionReference(refs[i].source.func)); + src.source.arch = new CoreArchitecture(refs[i].source.arch); + src.source.addr = refs[i].source.addr; + src.source.type = refs[i].source.type; + src.source.exprId = refs[i].source.exprId; + + result.push_back(src); + } + + BNFreeVariableReferenceSourceList(refs, count); + return result; +} + + +vector<VariableReferenceSource> Function::GetMediumLevelILVariableReferencesInRange(Architecture* arch, uint64_t addr, uint64_t len) +{ + size_t count; + BNVariableReferenceSource* refs = BNGetMediumLevelILVariableReferencesInRange(m_object, arch->GetObject(), addr, len, &count); + + vector<VariableReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + VariableReferenceSource src; + src.var.index = refs[i].var.index; + src.var.storage = refs[i].var.storage; + src.var.type = refs[i].var.type; + + src.source.func = new Function(BNNewFunctionReference(refs[i].source.func)); + src.source.arch = new CoreArchitecture(refs[i].source.arch); + src.source.addr = refs[i].source.addr; + src.source.type = refs[i].source.type; + src.source.exprId = refs[i].source.exprId; + + result.push_back(src); + } + + BNFreeVariableReferenceSourceList(refs, count); + return result; +} + + +vector<ILReferenceSource> Function::GetHighLevelILVariableReferences(const Variable& var) +{ + size_t count; + + BNVariable varData; + varData.type = var.type; + varData.index = var.index; + varData.storage = var.storage; + + BNILReferenceSource* refs = BNGetHighLevelILVariableReferences(m_object, &varData, &count); + + vector<ILReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + ILReferenceSource src; + src.func = new Function(BNNewFunctionReference(refs[i].func)); + src.arch = new CoreArchitecture(refs[i].arch); + src.addr = refs[i].addr; + src.type = refs[i].type; + src.exprId = refs[i].exprId; + result.push_back(src); + } + + BNFreeILReferences(refs, count); + return result; +} + + +vector<VariableReferenceSource> Function::GetHighLevelILVariableReferencesFrom(Architecture* arch, uint64_t addr) +{ + size_t count; + BNVariableReferenceSource* refs = BNGetHighLevelILVariableReferencesFrom(m_object, arch->GetObject(), addr, &count); + + vector<VariableReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + VariableReferenceSource src; + src.var.index = refs[i].var.index; + src.var.storage = refs[i].var.storage; + src.var.type = refs[i].var.type; + + src.source.func = new Function(BNNewFunctionReference(refs[i].source.func)); + src.source.arch = new CoreArchitecture(refs[i].source.arch); + src.source.addr = refs[i].source.addr; + src.source.type = refs[i].source.type; + src.source.exprId = refs[i].source.exprId; + + result.push_back(src); + } + + BNFreeVariableReferenceSourceList(refs, count); + return result; +} + + +vector<VariableReferenceSource> Function::GetHighLevelILVariableReferencesInRange(Architecture* arch, uint64_t addr, uint64_t len) +{ + size_t count; + BNVariableReferenceSource* refs = BNGetHighLevelILVariableReferencesInRange(m_object, arch->GetObject(), addr, len, &count); + + vector<VariableReferenceSource> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + VariableReferenceSource src; + src.var.index = refs[i].var.index; + src.var.storage = refs[i].var.storage; + src.var.type = refs[i].var.type; + + src.source.func = new Function(BNNewFunctionReference(refs[i].source.func)); + src.source.arch = new CoreArchitecture(refs[i].source.arch); + src.source.addr = refs[i].source.addr; + src.source.type = refs[i].source.type; + src.source.exprId = refs[i].source.exprId; + + result.push_back(src); + } + + BNFreeVariableReferenceSourceList(refs, count); + return result; +} + + AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(Function* func): m_func(func) { if (m_func) diff --git a/highlevelil.cpp b/highlevelil.cpp index 6c304d0e..a355c561 100644 --- a/highlevelil.cpp +++ b/highlevelil.cpp @@ -445,6 +445,13 @@ vector<DisassemblyTextLine> HighLevelILFunction::GetExprText(const HighLevelILIn } +vector<DisassemblyTextLine> HighLevelILFunction::GetInstructionText(size_t i, bool asFullAst) +{ + HighLevelILInstruction instr = GetInstruction(i); + return GetExprText(instr, asFullAst); +} + + Confidence<Ref<Type>> HighLevelILFunction::GetExprType(size_t expr) { BNTypeWithConfidence result = BNGetHighLevelILExprType(m_object, expr); diff --git a/python/binaryview.py b/python/binaryview.py index 193cf8b4..cbfc47ef 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -3207,18 +3207,21 @@ class BinaryView(object): return None return DataVariable(var.address, types.Type(var.type, platform = self.platform, confidence = var.typeConfidence), var.autoDiscovered, self) - def get_functions_containing(self, addr): + def get_functions_containing(self, addr, plat=None): """ ``get_functions_containing`` returns a list of functions which contain the given address. :param int addr: virtual address to query. :rtype: list of Function objects """ - basic_blocks = self.get_basic_blocks_at(addr) - + count = ctypes.c_ulonglong(0) + funcs = core.BNGetAnalysisFunctionsContainingAddress(self.handle, addr, count) result = [] - for block in basic_blocks: - result.append(block.function) + for i in range(0, count.value): + result.append(binaryninja.function.Function(self, core.BNNewFunctionReference(funcs[i]))) + core.BNFreeFunctionList(funcs, count.value) + if not plat is None: + result = [func for func in result in func.platform == plat] return result def get_function_at(self, addr, plat=None): @@ -3359,6 +3362,7 @@ class BinaryView(object): :param int addr: virtual address to query for references :param int length: optional length of query + :param Architecture arch: optional architecture of query :return: list of integers :rtype: list(integer) """ @@ -3439,6 +3443,242 @@ class BinaryView(object): return result + def get_code_refs_for_type(self, name): + """ + ``get_code_refs_for_type`` returns a list of ReferenceSource objects (xrefs or cross-references) that reference the provided QualifiedName. + + :param QualifiedName name: name of type to query for references + :return: List of References for the given type + :rtype: list(ReferenceSource) + :Example: + + >>> bv.get_code_refs_for_type('A') + [<ref: x86@0x4165ff>] + >>> + + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetCodeReferencesForType(self.handle, name, count) + + result = [] + for i in range(0, count.value): + if refs[i].func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch) + else: + arch = None + addr = refs[i].addr + result.append(binaryninja.architecture.ReferenceSource(func, arch, addr)) + core.BNFreeCodeReferences(refs, count.value) + return result + + + def get_code_refs_for_type_field(self, name, offset): + """ + ``get_code_refs_for_type`` returns a list of ReferenceSource objects (xrefs or cross-references) that reference the provided type field. + + :param QualifiedName name: name of type to query for references + :param int offset: offset of the field, relative to the type + :return: List of References for the given type + :rtype: list(ReferenceSource) + :Example: + + >>> bv.get_code_refs_for_type_field('A', 0x8) + [<ref: x86@0x4165ff>] + >>> + + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetCodeReferencesForTypeField(self.handle, name, offset, count) + + result = [] + for i in range(0, count.value): + if refs[i].func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch) + else: + arch = None + addr = refs[i].addr + result.append(binaryninja.architecture.ReferenceSource(func, arch, addr)) + core.BNFreeCodeReferences(refs, count.value) + return result + + + def get_data_refs_for_type(self, name): + """ + ``get_data_refs_for_type`` returns a list of virtual addresses of data which references the type ``name``. + Note, the returned addresses are the actual start of the queried type. For example, suppose there is a DataVariable + at 0x1000 that has type A, and type A contians type B at offset 0x10. Then `get_data_refs_for_type('B')` will + return 0x1010 for it. + + :param QualifiedName name: name of type to query for references + :return: list of integers + :rtype: list(integer) + :Example: + + >>> bv.get_data_refs_for_type('A') + [4203812] + >>> + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetDataReferencesForType(self.handle, name, count) + + result = [] + for i in range(0, count.value): + result.append(refs[i]) + core.BNFreeDataReferences(refs, count.value) + return result + + + def get_data_refs_for_type_field(self, name, offset): + """ + ``get_data_refs_for_type_field`` returns a list of virtual addresses of data which references the type ``name``. + Note, the returned addresses are the actual start of the queried type field. For example, suppose there is a + DataVariable at 0x1000 that has type A, and type A contians type B at offset 0x10. + Then `get_data_refs_for_type_field('B', 0x8)` will return 0x1018 for it. + + :param QualifiedName name: name of type to query for references + :param int offset: offset of the field, relative to the type + :return: list of integers + :rtype: list(integer) + :Example: + + >>> bv.get_data_refs_for_type_field('A', 0x8) + [4203812] + >>> + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetDataReferencesForTypeField(self.handle, name, offset, count) + + result = [] + for i in range(0, count.value): + result.append(refs[i]) + core.BNFreeDataReferences(refs, count.value) + return result + + + def get_type_refs_for_type(self, name): + """ + ``get_type_refs_for_type`` returns a list of TypeReferenceSource objects (xrefs or cross-references) that reference the provided QualifiedName. + + :param QualifiedName name: name of type to query for references + :return: List of references for the given type + :rtype: list(TypeReferenceSource) + :Example: + + >>> bv.get_type_refs_for_type('A') + ['<type D, offset 0x8, direct>', '<type C, offset 0x10, indirect>'] + >>> + + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetTypeReferencesForType(self.handle, name, count) + + result = [] + for i in range(0, count.value): + type_field = types.TypeReferenceSource(types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + result.append(type_field) + core.BNFreeTypeReferences(refs, count.value) + return result + + + def get_type_refs_for_type_field(self, name, offset): + """ + ``get_type_refs_for_type`` returns a list of TypeReferenceSource objects (xrefs or cross-references) that reference the provided type field. + + :param QualifiedName name: name of type to query for references + :param int offset: offset of the field, relative to the type + :return: List of references for the given type + :rtype: list(TypeReferenceSource) + :Example: + + >>> bv.get_type_refs_for_type_field('A', 0x8) + ['<type D, offset 0x8, direct>', '<type C, offset 0x10, indirect>'] + >>> + + """ + count = ctypes.c_ulonglong(0) + name = types.QualifiedName(name)._get_core_struct() + refs = core.BNGetTypeReferencesForTypeField(self.handle, name, offset, count) + + result = [] + for i in range(0, count.value): + type_field = types.TypeReferenceSource(types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + result.append(type_field) + core.BNFreeTypeReferences(refs, count.value) + return result + + def get_code_refs_for_type_from(self, addr, func = None, arch = None, length = None): + """ + ``get_code_refs_for_type_from`` returns a list of types referenced by code in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + all functions and containing the address will be returned. If no architecture is specified, the + architecture of the function will be used. + + :param int addr: virtual address to query for references + :param int length: optional length of query + :return: list of references + :rtype: list(TypeReferenceSource) + """ + result = [] + funcs = self.get_functions_containing(addr) if func is None else [func] + if not funcs: + return [] + for src_func in funcs: + src_arch = src_func.arch if arch is None else arch + ref_src = core.BNReferenceSource(src_func.handle, src_arch.handle, addr) + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetCodeReferencesForTypeFrom(self.handle, ref_src, count) + else: + refs = core.BNGetCodeReferencesForTypeFromInRange(self.handle, ref_src, length, count) + for i in range(0, count.value): + type_field = types.TypeReferenceSource(types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + result.append(type_field) + core.BNFreeTypeReferences(refs, count.value) + return result + + def get_code_refs_for_type_fields_from(self, addr, func = None, arch = None, length = None): + """ + ``get_code_refs_for_type_fields_from`` returns a list of type fields referenced by code in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + all functions and containing the address will be returned. If no architecture is specified, the + architecture of the function will be used. + + :param int addr: virtual address to query for references + :param int length: optional length of query + :return: list of references + :rtype: list(TypeReferenceSource) + """ + result = [] + funcs = self.get_functions_containing(addr) if func is None else [func] + if not funcs: + return [] + for src_func in funcs: + src_arch = src_func.arch if arch is None else arch + ref_src = core.BNReferenceSource(src_func.handle, src_arch.handle, addr) + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetCodeReferencesForTypeFieldsFrom(self.handle, ref_src, count) + else: + refs = core.BNGetCodeReferencesForTypeFieldsFromInRange(self.handle, ref_src, length, count) + for i in range(0, count.value): + type_field = types.TypeReferenceSource(types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + result.append(type_field) + core.BNFreeTypeReferences(refs, count.value) + return result + def add_user_data_ref(self, from_addr, to_addr): """ ``add_user_data_ref`` adds a user-specified data cross-reference (xref) from the address ``from_addr`` to the address ``to_addr``. @@ -5467,7 +5707,7 @@ class BinaryView(object): For annotating code, it is recommended to use comments attached to functions rather than address comments attached to the BinaryView. On the other hand, BinaryView comments can be attached to data whereas function comments cannot. - To create a function-level comment, use :func:`~binaryninja.function.Function.add_user_code_ref`. + To create a function-level comment, use :func:`~binaryninja.function.Function.set_comment_at`. """ count = ctypes.c_ulonglong() addrs = core.BNGetGlobalCommentedAddresses(self.handle, count) diff --git a/python/function.py b/python/function.py index 15bbf251..da6d66e2 100644 --- a/python/function.py +++ b/python/function.py @@ -1054,6 +1054,226 @@ class ParameterVariables(object): self._confidence = value +class ILReferenceSource(object): + def __init__(self, func, arch, addr, il_type, expr_id): + self._function = func + self._arch = arch + self._address = addr + self._il_type = il_type + self._expr_id = expr_id + + def get_il_name(self, il_type): + if il_type == FunctionGraphType.NormalFunctionGraph: + return 'disasmbly' + if il_type == FunctionGraphType.LowLevelILFunctionGraph: + return 'llil' + if il_type == FunctionGraphType.LiftedILFunctionGraph: + return 'lifted_llil' + if il_type == FunctionGraphType.LowLevelILSSAFormFunctionGraph: + return 'llil_ssa' + if il_type == FunctionGraphType.MediumLevelILFunctionGraph: + return 'mlil' + if il_type == FunctionGraphType.MediumLevelILSSAFormFunctionGraph: + return 'mlil_ssa' + if il_type == FunctionGraphType.MappedMediumLevelILFunctionGraph: + return 'mapped_mlil' + if il_type == FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph: + return 'mapped_mlil_ssa' + if il_type == FunctionGraphType.HighLevelILFunctionGraph: + return 'hlil' + if il_type == FunctionGraphType.HighLevelILSSAFormFunctionGraph: + return 'hlil_ssa' + + def __repr__(self): + if self._arch: + return "<ref: %s@%#x, %s@%d>" %\ + (self._arch.name, self._address, self.get_il_name(self._il_type), self.expr_id) + else: + return "<ref: %#x, %s@%d>" %\ + (self._address, self.get_il_name(self._il_type), self.expr_id) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self.function, self.arch, self.address, self.il_type, self.expr_id) ==\ + (other.address, other.function, other.arch, other.il_type, other.expr_id) + + def __ne__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return not (self == other) + + def __lt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.function < other.function: + return True + if self.function > other.function: + return False + if self.arch < other.arch: + return True + if self.arch > other.arch: + return False + if self.address < other.address: + return True + if self.address > other.address: + return False + if self.il_type < other.il_type: + return True + if self.il_type > other.il_type: + return False + return self.expr_id < other.expr_id + + def __gt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.function > other.function: + return True + if self.function < other.function: + return False + if self.arch > other.arch: + return True + if self.arch < other.arch: + return False + if self.address > other.address: + return True + if self.address < other.address: + return False + if self.il_type > other.il_type: + return True + if self.il_type < other.il_type: + return False + return self.expr_id > other.expr_id + + def __ge__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self == other) or (self > other) + + def __le__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self == other) or (self < other) + + def __hash__(self): + return hash((self._function, self._arch, self._address, self._il_type, self._expr_id)) + + @property + def function(self): + """ """ + return self._function + + @function.setter + def function(self, value): + self._function = value + + @property + def arch(self): + """ """ + return self._arch + + @arch.setter + def arch(self, value): + self._arch = value + + @property + def address(self): + """ """ + return self._address + + @address.setter + def address(self, value): + self._address = value + + @property + def il_type(self): + """ """ + return self._il_type + + @il_type.setter + def il_type(self, value): + self._il_type = value + + @property + def expr_id(self): + """ """ + return self._expr_id + + @expr_id.setter + def expr_id(self, value): + self._expr_id = value + + +class VariableReferenceSource(object): + def __init__(self, var, src): + self._var = var + self._src = src + + def __repr__(self): + return "<var: %s, src: %s>" % (repr(self._var), repr(self._src)) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self.var == other.var) and (self.src == other.src) + + def __ne__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return not (self == other) + + def __lt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.var < other.var: + return True + if self.var > other.var: + return False + return self.src < other.src + + def __gt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.var > other.var: + return True + if self.var < other.var: + return False + return self.src > other.src + + def __ge__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.var >= other.var: + return True + if self.var < other.var: + return False + return self.src >= other.src + + def __le__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + if self.var <= other.var: + return True + if self.var > other.var: + return False + return self.src <= other.src + + @property + def var(self): + return self._var + @var.setter + def var(self, value): + self._var = value + + @property + def src(self): + return self._src + + @src.setter + def src(self, value): + self._src = value + + class _FunctionAssociatedDataStore(associateddatastore._AssociatedDataStore): _defaults = {} @@ -2033,6 +2253,98 @@ class Function(object): core.BNRemoveUserCodeReference(self.handle, from_arch.handle, from_addr, to_addr) + def add_user_type_ref(self, from_addr, name, from_arch=None): + """ + ``add_user_type_ref`` places a user-defined type cross-reference from the instruction at + the given address and architecture to the specified type. If the specified + source instruction is not contained within this function, no action is performed. + To remove the reference, use :func:`remove_user_type_ref`. + + :param int from_addr: virtual address of the source instruction + :param QualifiedName name: name of the referenced type + :param Architecture from_arch: (optional) architecture of the source instruction + :rtype: None + :Example: + + >>> current_function.add_user_code_ref(here, 'A') + + """ + + if from_arch is None: + from_arch = self.arch + + name = types.QualifiedName(name)._get_core_struct() + core.BNAddUserTypeReference(self.handle, from_arch.handle, from_addr, name) + + def remove_user_type_ref(self, from_addr, name, from_arch=None): + """ + ``remove_user_type_ref`` removes a user-defined type cross-reference. + If the given address is not contained within this function, or if there is no + such user-defined cross-reference, no action is performed. + + :param int from_addr: virtual address of the source instruction + :param QualifiedName name: name of the referenced type + :param Architecture from_arch: (optional) architecture of the source instruction + :rtype: None + :Example: + + >>> current_function.remove_user_type_ref(here, 'A') + + """ + + if from_arch is None: + from_arch = self.arch + + name = types.QualifiedName(name)._get_core_struct() + core.BNRemoveUserTypeReference(self.handle, from_arch.handle, from_addr, name) + + def add_user_type_field_ref(self, from_addr, name, offset, from_arch=None): + """ + ``add_user_type_field_ref`` places a user-defined type field cross-reference from the + instruction at the given address and architecture to the specified type. If the specified + source instruction is not contained within this function, no action is performed. + To remove the reference, use :func:`remove_user_type_field_ref`. + + :param int from_addr: virtual address of the source instruction + :param QualifiedName name: name of the referenced type + :param int offset: offset of the field, relative to the type + :param Architecture from_arch: (optional) architecture of the source instruction + :rtype: None + :Example: + + >>> current_function.add_user_type_field_ref(here, 'A'. 0x8) + + """ + + if from_arch is None: + from_arch = self.arch + + name = types.QualifiedName(name)._get_core_struct() + core.BNAddUserTypeFieldReference(self.handle, from_arch.handle, from_addr, name, offset) + + def remove_user_type_field_ref(self, from_addr, name, offset, from_arch=None): + """ + ``remove_user_type_field_ref`` removes a user-defined type field cross-reference. + If the given address is not contained within this function, or if there is no + such user-defined cross-reference, no action is performed. + + :param int from_addr: virtual address of the source instruction + :param QualifiedName name: name of the referenced type + :param int offset: offset of the field, relative to the type + :param Architecture from_arch: (optional) architecture of the source instruction + :rtype: None + :Example: + + >>> current_function.remove_user_type_field_ref(here, 'A', 0x8) + + """ + + if from_arch is None: + from_arch = self.arch + + name = types.QualifiedName(name)._get_core_struct() + core.BNRemoveUserTypeFieldReference(self.handle, from_arch.handle, from_addr, name, offset) + def get_low_level_il_at(self, addr, arch=None): """ ``get_low_level_il_at`` gets the LowLevelILInstruction corresponding to the given virtual address @@ -2974,6 +3286,153 @@ class Function(object): functions.append(ref.function) return functions + def get_mlil_var_refs(self, var): + """ + ``get_mlil_var_refs`` returns a list of ILReferenceSource objects (IL xrefs or cross-references) + that reference the given variable. The variable is a local variable that can be either on the stack, + in a register, or in a flag. + This function is related to get_hlil_var_refs(), which returns variable references collected + from HLIL. The two can be different in several cases, e.g., multiple variables in MLIL can be merged + into a single variable in HLIL. + + :param Variable var: Variable for which to query the xref + :return: List of IL References for the given variable + :rtype: list(ILReferenceSource) + :Example: + + >>> var = current_mlil[0].operands[0] + >>> current_function.get_mlil_var_refs(var) + """ + count = ctypes.c_ulonglong(0) + var_data = core.BNVariable() + var_data.type = var.source_type + var_data.index = var.index + var_data.storage = var.storage + refs = core.BNGetMediumLevelILVariableReferences(self.handle, var_data, count) + result = [] + for i in range(0, count.value): + if refs[i].func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch) + else: + arch = None + + result.append(binaryninja.ILReferenceSource( + func, arch, refs[i].addr, refs[i].type, refs[i].exprId)) + core.BNFreeILReferences(refs, count.value) + return result + + def get_mlil_var_refs_from(self, addr, length = None, arch = None): + """ + ``get_mlil_var_refs_from`` returns a list of variables referenced by code in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + all functions and containing the address will be returned. If no architecture is specified, the + architecture of the function will be used. + This function is related to get_hlil_var_refs_from(), which returns variable references collected + from HLIL. The two can be different in several cases, e.g., multiple variables in MLIL can be merged + into a single variable in HLIL. + + :param int addr: virtual address to query for variable references + :param int length: optional length of query + :param Architecture arch: optional architecture of query + :return: list of variable reference sources + :rtype: list(VariableReferenceSource) + """ + result = [] + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetMediumLevelILVariableReferencesFrom(self.handle, self.arch.handle, addr, count) + else: + refs = core.BNGetMediumLevelILVariableReferencesInRange(self.handle, self.arch.handle, addr, length, count) + for i in range(0, count.value): + var = Variable(self, refs[i].var.type, refs[i].var.index, refs[i].var.storage) + if refs[i].source.func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].source.func)) + else: + func = None + if refs[i].source.arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].source.arch) + else: + arch = None + + src = ILReferenceSource(func, arch, refs[i].source.addr, refs[i].source.type, refs[i].source.exprId) + result.append(VariableReferenceSource(var, src)) + core.BNFreeVariableReferenceSourceList(refs, count.value) + return result + + def get_hlil_var_refs(self, var): + """ + ``get_hlil_var_refs`` returns a list of ILReferenceSource objects (IL xrefs or cross-references) + that reference the given variable. The variable is a local variable that can be either on the stack, + in a register, or in a flag. + + :param Variable var: Variable for which to query the xref + :return: List of IL References for the given variable + :rtype: list(ILReferenceSource) + :Example: + + >>> var = current_hlil[0].operands[0] + >>> current_function.get_hlil_var_refs(var) + """ + count = ctypes.c_ulonglong(0) + var_data = core.BNVariable() + var_data.type = var.source_type + var_data.index = var.index + var_data.storage = var.storage + refs = core.BNGetHighLevelILVariableReferences(self.handle, var_data, count) + result = [] + for i in range(0, count.value): + if refs[i].func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].arch) + else: + arch = None + result.append(binaryninja.ILReferenceSource( + func, arch, refs[i].addr, refs[i].type, refs[i].exprId)) + core.BNFreeILReferences(refs, count.value) + return result + + def get_hlil_var_refs_from(self, addr, length = None, arch = None): + """ + ``get_hlil_var_refs_from`` returns a list of variables referenced by code in the function ``func``, + of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + all functions and containing the address will be returned. If no architecture is specified, the + architecture of the function will be used. + + :param int addr: virtual address to query for variable references + :param int length: optional length of query + :param Architecture arch: optional architecture of query + :return: list of variables reference sources + :rtype: list(VariableReferenceSource) + """ + result = [] + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetHighLevelILVariableReferencesFrom(self.handle, self.arch.handle, addr, count) + else: + refs = core.BNGetHighLevelILVariableReferencesInRange(self.handle, self.arch.handle, addr, length, count) + for i in range(0, count.value): + var = Variable(self, refs[i].var.type, refs[i].var.index, refs[i].var.storage) + if refs[i].source.func: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(refs[i].source.func)) + else: + func = None + if refs[i].source.arch: + arch = binaryninja.architecture.CoreArchitecture._from_cache(refs[i].source.arch) + else: + arch = None + + src = ILReferenceSource(func, arch, refs[i].source.addr, refs[i].source.type, refs[i].source.exprId) + result.append(VariableReferenceSource(var, src)) + core.BNFreeVariableReferenceSourceList(refs, count.value) + return result + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): diff --git a/python/types.py b/python/types.py index 7d59261d..e6ab5c2b 100644 --- a/python/types.py +++ b/python/types.py @@ -26,7 +26,7 @@ import ctypes # Binary Ninja components import binaryninja from binaryninja import _binaryninjacore as core -from binaryninja.enums import SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType +from binaryninja.enums import SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType, TypeReferenceType # 2-3 compatibility from binaryninja import range @@ -146,6 +146,88 @@ class QualifiedName(object): self._byte_name = value +class TypeReferenceSource(object): + def __init__(self, name, offset, ref_type): + self._name = name + self._offset = offset + self._ref_type = ref_type + + def __str__(self): + if self.ref_type == TypeReferenceType.DirectTypeReferenceType: + s = 'direct' + elif self.ref_type == TypeReferenceType.IndirectTypeReferenceType: + s = 'indirect' + else: + s = 'unknown' + return '<type %s, offset 0x%x, %s>' % (self.name, self.offset, s) + + def __repr__(self): + return repr(str(self)) + + @property + def name(self): + """ """ + return self._name + + @property + def offset(self): + """ """ + return self._offset + + @property + def ref_type(self): + """ """ + return self._ref_type + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.name == other.name and self.offset == other.offset and self.ref_type == other.ref_type + return NotImplemented + + def __ne__(self, other): + if isinstance(other, self.__class__): + return not self.__eq__(other) + return NotImplemented + + def __lt__(self, other): + if isinstance(other, self.__class__): + if self.name < other.name: + return True + elif self.name > other.name: + return False + elif self.offset < other.offset: + return True + elif self.offset > other.offset: + return False + return self.ref_type < other.ref_type + return NotImplemented + + def __gt__(self, other): + if isinstance(other, self.__class__): + if self.name > other.name: + return True + elif self.name < other.name: + return False + elif self.offset > other.offset: + return True + elif self.offset < other.offset: + return False + return self.ref_type > other.ref_type + return NotImplemented + + def __cmp__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + + if self == other: + return 0 + elif self < other: + return -1 + return 1 + + def __hash__(self): + return hash(str(self)) + class NameSpace(QualifiedName): def __str__(self): return ":".join(self.name) diff --git a/suite/binaries b/suite/binaries -Subproject 9ccb8fe2925388881eddf2c09902ba2103f0eee +Subproject 596cd75165649589d821ca3c26c7f4c7eba269c diff --git a/suite/generator.py b/suite/generator.py index 75a83ad6..bae35016 100755 --- a/suite/generator.py +++ b/suite/generator.py @@ -241,6 +241,32 @@ def generate(test_store, outdir, exclude_binaries): unittest = UnitTestFile(os.path.join(outdir, "unit.py"), outdir, test_store) oracle = OracleTestFile(os.path.join(outdir, "oracle")) + # check all files to see if there is any newly added ones. + # If so, create a zip archive for it and delete the original file + allfiles = sorted(testcommon.get_file_list(test_store)) + for progress, testfile in enumerate(allfiles): + oraclefile = None + zip_only = False + if testfile.endswith(".gitignore"): + continue + if testfile.endswith(".pkl"): + continue + elif testfile.endswith(".DS_Store"): + continue + elif testfile.endswith(".zip"): + continue + else: + if os.path.exists(testfile + ".zip"): + # We've got a zip file for it, skip + continue + + # create the zip archive for the file + if not os.path.exists(testfile + ".zip"): + with zipfile.ZipFile(testfile + ".zip", "w") as zf: + zf.write(testfile, os.path.relpath(testfile, start=os.path.dirname(__file__))) + + os.unlink(testfile) + # Generate the tests that don't involve binaries but do involve oracles builder = testcommon.TestBuilder(test_store) tests = builder.methods() diff --git a/suite/testcommon.py b/suite/testcommon.py index c7a48c77..fc936d59 100644 --- a/suite/testcommon.py +++ b/suite/testcommon.py @@ -1000,6 +1000,94 @@ class TestBuilder(Builder): finally: self.delete_package("helloworld") + def test_type_xref(self): + """Type xref failure""" + + def dump_type_xref_info(type_name, code_refs, data_refs, type_refs, offset = None): + retinfo = [] + if offset is None: + for ref in code_refs: + retinfo.append('type {} is referenced by code {}'.format(type_name, ref)) + for ref in data_refs: + retinfo.append('type {} is referenced by data {}'.format(type_name, ref)) + for ref in type_refs: + retinfo.append('type {} is referenced by type {}'.format(type_name, ref)) + else: + for ref in code_refs: + retinfo.append('type field {}, offset {} is referenced by code {}'.format(type_name, hex(offset), ref)) + for ref in data_refs: + retinfo.append('type field {}, offset {} is referenced by data {}'.format(type_name, hex(offset), ref)) + for ref in type_refs: + retinfo.append('type field {}, offset {} is referenced by type {}'.format(type_name, hex(offset), ref)) + + return retinfo + + retinfo = [] + file_name = self.unpackage_file("type_xref.bndb") + if not os.path.exists(file_name): + return retinfo + + with BinaryViewType.get_view_of_file(file_name) as bv: + if bv is None: + return retinfo + + types = bv.types + test_types = ['A', 'B', 'C', 'D', 'E', 'F'] + for test_type in test_types: + code_refs = bv.get_code_refs_for_type(test_type) + data_refs = bv.get_data_refs_for_type(test_type) + type_refs = bv.get_type_refs_for_type(test_type) + retinfo.extend(dump_type_xref_info(test_type, code_refs, data_refs, type_refs)) + + t = types[test_type] + if not t: + continue + + for member in t.structure.members: + offset = member.offset + code_refs = bv.get_code_refs_for_type_field(test_type, offset) + data_refs = bv.get_data_refs_for_type_field(test_type, offset) + type_refs = bv.get_type_refs_for_type_field(test_type, offset) + retinfo.extend(dump_type_xref_info(test_type, code_refs, data_refs, type_refs, offset)) + + self.delete_package("type_xref.bndb") + return fixOutput(sorted(retinfo)) + + def test_variable_xref(self): + """Variable xref failure""" + + def dump_var_xref_info(var, var_refs): + retinfo = [] + for ref in var_refs: + retinfo.append('var {} is referenced at {}'.format(repr(var), repr(ref))) + return retinfo + + retinfo = [] + file_name = self.unpackage_file("type_xref.bndb") + if not os.path.exists(file_name): + return retinfo + + with BinaryViewType.get_view_of_file(file_name) as bv: + if bv is None: + return retinfo + + func = bv.get_function_at(0x1169) + for var in func.vars: + mlil_refs = func.get_mlil_var_refs(var) + retinfo.extend(dump_var_xref_info(var, mlil_refs)) + hlil_refs = func.get_hlil_var_refs(var) + retinfo.extend(dump_var_xref_info(var, hlil_refs)) + + mlil_range_var_refs = func.get_mlil_var_refs_from(0x1175, 0x8c) + for ref in mlil_range_var_refs: + retinfo.append("var {} is referenced at {}".format(ref.var, ref.src)) + + hlil_range_var_refs = func.get_hlil_var_refs_from(0x1175, 0x8c) + for ref in hlil_range_var_refs: + retinfo.append("var {} is referenced at {}".format(ref.var, ref.src)) + + self.delete_package("type_xref.bndb") + return fixOutput(sorted(retinfo)) class VerifyBuilder(Builder): """ The VerifyBuilder is for tests that verify @@ -91,6 +91,12 @@ bool NameList::operator<(const NameList& other) const } +bool NameList::operator>(const NameList& other) const +{ + return m_name > other.m_name; +} + + NameList NameList::operator+(const NameList& other) const { NameList result(*this); @@ -962,6 +968,32 @@ Ref<Type> Type::WithReplacedNamedTypeReference(NamedTypeReference* from, NamedTy } +bool Type::AddTypeMemberTokens(BinaryView* data, vector<InstructionTextToken>& tokens, int64_t offset, + vector<string>& nameList, size_t size, bool indirect) +{ + size_t tokenCount; + BNInstructionTextToken* list; + + size_t nameCount; + char** names = nullptr; + + if (!BNAddTypeMemberTokens(m_object, data->GetObject(), &list, &tokenCount, offset, &names, &nameCount, size, indirect)) + return false; + + vector<InstructionTextToken> newTokens = InstructionTextToken::ConvertAndFreeInstructionTextTokenList(list, tokenCount); + tokens.insert(tokens.end(), newTokens.begin(), newTokens.end()); + + nameList.clear(); + nameList.reserve(nameCount); + for (size_t i = 0; i < nameCount; i++) + nameList.emplace_back(names[i]); + + BNFreeStringList(names, nameCount); + + return true; +} + + TypeBuilder::TypeBuilder() { m_object = BNCreateVoidTypeBuilder(); diff --git a/ui/commands.h b/ui/commands.h index d0e8b981..a47f9ab5 100644 --- a/ui/commands.h +++ b/ui/commands.h @@ -33,7 +33,10 @@ bool BINARYNINJAUIAPI overwriteCode(BinaryViewRef data, ArchitectureRef arch, StructureRef BINARYNINJAUIAPI getInnerMostStructureContaining(BinaryViewRef data, StructureRef structure, size_t& memberIndex, const std::vector<std::string>& nameList, size_t nameIndex, TypeRef& type, std::string& typeName); StructureRef BINARYNINJAUIAPI getInnerMostStructureContainingOffset(BinaryViewRef data, StructureRef structure, - const std::vector<std::string>& nameList, size_t nameIndex, size_t& offset, TypeRef& type, std::string& typeName); + const std::vector<std::string>& nameList, size_t nameIndex, size_t offset, TypeRef& type, std::string& typeName); +// Get the offset of the inner most structure, ralative to the supplied outer most structure +uint64_t BINARYNINJAUIAPI getInnerMostStructureOffset(BinaryViewRef data, StructureRef structure, + const std::vector<std::string>& nameList, size_t nameIndex); // Auto generate a structure name std::string BINARYNINJAUIAPI createStructureName(BinaryViewRef data); diff --git a/ui/flowgraphwidget.h b/ui/flowgraphwidget.h index 7b6fc036..1b313c31 100644 --- a/ui/flowgraphwidget.h +++ b/ui/flowgraphwidget.h @@ -213,7 +213,7 @@ public: virtual BinaryViewRef getData() override { return m_data; } virtual uint64_t getCurrentOffset() override; virtual BNAddressRange getSelectionOffsets() override; - virtual BNAddressRange getSelectionForInfo() override; + virtual SelectionInfoForXref getSelectionForXref() override; virtual void setSelectionOffsets(BNAddressRange range) override; virtual bool navigate(uint64_t pos) override; virtual bool navigateToFunction(FunctionRef func, uint64_t pos) override; @@ -275,7 +275,7 @@ public: void showLineInNode(FlowGraphNodeRef node, size_t lineIndex); void ensureCursorVisible(); - void viewInTypesView(std::string typeName); + void viewInTypesView(std::string typeName, uint64_t offset = 0); void setInstructionHighlight(BNHighlightColor color); void setBlockHighlight(BNHighlightColor color); diff --git a/ui/linearview.h b/ui/linearview.h index 2d03248c..5c1d51bd 100644 --- a/ui/linearview.h +++ b/ui/linearview.h @@ -217,7 +217,7 @@ private Q_SLOTS: void adjustSize(int width, int height); void viewInHexEditor(); void viewInGraph(); - void viewInTypesView(std::string typeName = ""); + void viewInTypesView(std::string typeName = "", uint64_t offset = 0); void cycleILView(bool forward); void copyAddressSlot(); void goToAddress(); @@ -295,7 +295,7 @@ public: virtual uint64_t getCurrentOffset() override; virtual UIActionContext actionContext() override; virtual BNAddressRange getSelectionOffsets() override; - virtual BNAddressRange getSelectionForInfo() override; + virtual SelectionInfoForXref getSelectionForXref() override; virtual void setSelectionOffsets(BNAddressRange range) override; virtual FunctionRef getCurrentFunction() override; virtual BasicBlockRef getCurrentBasicBlock() override; diff --git a/ui/tokenizedtextview.h b/ui/tokenizedtextview.h index d937760a..01174e82 100644 --- a/ui/tokenizedtextview.h +++ b/ui/tokenizedtextview.h @@ -63,7 +63,7 @@ class BINARYNINJAUIAPI TokenizedTextView: public QAbstractScrollArea, public Vie void viewInHexEditor(); void viewInGraph(); - void viewInTypesView(std::string typeName = ""); + void viewInTypesView(std::string typeName = "", uint64_t offset = 0); void goToAddress(); void defineNameAtAddr(uint64_t addr); void defineName(); @@ -108,7 +108,7 @@ public: virtual BinaryViewRef getData() override { return m_data; } virtual uint64_t getCurrentOffset() override; virtual BNAddressRange getSelectionOffsets() override; - virtual BNAddressRange getSelectionForInfo() override; + virtual SelectionInfoForXref getSelectionForXref() override; virtual void setSelectionOffsets(BNAddressRange range) override; virtual FunctionRef getCurrentFunction() override; virtual BasicBlockRef getCurrentBasicBlock() override; diff --git a/ui/typeview.h b/ui/typeview.h index bc2fcc10..23985c59 100644 --- a/ui/typeview.h +++ b/ui/typeview.h @@ -157,6 +157,7 @@ public: virtual BinaryViewRef getData() override { return m_data; } virtual uint64_t getCurrentOffset() override; virtual BNAddressRange getSelectionOffsets() override; + virtual SelectionInfoForXref getSelectionForXref() override; virtual void setSelectionOffsets(BNAddressRange range) override; virtual bool navigate(uint64_t) override; @@ -164,7 +165,8 @@ public: virtual void setNavigationMode(std::string mode) override; virtual std::vector<std::string> getNavigationModes() override; - bool navigateToType(const std::string& name); + uint64_t findMatchingLine(const BinaryNinja::QualifiedName& name, uint64_t offset); + bool navigateToType(const std::string& name, uint64_t offset = 0); virtual void OnTypeDefined(BinaryNinja::BinaryView* view, const BinaryNinja::QualifiedName& name, BinaryNinja::Type* type) override; @@ -196,6 +198,8 @@ public: static void registerActions(); + virtual ArchitectureRef getOrAskForArchitecture(); + protected: virtual void resizeEvent(QResizeEvent* event) override; virtual void paintEvent(QPaintEvent* event) override; @@ -222,6 +226,7 @@ private Q_SLOTS: void createStructure(); void createUnion(); void setStructureSize(); + void addUserXref(); void updateLineNumberAreaWidth(size_t lineCount); }; diff --git a/ui/viewframe.h b/ui/viewframe.h index 91303cad..162dac11 100644 --- a/ui/viewframe.h +++ b/ui/viewframe.h @@ -14,6 +14,45 @@ #include "viewtype.h" #include "action.h" +// this struct is used to pass selection information for cross references +struct SelectionInfoForXref +{ + // Check these booleans before accessing the address/type/variable info, + // since the invalid fields are not guaranteed to be initialized/zero-ed. + // At any given time, at most one of these four should be true. + bool addrValid, typeValid, typeFieldValid, localVarValid; + + BNFunctionGraphType ilSource; + + uint64_t start; + uint64_t end; + + BinaryNinja::QualifiedName type; + uint64_t offset; + + BinaryNinja::Variable var; + + // These two need to be tested against nullptr before de-referencing + FunctionRef func; + ArchitectureRef arch; + + bool operator== (const SelectionInfoForXref& other) const + { + if (addrValid && other.addrValid) + return (start == other.start) && (end == other.end) && + (func == other.func) && (arch == other.arch); + else if (typeValid && other.typeValid) + return type == other.type; + else if (typeFieldValid && other.typeFieldValid) + return (type == other.type) && (offset == other.offset); + else if (localVarValid && other.localVarValid) + return (var == other.var) && (ilSource == other.ilSource); + return false; + } + + bool operator!= (const SelectionInfoForXref& other) const { return !(*this == other); } + bool isValid() const { return addrValid || typeValid || typeFieldValid || localVarValid; } +}; class BINARYNINJAUIAPI HistoryEntry: public BinaryNinja::RefCountObject { @@ -77,7 +116,7 @@ public: virtual BinaryViewRef getData() = 0; virtual uint64_t getCurrentOffset() = 0; virtual BNAddressRange getSelectionOffsets(); - virtual BNAddressRange getSelectionForInfo(); + virtual SelectionInfoForXref getSelectionForXref(); virtual void setSelectionOffsets(BNAddressRange range) = 0; virtual bool navigate(uint64_t offset) = 0; virtual bool navigateToFunction(FunctionRef func, uint64_t offset); @@ -290,6 +329,8 @@ public: bool navigate(BinaryViewRef data, uint64_t offset, bool updateInfo = true, bool addHistoryEntry = true); bool navigateToFunction(FunctionRef func, uint64_t offset, bool updateInfo = true, bool addHistoryEntry = true); bool goToReference(BinaryViewRef data, FunctionRef func, uint64_t source, uint64_t target, bool addHistoryEntry = true); + bool navigateToViewLocation(BinaryViewRef data, const ViewLocation& viewLocation, + bool addHistoryEntry = true); QString getTypeForView(QWidget* view); QString getDataTypeForView(const QString& type); QString getDataTypeForView(QWidget* view); diff --git a/ui/xreflist.h b/ui/xreflist.h index 5194a7e2..fe59d3d4 100644 --- a/ui/xreflist.h +++ b/ui/xreflist.h @@ -41,13 +41,19 @@ public: { DataXrefType, CodeXrefType, - VariableXrefType + VariableXrefType, + TypeXrefType }; protected: FunctionRef m_func; ArchitectureRef m_arch; uint64_t m_addr; + BinaryNinja::QualifiedName m_typeName; + uint64_t m_offset; + BinaryNinja::Variable m_var; + BNFunctionGraphType m_ilType; + size_t m_instrId; XrefType m_type; XrefDirection m_direction; mutable XrefHeader* m_parentItem; @@ -57,7 +63,11 @@ protected: public: explicit XrefItem(); explicit XrefItem(XrefHeader* parent, XrefType type, FunctionRef func); - explicit XrefItem(BinaryNinja::ReferenceSource referenceSource, XrefType type, XrefDirection direction); + // The four constructors are used for code/data/type/variable referecens, respectively + explicit XrefItem(BinaryNinja::ReferenceSource ref, XrefType type, XrefDirection direction); + explicit XrefItem(uint64_t addr, XrefType type, XrefDirection direction); + explicit XrefItem(BinaryNinja::TypeReferenceSource ref, XrefType type, XrefDirection direction); + explicit XrefItem(BinaryNinja::Variable var, BinaryNinja::ILReferenceSource ref, XrefType type, XrefDirection direction); XrefItem(const XrefItem& ref); virtual ~XrefItem(); @@ -65,6 +75,11 @@ public: const FunctionRef& func() const { return m_func; } const ArchitectureRef& arch() const { return m_arch; } uint64_t addr() const { return m_addr; } + BinaryNinja::QualifiedName typeName() const { return m_typeName; } + uint64_t offset() const { return m_offset; } + BinaryNinja::Variable variable() const { return m_var; } + BNFunctionGraphType ilType() const { return m_ilType; } + size_t instrId() const { return m_instrId; } XrefType type() const { return m_type; } int size() const { return m_size; } void setSize(int size) const { m_size = size; } @@ -113,6 +128,34 @@ public: }; +class XrefTypeHeader : public XrefHeader +{ + std::deque<XrefItem*> m_refs; +public: + XrefTypeHeader(); + XrefTypeHeader(BinaryNinja::QualifiedName name, XrefHeader* parent, XrefItem* child); + XrefTypeHeader(const XrefTypeHeader& header); + virtual int childCount() const override { return (int)m_refs.size(); } + virtual void appendChild(XrefItem* ref) override; + virtual int row(const XrefItem* item) const override; + virtual XrefItem* child(int i) const override; +}; + + +class XrefVariableHeader : public XrefHeader +{ + std::deque<XrefItem*> m_refs; +public: + XrefVariableHeader(); + XrefVariableHeader(XrefHeader* parent, XrefItem* child); + XrefVariableHeader(const XrefVariableHeader& header); + virtual int childCount() const override { return (int)m_refs.size(); } + virtual void appendChild(XrefItem* ref) override; + virtual int row(const XrefItem* item) const override; + virtual XrefItem* child(int i) const override; +}; + + class XrefCodeReferences: public XrefHeader { std::map<FunctionRef, XrefFunctionHeader*> m_refs; @@ -141,9 +184,39 @@ public: }; +class XrefTypeReferences: public XrefHeader +{ + std::map<BinaryNinja::QualifiedName, XrefTypeHeader*> m_refs; + std::deque<XrefTypeHeader*> m_refList; +public: + XrefTypeReferences(XrefHeader* parent); + virtual ~XrefTypeReferences(); + virtual int childCount() const override { return (int)m_refs.size(); }; + virtual void appendChild(XrefItem* ref) override; + XrefHeader* parentOf(XrefItem* ref) const; + virtual int row(const XrefItem* item) const override; + virtual XrefItem* child(int i) const override; +}; + + +class XrefVariableReferences: public XrefHeader +{ + std::map<BinaryNinja::Variable, XrefVariableHeader*> m_refs; + std::deque<XrefVariableHeader*> m_refList; +public: + XrefVariableReferences(XrefHeader* parent); + virtual ~XrefVariableReferences(); + virtual int childCount() const override { return (int)m_refs.size(); }; + virtual void appendChild(XrefItem* ref) override; + XrefHeader* parentOf(XrefItem* ref) const; + virtual int row(const XrefItem* item) const override; + virtual XrefItem* child(int i) const override; +}; + + class XrefRoot: public XrefHeader { - std::map<int, XrefHeader*> m_refs; + std::map<XrefItem::XrefType, XrefHeader*> m_refs; public: XrefRoot(); XrefRoot(XrefRoot&& root); @@ -162,10 +235,11 @@ class BINARYNINJAUIAPI CrossReferenceTreeModel : public QAbstractItemModel XrefRoot* m_rootItem; QWidget* m_owner; BinaryViewRef m_data; + ViewFrame* m_view; std::vector<XrefItem> m_refs; public: - CrossReferenceTreeModel(QWidget* parent, BinaryViewRef data); + CrossReferenceTreeModel(QWidget* parent, BinaryViewRef data, ViewFrame* view); virtual ~CrossReferenceTreeModel() {} virtual QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const override; @@ -181,6 +255,7 @@ public: XrefRoot* getRoot() { return m_rootItem; } bool setModelData(std::vector<XrefItem>& refs, QItemSelectionModel* selectionModel, bool& selectionUpdated); int leafCount() const; + ViewFrame* getView() const { return m_view; } }; @@ -190,6 +265,7 @@ class BINARYNINJAUIAPI CrossReferenceTableModel : public QAbstractTableModel QWidget* m_owner; BinaryViewRef m_data; + ViewFrame* m_view; std::vector<XrefItem> m_refs; public: enum ColumnHeaders @@ -200,7 +276,7 @@ public: Preview = 3 }; - CrossReferenceTableModel(QWidget* parent, BinaryViewRef data); + CrossReferenceTableModel(QWidget* parent, BinaryViewRef data, ViewFrame* view); virtual ~CrossReferenceTableModel() {} virtual QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const override; @@ -213,6 +289,7 @@ public: virtual bool hasChildren(const QModelIndex&) const override { return false; } bool setModelData(std::vector<XrefItem>& refs, QItemSelectionModel* selectionModel, bool& selectionUpdated); const XrefItem& getRow(int idx); + ViewFrame* getView() const { return m_view; } }; @@ -243,6 +320,8 @@ class BINARYNINJAUIAPI CrossReferenceFilterProxyModel : public QSortFilterProxyM bool m_showData = true; bool m_showCode = true; + bool m_showType = true; + bool m_showVariable = true; bool m_showIncoming = true; bool m_showOutgoing = true; bool m_table; @@ -261,8 +340,8 @@ protected: virtual bool hasChildren(const QModelIndex& parent) const override; public Q_SLOTS: - void directionChanged(int index); - void typeChanged(int index); + void directionChanged(int index, bool checked); + void typeChanged(int index, bool checked); void resetFilter(); }; @@ -278,7 +357,7 @@ public: CrossReferenceContainer(CrossReferenceWidget* parent, ViewFrame* view, BinaryViewRef data); virtual ~CrossReferenceContainer() {} virtual QModelIndex translateIndex(const QModelIndex& idx) const = 0; - virtual bool getReference(const QModelIndex& idx, FunctionRef& func, uint64_t& addr) const = 0; + virtual bool getReference(const QModelIndex& idx, XrefItem** refPtr) const = 0; virtual QModelIndex nextIndex() = 0; virtual QModelIndex prevIndex() = 0; virtual QModelIndexList selectedRows() const = 0; @@ -300,7 +379,7 @@ class BINARYNINJAUIAPI CrossReferenceTree: public QTreeView, public CrossReferen protected: void drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const override; - virtual bool getReference(const QModelIndex& idx, FunctionRef& func, uint64_t& addr) const override; + virtual bool getReference(const QModelIndex& idx, XrefItem** refPtr) const override; public: CrossReferenceTree(CrossReferenceWidget* parent, ViewFrame* view, BinaryViewRef data); @@ -344,7 +423,7 @@ public: virtual QModelIndex prevIndex() override; virtual bool hasSelection() const override { return selectionModel()->selectedRows().size() != 0; } virtual QModelIndexList selectedRows() const override { return selectionModel()->selectedRows(); } - virtual bool getReference(const QModelIndex& idx, FunctionRef& func, uint64_t& addr) const override; + virtual bool getReference(const QModelIndex& idx, XrefItem** refPtr) const override; virtual void mouseMoveEvent(QMouseEvent* e) override; virtual void mousePressEvent(QMouseEvent* e) override; virtual void keyPressEvent(QKeyEvent* e) override; @@ -360,6 +439,7 @@ Q_SIGNALS: }; class ExpandableGroup; +class QCheckboxCombo; class BINARYNINJAUIAPI CrossReferenceWidget: public QWidget, public DockContextHandler { Q_OBJECT @@ -370,7 +450,7 @@ class BINARYNINJAUIAPI CrossReferenceWidget: public QWidget, public DockContextH QAbstractItemView* m_object; QLabel* m_label; QCheckBox* m_pinRefs; - QComboBox* m_direction, *m_type; + QCheckboxCombo *m_direction, *m_type; CrossReferenceTable* m_table; CrossReferenceTree* m_tree; CrossReferenceContainer* m_container; @@ -384,10 +464,8 @@ class BINARYNINJAUIAPI CrossReferenceWidget: public QWidget, public DockContextH ExpandableGroup* m_group; bool m_curRefTargetValid = false; - uint64_t m_curRefTarget = 0; - uint64_t m_curRefTargetEnd = 0; - uint64_t m_newRefTarget = 0; - uint64_t m_newRefTargetEnd = 0; + SelectionInfoForXref m_curRef; + SelectionInfoForXref m_newRef; bool m_navigating = false; bool m_navToNextOrPrevStarted = false; bool m_pinned; @@ -400,8 +478,9 @@ public: virtual void notifyFontChanged() override; virtual bool shouldBeVisible(ViewFrame* frame) override; - virtual void setCurrentSelection(uint64_t begin, uint64_t end); - virtual void setCurrentPinnedSelection(uint64_t begin, uint64_t end); + virtual QString getHeaderText(SelectionInfoForXref selectionInfo); + virtual void setCurrentSelection(SelectionInfoForXref selectionInfo); + virtual void setCurrentPinnedSelection(SelectionInfoForXref selectionInfo); void updatePinnedSelection(); virtual void navigateToNext(); virtual void navigateToPrev(); @@ -423,8 +502,8 @@ public Q_SLOTS: void referenceActivated(const QModelIndex& idx); void pinnedStateChanged(bool state); void selectionChanged(); - void typeChanged(int change); - void directionChanged(int change); + void typeChanged(int index, bool checked); + void directionChanged(int change, bool checked); }; @@ -445,4 +524,33 @@ public: explicit ExpandableGroup(const QString& title = "", QWidget* parent = nullptr); void setContentLayout(QLayout* contentLayout); void setTitle(const QString& title) { m_button->setText(title); } -};
\ No newline at end of file +}; + + +// https://github.com/CuriousCrow/QCheckboxCombo +/* + * QCheckboxCombo is a combobox widget that contains items with checkboxes + * User can select proper items by checking corresponding checkboxes. + * Resulting text will contain list of selected items separated by delimiter (", " by default) + */ +class BINARYNINJAUIAPI QCheckboxCombo : public QComboBox +{ + Q_OBJECT + +public: + explicit QCheckboxCombo(QWidget *parent = nullptr); + bool eventFilter(QObject* watched, QEvent* event); + void hidePopup(); + void showPopup(); + void addItem(const QString &text, bool checked = true); + +Q_SIGNALS: + void selectionChanged(const QString& text); + void itemToggled(int index, bool checked); + +private: + bool m_popupVisible = false; + bool m_editable = false; + QString m_selectionString; + const QString m_delimiter = ", "; +}; |
