diff options
| author | Brian Potchik <brian@vector35.com> | 2025-11-24 15:35:58 -0500 |
|---|---|---|
| committer | Brian Potchik <brian@vector35.com> | 2025-11-24 15:35:58 -0500 |
| commit | b4d77d5b44dd322042f90b5a4a4da9075d05b644 (patch) | |
| tree | 9d13e5ae7c4c2f62ffd67ba79bfb8cc42b1566cc | |
| parent | d3d4d43d223da5cd84b48a129b54acc39612c986 (diff) | |
Add AnalysisContext FFI for SectionMap queries.
| -rw-r--r-- | binaryninjaapi.h | 9 | ||||
| -rw-r--r-- | binaryninjacore.h | 9 | ||||
| -rw-r--r-- | python/workflow.py | 77 | ||||
| -rw-r--r-- | rust/src/workflow.rs | 66 | ||||
| -rw-r--r-- | workflow.cpp | 59 |
5 files changed, 219 insertions, 1 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 37bbd235..6f84250c 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -11483,6 +11483,15 @@ namespace BinaryNinja { Ref<Segment> GetSegmentAt(uint64_t addr); std::vector<BNAddressRange> GetMappedAddressRanges(); std::vector<BNAddressRange> GetBackedAddressRanges(); + + // Section map access - lock-free access to cached SectionMap + bool IsOffsetCodeSemantics(uint64_t offset); + bool IsOffsetExternSemantics(uint64_t offset); + bool IsOffsetWritableSemantics(uint64_t offset); + bool IsOffsetReadOnlySemantics(uint64_t offset); + std::vector<Ref<Section>> GetSections(); + Ref<Section> GetSectionByName(const std::string& name); + std::vector<Ref<Section>> GetSectionsAt(uint64_t addr); }; // Explicit template specialization declarations for AnalysisContext::GetSetting<T> diff --git a/binaryninjacore.h b/binaryninjacore.h index b7b33715..a86fd5d3 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -37,7 +37,7 @@ // Current ABI version for linking to the core. This is incremented any time // there are changes to the API that affect linking, including new functions, // new types, or modifications to existing functions or types. -#define BN_CURRENT_CORE_ABI_VERSION 149 +#define BN_CURRENT_CORE_ABI_VERSION 150 // Minimum ABI version that is supported for loading of plugins. Plugins that // are linked to an ABI version less than this will not be able to load and @@ -5945,6 +5945,13 @@ extern "C" BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetWritable(BNAnalysisContext* analysisContext, uint64_t offset); BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetExecutable(BNAnalysisContext* analysisContext, uint64_t offset); BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetBackedByFile(BNAnalysisContext* analysisContext, uint64_t offset); + BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetCodeSemantics(BNAnalysisContext* analysisContext, uint64_t offset); + BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetExternSemantics(BNAnalysisContext* analysisContext, uint64_t offset); + BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetWritableSemantics(BNAnalysisContext* analysisContext, uint64_t offset); + BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetReadOnlySemantics(BNAnalysisContext* analysisContext, uint64_t offset); + BINARYNINJACOREAPI BNSection** BNAnalysisContextGetSections(BNAnalysisContext* analysisContext, size_t* count); + BINARYNINJACOREAPI BNSection* BNAnalysisContextGetSectionByName(BNAnalysisContext* analysisContext, const char* name); + BINARYNINJACOREAPI BNSection** BNAnalysisContextGetSectionsAt(BNAnalysisContext* analysisContext, uint64_t addr, size_t* count); BINARYNINJACOREAPI uint64_t BNAnalysisContextGetStart(BNAnalysisContext* analysisContext); BINARYNINJACOREAPI uint64_t BNAnalysisContextGetEnd(BNAnalysisContext* analysisContext); BINARYNINJACOREAPI uint64_t BNAnalysisContextGetLength(BNAnalysisContext* analysisContext); diff --git a/python/workflow.py b/python/workflow.py index ed6bc876..61827b55 100644 --- a/python/workflow.py +++ b/python/workflow.py @@ -293,6 +293,83 @@ class AnalysisContext: """ return core.BNAnalysisContextIsOffsetBackedByFile(self.handle, offset) + def is_offset_code_semantics(self, offset: int) -> bool: + """ + Check if an offset has code semantics in the cached section map. + + :param offset: Offset to check + :return: True if offset has code semantics + """ + return core.BNAnalysisContextIsOffsetCodeSemantics(self.handle, offset) + + def is_offset_extern_semantics(self, offset: int) -> bool: + """ + Check if an offset has external semantics in the cached section map. + + :param offset: Offset to check + :return: True if offset has external semantics + """ + return core.BNAnalysisContextIsOffsetExternSemantics(self.handle, offset) + + def is_offset_writable_semantics(self, offset: int) -> bool: + """ + Check if an offset has writable semantics in the cached section map. + + :param offset: Offset to check + :return: True if offset has writable semantics + """ + return core.BNAnalysisContextIsOffsetWritableSemantics(self.handle, offset) + + def is_offset_readonly_semantics(self, offset: int) -> bool: + """ + Check if an offset has read-only semantics in the cached section map. + + :param offset: Offset to check + :return: True if offset has read-only semantics + """ + return core.BNAnalysisContextIsOffsetReadOnlySemantics(self.handle, offset) + + def get_sections(self) -> List['binaryninja.binaryview.Section']: + """ + Get all sections from the cached section map. + + :return: List of all sections + """ + count = ctypes.c_ulonglong() + sections = core.BNAnalysisContextGetSections(self.handle, count) + result = [] + for i in range(count.value): + result.append(binaryninja.binaryview.Section(core.BNNewSectionReference(sections[i]))) + core.BNFreeSectionList(sections, count.value) + return result + + def get_section_by_name(self, name: str) -> Optional['binaryninja.binaryview.Section']: + """ + Get a section by name from the cached section map. + + :param name: Section name + :return: Section with the given name, or None if not found + """ + section = core.BNAnalysisContextGetSectionByName(self.handle, name) + if not section: + return None + return binaryninja.binaryview.Section(section) + + def get_sections_at(self, addr: int) -> List['binaryninja.binaryview.Section']: + """ + Get all sections containing the given address from the cached section map. + + :param addr: Address to query + :return: List of sections containing the address + """ + count = ctypes.c_ulonglong() + sections = core.BNAnalysisContextGetSectionsAt(self.handle, addr, count) + result = [] + for i in range(count.value): + result.append(binaryninja.binaryview.Section(core.BNNewSectionReference(sections[i]))) + core.BNFreeSectionList(sections, count.value) + return result + def get_start(self) -> int: """ Get the start address from the cached memory map. diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index adc8d4ba..a3de4221 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -12,6 +12,7 @@ use crate::high_level_il::HighLevelILFunction; use crate::low_level_il::{LowLevelILMutableFunction, LowLevelILRegularFunction}; use crate::medium_level_il::MediumLevelILFunction; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use crate::section::Section; use crate::segment::{Segment, SegmentFlags}; use crate::string::{BnString, IntoCStr}; use std::ffi::c_char; @@ -215,6 +216,71 @@ impl AnalysisContext { unsafe { BNAnalysisContextIsOffsetBackedByFile(self.handle.as_ptr(), offset) } } + /// Check if an offset has code semantics in the cached section map. + /// + /// NOTE: This is a lock-free alternative to [`BinaryView::is_offset_code_semantics`]. + pub fn is_offset_code_semantics(&self, offset: u64) -> bool { + unsafe { BNAnalysisContextIsOffsetCodeSemantics(self.handle.as_ptr(), offset) } + } + + /// Check if an offset has external semantics in the cached section map. + /// + /// NOTE: This is a lock-free alternative to [`BinaryView::is_offset_extern_semantics`]. + pub fn is_offset_extern_semantics(&self, offset: u64) -> bool { + unsafe { BNAnalysisContextIsOffsetExternSemantics(self.handle.as_ptr(), offset) } + } + + /// Check if an offset has writable semantics in the cached section map. + /// + /// NOTE: This is a lock-free alternative to [`BinaryView::is_offset_writable_semantics`]. + pub fn is_offset_writable_semantics(&self, offset: u64) -> bool { + unsafe { BNAnalysisContextIsOffsetWritableSemantics(self.handle.as_ptr(), offset) } + } + + /// Check if an offset has read-only semantics in the cached section map. + /// + /// NOTE: This is a lock-free alternative to [`BinaryView::is_offset_readonly_semantics`]. + pub fn is_offset_readonly_semantics(&self, offset: u64) -> bool { + unsafe { BNAnalysisContextIsOffsetReadOnlySemantics(self.handle.as_ptr(), offset) } + } + + /// Get all sections from the cached section map. + /// + /// NOTE: This is a lock-free alternative to [`BinaryView::sections`]. + pub fn sections(&self) -> Array<Section> { + unsafe { + let mut count = 0; + let sections = BNAnalysisContextGetSections(self.handle.as_ptr(), &mut count); + Array::new(sections, count, ()) + } + } + + /// Get a section by name from the cached section map. + /// + /// NOTE: This is a lock-free alternative to [`BinaryView::section_by_name`]. + pub fn section_by_name(&self, name: impl IntoCStr) -> Option<Ref<Section>> { + unsafe { + let raw_name = name.to_cstr(); + let name_ptr = raw_name.as_ptr(); + let raw_section_ptr = BNAnalysisContextGetSectionByName(self.handle.as_ptr(), name_ptr); + match raw_section_ptr.is_null() { + false => Some(Section::ref_from_raw(raw_section_ptr)), + true => None, + } + } + } + + /// Get all sections containing the given address from the cached section map. + /// + /// NOTE: This is a lock-free alternative to [`BinaryView::sections_at`]. + pub fn sections_at(&self, addr: u64) -> Array<Section> { + unsafe { + let mut count = 0; + let sections = BNAnalysisContextGetSectionsAt(self.handle.as_ptr(), addr, &mut count); + Array::new(sections, count, ()) + } + } + /// Get the start address (the lowest address) from the cached [`MemoryMap`]. /// /// NOTE: This is a lock-free alternative to [`BinaryView::start`]. diff --git a/workflow.cpp b/workflow.cpp index d4981c1a..5be636d2 100644 --- a/workflow.cpp +++ b/workflow.cpp @@ -235,6 +235,65 @@ bool AnalysisContext::IsOffsetBackedByFile(uint64_t offset) } +bool AnalysisContext::IsOffsetCodeSemantics(uint64_t offset) +{ + return BNAnalysisContextIsOffsetCodeSemantics(m_object, offset); +} + + +bool AnalysisContext::IsOffsetExternSemantics(uint64_t offset) +{ + return BNAnalysisContextIsOffsetExternSemantics(m_object, offset); +} + + +bool AnalysisContext::IsOffsetWritableSemantics(uint64_t offset) +{ + return BNAnalysisContextIsOffsetWritableSemantics(m_object, offset); +} + + +bool AnalysisContext::IsOffsetReadOnlySemantics(uint64_t offset) +{ + return BNAnalysisContextIsOffsetReadOnlySemantics(m_object, offset); +} + + +vector<Ref<Section>> AnalysisContext::GetSections() +{ + size_t count; + BNSection** sections = BNAnalysisContextGetSections(m_object, &count); + vector<Ref<Section>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new Section(BNNewSectionReference(sections[i]))); + BNFreeSectionList(sections, count); + return result; +} + + +Ref<Section> AnalysisContext::GetSectionByName(const string& name) +{ + BNSection* section = BNAnalysisContextGetSectionByName(m_object, name.c_str()); + if (!section) + return nullptr; + return new Section(section); +} + + +vector<Ref<Section>> AnalysisContext::GetSectionsAt(uint64_t addr) +{ + size_t count; + BNSection** sections = BNAnalysisContextGetSectionsAt(m_object, addr, &count); + vector<Ref<Section>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new Section(BNNewSectionReference(sections[i]))); + BNFreeSectionList(sections, count); + return result; +} + + uint64_t AnalysisContext::GetStart() { return BNAnalysisContextGetStart(m_object); |
