diff options
| author | Rusty Wagner <rusty@vector35.com> | 2016-10-10 21:28:16 -0400 |
|---|---|---|
| committer | Rusty Wagner <rusty@vector35.com> | 2016-10-10 21:28:16 -0400 |
| commit | 7e4cbbbf09e8dcda20f552a937b458aa09c28cf9 (patch) | |
| tree | 95e0ef73cddbf83936d772a3f0bec64ce6d8c8a3 | |
| parent | 70dd487931d7bcd75e10753a741fba3299488327 (diff) | |
| parent | cf7832b8025c9acee11304bec0540f8896d56299 (diff) | |
Merge branch 'segments' into dev
| -rw-r--r-- | binaryninjaapi.h | 45 | ||||
| -rw-r--r-- | binaryninjacore.h | 81 | ||||
| -rw-r--r-- | binaryview.cpp | 220 | ||||
| -rw-r--r-- | python/__init__.py | 313 | ||||
| -rw-r--r-- | python/examples/nds.py | 88 | ||||
| -rw-r--r-- | python/examples/nes.py | 114 |
6 files changed, 680 insertions, 181 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index ed714be6..7c297f73 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -730,6 +730,22 @@ namespace BinaryNinja bool autoDiscovered; }; + struct Segment + { + uint64_t start, length; + uint64_t dataOffset, dataLength; + uint32_t flags; + }; + + struct Section + { + std::string name, type; + uint64_t start, length; + std::string linkedSection, infoSection; + uint64_t infoData; + uint64_t align, entrySize; + }; + struct NameAndType; /*! BinaryView is the base class for creating views on binary data (e.g. ELF, PE, Mach-O). @@ -743,8 +759,9 @@ namespace BinaryNinja /*! BinaryView constructor \param typeName name of the BinaryView (e.g. ELF, PE, Mach-O, ...) \param file a file to create a view from + \param parentView optional view that contains the raw data used by this view */ - BinaryView(const std::string& typeName, FileMetadata* file); + BinaryView(const std::string& typeName, FileMetadata* file, BinaryView* parentView = nullptr); /*! PerformRead provides a mapping between the flat file and virtual offsets in the file. @@ -771,7 +788,7 @@ namespace BinaryNinja virtual BNEndianness PerformGetDefaultEndianness() const; virtual size_t PerformGetAddressSize() const; - virtual bool PerformSave(FileAccessor* file) { (void)file; return false; } + virtual bool PerformSave(FileAccessor* file); void NotifyDataWritten(uint64_t offset, size_t len); void NotifyDataInserted(uint64_t offset, size_t len); @@ -805,6 +822,7 @@ namespace BinaryNinja virtual bool Init() { return true; } FileMetadata* GetFile() const { return m_file; } + Ref<BinaryView> GetParentView() const; std::string GetTypeName() const; bool IsModified() const; @@ -969,6 +987,29 @@ namespace BinaryNinja bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title); bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title, uint64_t currentAddress); + + void AddAutoSegment(uint64_t start, uint64_t length, uint64_t dataOffset, uint64_t dataLength, uint32_t flags); + void RemoveAutoSegment(uint64_t start, uint64_t length); + void AddUserSegment(uint64_t start, uint64_t length, uint64_t dataOffset, uint64_t dataLength, uint32_t flags); + void RemoveUserSegment(uint64_t start, uint64_t length); + std::vector<Segment> GetSegments(); + bool GetSegmentAt(uint64_t addr, Segment& result); + + void AddAutoSection(const std::string& name, uint64_t start, uint64_t length, const std::string& type = "", + uint64_t align = 1, uint64_t entrySize = 0, const std::string& linkedSection = "", + const std::string& infoSection = "", uint64_t infoData = 0); + void RemoveAutoSection(const std::string& name); + void AddUserSection(const std::string& name, uint64_t start, uint64_t length, const std::string& type = "", + uint64_t align = 1, uint64_t entrySize = 0, const std::string& linkedSection = "", + const std::string& infoSection = "", uint64_t infoData = 0); + void RemoveUserSection(const std::string& name); + std::vector<Section> GetSections(); + std::vector<Section> GetSectionsAt(uint64_t addr); + bool GetSectionByName(const std::string& name, Section& result); + + std::vector<std::string> GetUniqueSectionNames(const std::vector<std::string>& names); + + std::vector<BNAddressRange> GetAllocatedRanges(); }; class BinaryData: public BinaryView diff --git a/binaryninjacore.h b/binaryninjacore.h index 0eeeaa48..ac615922 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -201,7 +201,14 @@ extern "C" FunctionContinuationLineType, StackVariableLineType, StackVariableListEndLineType, - FunctionEndLineType + FunctionEndLineType, + NoteStartLineType, + NoteLineType, + NoteEndLineType, + SectionStartLineType, + SectionEndLineType, + SectionSeparatorLineType, + NonContiguousSeparatorLineType }; enum BNSymbolType @@ -1144,8 +1151,44 @@ extern "C" void (*destructFunction)(void* ctxt, BNFunction* func); }; + enum BNSegmentFlag + { + SegmentExecutable = 1, + SegmentWritable = 2, + SegmentReadable = 4, + SegmentContainsData = 8, + SegmentContainsCode = 0x10, + SegmentDenyWrite = 0x20, + SegmentDenyExecute = 0x40 + }; + + struct BNSegment + { + uint64_t start, length; + uint64_t dataOffset, dataLength; + uint32_t flags; + }; + + struct BNSection + { + char* name; + char* type; + uint64_t start, length; + char* linkedSection; + char* infoSection; + uint64_t infoData; + uint64_t align, entrySize; + }; + + struct BNAddressRange + { + uint64_t start; + uint64_t end; + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); + BINARYNINJACOREAPI void BNFreeStringList(char** strs, size_t count); BINARYNINJACOREAPI void BNShutdown(void); @@ -1273,6 +1316,8 @@ extern "C" BINARYNINJACOREAPI BNFileMetadata* BNGetFileForView(BNBinaryView* view); BINARYNINJACOREAPI char* BNGetViewType(BNBinaryView* view); + BINARYNINJACOREAPI BNBinaryView* BNGetParentView(BNBinaryView* view); + BINARYNINJACOREAPI size_t BNReadViewData(BNBinaryView* view, void* dest, uint64_t offset, size_t len); BINARYNINJACOREAPI BNDataBuffer* BNReadViewBuffer(BNBinaryView* view, uint64_t offset, size_t len); @@ -1332,6 +1377,35 @@ extern "C" BINARYNINJACOREAPI bool BNFindNextData(BNBinaryView* view, uint64_t start, BNDataBuffer* data, uint64_t* result, BNFindFlag flags); + BINARYNINJACOREAPI void BNAddAutoSegment(BNBinaryView* view, uint64_t start, uint64_t length, + uint64_t dataOffset, uint64_t dataLength, uint32_t flags); + BINARYNINJACOREAPI void BNRemoveAutoSegment(BNBinaryView* view, uint64_t start, uint64_t length); + BINARYNINJACOREAPI void BNAddUserSegment(BNBinaryView* view, uint64_t start, uint64_t length, + uint64_t dataOffset, uint64_t dataLength, uint32_t flags); + BINARYNINJACOREAPI void BNRemoveUserSegment(BNBinaryView* view, uint64_t start, uint64_t length); + BINARYNINJACOREAPI BNSegment* BNGetSegments(BNBinaryView* view, size_t* count); + BINARYNINJACOREAPI void BNFreeSegmentList(BNSegment* segments); + BINARYNINJACOREAPI bool BNGetSegmentAt(BNBinaryView* view, uint64_t addr, BNSegment* result); + + BINARYNINJACOREAPI void BNAddAutoSection(BNBinaryView* view, const char* name, uint64_t start, uint64_t length, + const char* type, uint64_t align, uint64_t entrySize, const char* linkedSection, const char* infoSection, + uint64_t infoData); + BINARYNINJACOREAPI void BNRemoveAutoSection(BNBinaryView* view, const char* name); + BINARYNINJACOREAPI void BNAddUserSection(BNBinaryView* view, const char* name, uint64_t start, uint64_t length, + const char* type, uint64_t align, uint64_t entrySize, const char* linkedSection, const char* infoSection, + uint64_t infoData); + BINARYNINJACOREAPI void BNRemoveUserSection(BNBinaryView* view, const char* name); + BINARYNINJACOREAPI BNSection* BNGetSections(BNBinaryView* view, size_t* count); + BINARYNINJACOREAPI BNSection* BNGetSectionsAt(BNBinaryView* view, uint64_t addr, size_t* count); + BINARYNINJACOREAPI void BNFreeSectionList(BNSection* sections, size_t count); + BINARYNINJACOREAPI bool BNGetSectionByName(BNBinaryView* view, const char* name, BNSection* result); + BINARYNINJACOREAPI void BNFreeSection(BNSection* section); + + BINARYNINJACOREAPI char** BNGetUniqueSectionNames(BNBinaryView* view, const char** names, size_t count); + + BINARYNINJACOREAPI BNAddressRange* BNGetAllocatedRanges(BNBinaryView* view, size_t* count); + BINARYNINJACOREAPI void BNFreeAddressRanges(BNAddressRange* ranges); + // Raw binary data view BINARYNINJACOREAPI BNBinaryView* BNCreateBinaryDataView(BNFileMetadata* file); BINARYNINJACOREAPI BNBinaryView* BNCreateBinaryDataViewFromBuffer(BNFileMetadata* file, BNDataBuffer* buf); @@ -1340,7 +1414,8 @@ extern "C" BINARYNINJACOREAPI BNBinaryView* BNCreateBinaryDataViewFromFile(BNFileMetadata* file, BNFileAccessor* accessor); // Creation of new types of binary views - BINARYNINJACOREAPI BNBinaryView* BNCreateCustomBinaryView(const char* name, BNFileMetadata* file, BNCustomBinaryView* view); + BINARYNINJACOREAPI BNBinaryView* BNCreateCustomBinaryView(const char* name, BNFileMetadata* file, + BNBinaryView* parent, BNCustomBinaryView* view); // Binary view type management BINARYNINJACOREAPI BNBinaryViewType* BNGetBinaryViewTypeByName(const char* name); @@ -1623,7 +1698,7 @@ extern "C" BINARYNINJACOREAPI BNStringReference* BNGetStrings(BNBinaryView* view, size_t* count); BINARYNINJACOREAPI BNStringReference* BNGetStringsInRange(BNBinaryView* view, uint64_t start, uint64_t len, size_t* count); - BINARYNINJACOREAPI void BNFreeStringList(BNStringReference* strings); + BINARYNINJACOREAPI void BNFreeStringReferenceList(BNStringReference* strings); BINARYNINJACOREAPI BNStackVariable* BNGetStackLayout(BNFunction* func, size_t* count); BINARYNINJACOREAPI void BNFreeStackLayout(BNStackVariable* vars, size_t count); diff --git a/binaryview.cpp b/binaryview.cpp index 863d57b2..98f6f334 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -18,6 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. +#include <algorithm> #include "binaryninjaapi.h" using namespace BinaryNinja; @@ -243,7 +244,7 @@ void AnalysisCompletionEvent::Cancel() } -BinaryView::BinaryView(const std::string& typeName, FileMetadata* file) +BinaryView::BinaryView(const std::string& typeName, FileMetadata* file, BinaryView* parentView) { BNCustomBinaryView view; view.context = this; @@ -270,7 +271,8 @@ BinaryView::BinaryView(const std::string& typeName, FileMetadata* file) m_file = file; AddRefForRegistration(); - m_object = BNCreateCustomBinaryView(typeName.c_str(), m_file->GetObject(), &view); + m_object = BNCreateCustomBinaryView(typeName.c_str(), m_file->GetObject(), + parentView ? parentView->GetObject() : nullptr, &view); } @@ -481,6 +483,15 @@ size_t BinaryView::PerformGetAddressSize() const } +bool BinaryView::PerformSave(FileAccessor* file) +{ + Ref<BinaryView> parent = GetParentView(); + if (parent) + return parent->Save(file); + return false; +} + + void BinaryView::NotifyDataWritten(uint64_t offset, size_t len) { BNNotifyDataWritten(m_object, offset, len); @@ -499,6 +510,15 @@ void BinaryView::NotifyDataRemoved(uint64_t offset, uint64_t len) } +Ref<BinaryView> BinaryView::GetParentView() const +{ + BNBinaryView* view = BNGetParentView(m_object); + if (!view) + return nullptr; + return new BinaryView(view); +} + + string BinaryView::GetTypeName() const { char* str = BNGetViewType(m_object); @@ -1225,7 +1245,7 @@ vector<BNStringReference> BinaryView::GetStrings() BNStringReference* strings = BNGetStrings(m_object, &count); vector<BNStringReference> result; result.insert(result.end(), strings, strings + count); - BNFreeStringList(strings); + BNFreeStringReferenceList(strings); return result; } @@ -1236,7 +1256,7 @@ vector<BNStringReference> BinaryView::GetStrings(uint64_t start, uint64_t len) BNStringReference* strings = BNGetStringsInRange(m_object, start, len, &count); vector<BNStringReference> result; result.insert(result.end(), strings, strings + count); - BNFreeStringList(strings); + BNFreeStringReferenceList(strings); return result; } @@ -1513,6 +1533,198 @@ bool BinaryView::GetAddressInput(uint64_t& result, const string& prompt, const s } +void BinaryView::AddAutoSegment(uint64_t start, uint64_t length, uint64_t dataOffset, uint64_t dataLength, + uint32_t flags) +{ + BNAddAutoSegment(m_object, start, length, dataOffset, dataLength, flags); +} + + +void BinaryView::RemoveAutoSegment(uint64_t start, uint64_t length) +{ + BNRemoveAutoSegment(m_object, start, length); +} + + +void BinaryView::AddUserSegment(uint64_t start, uint64_t length, uint64_t dataOffset, uint64_t dataLength, + uint32_t flags) +{ + BNAddUserSegment(m_object, start, length, dataOffset, dataLength, flags); +} + + +void BinaryView::RemoveUserSegment(uint64_t start, uint64_t length) +{ + BNRemoveUserSegment(m_object, start, length); +} + + +vector<Segment> BinaryView::GetSegments() +{ + size_t count; + BNSegment* segments = BNGetSegments(m_object, &count); + + vector<Segment> result; + for (size_t i = 0; i < count; i++) + { + Segment segment; + segment.start = segments[i].start; + segment.length = segments[i].length; + segment.dataOffset = segments[i].dataOffset; + segment.dataLength = segments[i].dataLength; + segment.flags = segments[i].flags; + result.push_back(segment); + } + + BNFreeSegmentList(segments); + return result; +} + + +bool BinaryView::GetSegmentAt(uint64_t addr, Segment& result) +{ + BNSegment segment; + if (!BNGetSegmentAt(m_object, addr, &segment)) + return false; + + result.start = segment.start; + result.length = segment.length; + result.dataOffset = segment.dataOffset; + result.dataLength = segment.dataLength; + result.flags = segment.flags; + return true; +} + + +void BinaryView::AddAutoSection(const string& name, uint64_t start, uint64_t length, const string& type, + uint64_t align, uint64_t entrySize, const string& linkedSection, const string& infoSection, uint64_t infoData) +{ + BNAddAutoSection(m_object, name.c_str(), start, length, type.c_str(), align, entrySize, linkedSection.c_str(), + infoSection.c_str(), infoData); +} + + +void BinaryView::RemoveAutoSection(const string& name) +{ + BNRemoveAutoSection(m_object, name.c_str()); +} + + +void BinaryView::AddUserSection(const string& name, uint64_t start, uint64_t length, const string& type, + uint64_t align, uint64_t entrySize, const string& linkedSection, const string& infoSection, uint64_t infoData) +{ + BNAddUserSection(m_object, name.c_str(), start, length, type.c_str(), align, entrySize, linkedSection.c_str(), + infoSection.c_str(), infoData); +} + + +void BinaryView::RemoveUserSection(const string& name) +{ + BNRemoveUserSection(m_object, name.c_str()); +} + + +vector<Section> BinaryView::GetSections() +{ + size_t count; + BNSection* sections = BNGetSections(m_object, &count); + + vector<Section> result; + for (size_t i = 0; i < count; i++) + { + Section section; + section.name = sections[i].name; + section.type = sections[i].type; + section.start = sections[i].start; + section.length = sections[i].length; + section.linkedSection = sections[i].linkedSection; + section.infoSection = sections[i].infoSection; + section.infoData = sections[i].infoData; + section.align = sections[i].align; + section.entrySize = sections[i].entrySize; + result.push_back(section); + } + + BNFreeSectionList(sections, count); + return result; +} + + +vector<Section> BinaryView::GetSectionsAt(uint64_t addr) +{ + size_t count; + BNSection* sections = BNGetSectionsAt(m_object, addr, &count); + + vector<Section> result; + for (size_t i = 0; i < count; i++) + { + Section section; + section.name = sections[i].name; + section.type = sections[i].type; + section.start = sections[i].start; + section.length = sections[i].length; + section.linkedSection = sections[i].linkedSection; + section.infoSection = sections[i].infoSection; + section.infoData = sections[i].infoData; + section.align = sections[i].align; + section.entrySize = sections[i].entrySize; + result.push_back(section); + } + + BNFreeSectionList(sections, count); + return result; +} + + +bool BinaryView::GetSectionByName(const string& name, Section& result) +{ + BNSection section; + if (!BNGetSectionByName(m_object, name.c_str(), §ion)) + return false; + + result.name = section.name; + result.type = section.type; + result.start = section.start; + result.length = section.length; + result.linkedSection = section.linkedSection; + result.infoSection = section.infoSection; + result.infoData = section.infoData; + result.align = section.align; + result.entrySize = section.entrySize; + + BNFreeSection(§ion); + return true; +} + + +vector<string> BinaryView::GetUniqueSectionNames(const vector<string>& names) +{ + const char** incomingNames = new const char*[names.size()]; + for (size_t i = 0; i < names.size(); i++) + incomingNames[i] = names[i].c_str(); + + char** outgoingNames = BNGetUniqueSectionNames(m_object, incomingNames, names.size()); + vector<string> result; + for (size_t i = 0; i < names.size(); i++) + result.push_back(outgoingNames[i]); + + BNFreeStringList(outgoingNames, names.size()); + return result; +} + + +vector<BNAddressRange> BinaryView::GetAllocatedRanges() +{ + size_t count; + BNAddressRange* ranges = BNGetAllocatedRanges(m_object, &count); + + vector<BNAddressRange> result; + copy(&ranges[0], &ranges[count], back_inserter(result)); + BNFreeAddressRanges(ranges); + return result; +} + + BinaryData::BinaryData(FileMetadata* file): BinaryView(BNCreateBinaryDataView(file->GetObject())) { } diff --git a/python/__init__.py b/python/__init__.py index bfd2358f..70267678 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -300,7 +300,7 @@ class FileMetadata(object): view = core.BNGetFileViewOfType(self.handle, "Raw") if view is None: return None - return BinaryView(self, handle = view) + return BinaryView(file_metadata = self, handle = view) @property def saved(self): @@ -455,7 +455,7 @@ class FileMetadata(object): lambda ctxt, cur, total: progress_func(cur, total))) if view is None: return None - return BinaryView(self, handle = view) + return BinaryView(file_metadata = self, handle = view) def save_auto_snapshot(self, progress_func = None): if progress_func is None: @@ -474,7 +474,7 @@ class FileMetadata(object): view = core.BNCreateBinaryViewOfType(view_type, self.raw.handle) if view is None: return None - return BinaryView(self, handle = view) + return BinaryView(file_metadata = self, handle = view) def __setattr__(self, name, value): try: @@ -812,7 +812,7 @@ class BinaryViewType(object): view = core.BNCreateBinaryViewOfType(self.handle, data.handle) if view is None: return None - return BinaryView(data.file, handle = view) + return BinaryView(file_metadata = data.file, handle = view) def open(self, src, file_metadata = None): data = BinaryView.open(src, file_metadata) @@ -924,6 +924,64 @@ class DataVariable(object): def __repr__(self): return "<var 0x%x: %s>" % (self.address, str(self.type)) +class Segment(object): + def __init__(self, start, length, data_offset, data_length, flags): + self.start = start + self.length = length + self.data_offset = data_offset + self.data_length = data_length + self.flags = flags + + @property + def end(self): + return self.start + self.length + + def __len__(self): + return self.length + + def __repr__(self): + return "<segment: %#x-%#x, %s%s%s>" % (self.start, self.end, + "r" if (self.flags & core.SegmentReadable) != 0 else "-", + "w" if (self.flags & core.SegmentWritable) != 0 else "-", + "x" if (self.flags & core.SegmentExecutable) != 0 else "-") + +class Section(object): + def __init__(self, name, section_type, start, length, linked_section, info_section, info_data, align, entry_size): + self.name = name + self.type = section_type + self.start = start + self.length = length + self.linked_section = linked_section + self.info_section = info_section + self.info_data = info_data + self.align = align + self.entry_size = entry_size + + @property + def end(self): + return self.start + self.length + + def __len__(self): + return self.length + + def __repr__(self): + return "<section %s: %#x-%#x>" % (self.name, self.start, self.end) + +class AddressRange(object): + def __init__(self, start, end): + self.start = start + self.end = end + + @property + def length(self): + return self.end - self.start + + def __len__(self): + return self.end - self.start + + def __repr__(self): + return "<%#x-%#x>" % (self.start, self.end) + class _BinaryViewAssociatedDataStore(_AssociatedDataStore): _defaults = {} @@ -982,7 +1040,7 @@ class BinaryView(object): next_address = 0 _associated_data = {} - def __init__(self, file_metadata = None, handle = None): + def __init__(self, file_metadata = None, parent_view = None, handle = None): if handle is not None: self.handle = core.handle_of_type(handle, core.BNBinaryView) if file_metadata is None: @@ -1020,7 +1078,9 @@ class BinaryView(object): self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) self._cb.save = self._cb.save.__class__(self._save) self.file = file_metadata - self.handle = core.BNCreateCustomBinaryView(self.__class__.name, file_metadata.handle, self._cb) + if parent_view is not None: + parent_view = parent_view.handle + self.handle = core.BNCreateCustomBinaryView(self.__class__.name, file_metadata.handle, parent_view, self._cb) self.notifications = {} self.next_address = None # Do NOT try to access view before init() is called, use placeholder @@ -1042,7 +1102,7 @@ class BinaryView(object): def _create(cls, ctxt, data): try: file_metadata = FileMetadata(handle = core.BNGetFileForView(data)) - view = cls(BinaryView(file_metadata, handle = core.BNNewViewReference(data))) + view = cls(BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(data))) if view is None: return None return ctypes.cast(core.BNNewViewReference(view.handle), ctypes.c_void_p).value @@ -1053,7 +1113,7 @@ class BinaryView(object): @classmethod def _is_valid_for_data(cls, ctxt, data): try: - return cls.is_valid_for_data(BinaryView(None, handle = core.BNNewViewReference(data))) + return cls.is_valid_for_data(BinaryView(handle = core.BNNewViewReference(data))) except: log_error(traceback.format_exc()) return False @@ -1071,7 +1131,7 @@ class BinaryView(object): view = core.BNCreateBinaryDataViewFromFilename(file_metadata.handle, str(src)) if view is None: return None - result = BinaryView(file_metadata, handle = view) + result = BinaryView(file_metadata = file_metadata, handle = view) return result @classmethod @@ -1086,7 +1146,7 @@ class BinaryView(object): view = core.BNCreateBinaryDataViewFromBuffer(file_metadata.handle, buf.handle) if view is None: return None - result = BinaryView(file_metadata, handle = view) + result = BinaryView(file_metadata = file_metadata, handle = view) return result @classmethod @@ -1114,6 +1174,14 @@ class BinaryView(object): core.BNFreeFunctionList(funcs, count.value) @property + def parent_view(self): + """View that contains the raw data used by this view (read-only)""" + result = core.BNGetParentView(self.handle) + if result is None: + return None + return BinaryView(handle = result) + + @property def modified(self): """boolean modification state of the BinaryView (read/write)""" return self.file.modified @@ -1311,6 +1379,42 @@ class BinaryView(object): return result @property + def segments(self): + """List of segments (read-only)""" + count = ctypes.c_ulonglong(0) + segment_list = core.BNGetSegments(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append(Segment(segment_list[i].start, segment_list[i].length, + segment_list[i].dataOffset, segment_list[i].dataLength, segment_list[i].flags)) + core.BNFreeSegmentList(segment_list) + return result + + @property + def sections(self): + """List of sections (read-only)""" + count = ctypes.c_ulonglong(0) + section_list = core.BNGetSections(self.handle, count) + result = {} + for i in xrange(0, count.value): + result[section_list[i].name] = Section(section_list[i].name, section_list[i].type, section_list[i].start, + section_list[i].length, section_list[i].linkedSection, section_list[i].infoSection, + section_list[i].infoData, section_list[i].align, section_list[i].entrySize) + core.BNFreeSectionList(section_list, count.value) + return result + + @property + def allocated_ranges(self): + """List of valid address ranges for this view (read-only)""" + count = ctypes.c_ulonglong(0) + range_list = core.BNGetAllocatedRanges(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append(AddressRange(range_list[i].start, range_list[i].end)) + core.BNFreeAddressRanges(range_list) + return result + + @property def session_data(self): """Dictionary object where plugins can store arbitrary data associated with the view""" handle = ctypes.cast(self.handle, ctypes.c_void_p) @@ -1587,43 +1691,52 @@ class BinaryView(object): return None return ''.join(str(a) for a in txt).strip() - @abc.abstractmethod def perform_save(self, accessor): - raise NotImplementedError + if self.parent_view is not None: + return self.parent_view.save(accessor) + return False @abc.abstractmethod def perform_get_address_size(self): raise NotImplementedError - @abc.abstractmethod def perform_get_length(self): - raise NotImplementedError + """ + ``perform_get_length`` implements a query for the size of the virtual address range used by + the BinaryView. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :return: returns the size of the virtual address range used by the BinaryView. + :rtype: int + """ + return 0 - @abc.abstractmethod def perform_read(self, addr, length): """ ``perform_read`` implements a mapping between a virtual address and an absolute file offset, reading ``length`` bytes from the rebased address ``addr``. - .. note:: This method must be overridden by custom BinaryViews if they have segments or the virtual address is\ - different from the physical address. + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :param int addr: a virtual address to attempt to read from :param int length: the number of bytes to be read :return: length bytes read from addr, should return empty string on error - :rtype: int + :rtype: str """ - raise NotImplementedError + return "" - @abc.abstractmethod def perform_write(self, addr, data): """ ``perform_write`` implements a mapping between a virtual address and an absolute file offset, writing the bytes ``data`` to rebased address ``addr``. - .. note:: This method must be overridden by custom BinaryViews if they have segments or the virtual address is \ - different from the physical address. + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :param int addr: a virtual address @@ -1631,16 +1744,14 @@ class BinaryView(object): :return: length of data written, should return 0 on error :rtype: int """ - raise NotImplementedError + return 0 - @abc.abstractmethod def perform_insert(self, addr, data): """ ``perform_insert`` implements a mapping between a virtual address and an absolute file offset, inserting the bytes ``data`` to rebased address ``addr``. - .. note:: This method must be overridden by custom BinaryViews if they have segments or the virtual address is \ - different from the physical address. + .. note:: This method **may** be overridden by custom BinaryViews. If not overridden, inserting is disallowed .. warning:: This method **must not** be called directly. :param int addr: a virtual address @@ -1648,16 +1759,14 @@ class BinaryView(object): :return: length of data inserted, should return 0 on error :rtype: int """ - raise NotImplementedError + return 0 - @abc.abstractmethod def perform_remove(self, addr, length): """ ``perform_remove`` implements a mapping between a virtual address and an absolute file offset, removing ``length`` bytes from the rebased address ``addr``. - .. note:: This method must be overridden by custom BinaryViews if they have segments or the virtual address is \ - different from the physical address. + .. note:: This method **may** be overridden by custom BinaryViews. If not overridden, removing data is disallowed .. warning:: This method **must not** be called directly. :param int addr: a virtual address @@ -1665,14 +1774,14 @@ class BinaryView(object): :return: length of data removed, should return 0 on error :rtype: int """ - raise NotImplementedError + return 0 - @abc.abstractmethod def perform_get_modification(self, addr): """ ``perform_get_modification`` implements query to the whether the virtual address ``addr`` is modified. - .. note:: This method **may** be overridden by custom BinaryViews. + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :param int addr: a virtual address to be checked @@ -1681,13 +1790,12 @@ class BinaryView(object): """ return core.Original - @abc.abstractmethod def perform_is_valid_offset(self, addr): """ ``perform_is_valid_offset`` implements a check if an virtual address ``addr`` is valid. - .. note:: This method **must** be implemented for custom BinaryViews whose virtual addresses differ from \ - physical file offsets. + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :param int addr: a virtual address to be checked @@ -1697,13 +1805,12 @@ class BinaryView(object): data = self.read(addr, 1) return (data is not None) and (len(data) == 1) - @abc.abstractmethod def perform_is_offset_readable(self, offset): """ ``perform_is_offset_readable`` implements a check if an virtual address is readable. - .. note:: This method **must** be implemented for custom BinaryViews whose virtual addresses differ from \ - physical file offsets, or if memory protections exist. + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :param int offset: a virtual address to be checked @@ -1712,13 +1819,12 @@ class BinaryView(object): """ return self.is_valid_offset(offset) - @abc.abstractmethod def perform_is_offset_writable(self, addr): """ ``perform_is_offset_writable`` implements a check if a virtual address ``addr`` is writable. - .. note:: This method **must** be implemented for custom BinaryViews whose virtual addresses differ from \ - physical file offsets, or if memory protections exist. + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :param int addr: a virtual address to be checked @@ -1727,13 +1833,12 @@ class BinaryView(object): """ return self.is_valid_offset(addr) - @abc.abstractmethod def perform_is_offset_executable(self, addr): """ ``perform_is_offset_writable`` implements a check if a virtual address ``addr`` is executable. - .. note:: This method **must** be implemented for custom BinaryViews whose virtual addresses differ from \ - physical file offsets, or if memory protections exist. + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :param int addr: a virtual address to be checked @@ -1742,13 +1847,13 @@ class BinaryView(object): """ return self.is_valid_offset(addr) - @abc.abstractmethod def perform_get_next_valid_offset(self, addr): """ ``perform_get_next_valid_offset`` implements a query for the next valid readable, writable, or executable virtual memory address. - .. note:: This method **may** be implemented by custom BinaryViews + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :param int addr: a virtual address to start checking from. @@ -1759,13 +1864,13 @@ class BinaryView(object): return self.perform_get_start() return addr - @abc.abstractmethod def perform_get_start(self): """ ``perform_get_start`` implements a query for the first readable, writable, or executable virtual address in the BinaryView. - .. note:: This method **may** be implemented by custom BinaryViews + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. .. warning:: This method **must not** be called directly. :return: returns the first virtual address in the BinaryView. @@ -1773,7 +1878,6 @@ class BinaryView(object): """ return 0 - @abc.abstractmethod def perform_get_entry_point(self): """ ``perform_get_entry_point`` implements a query for the initial entry point for code execution. @@ -1786,7 +1890,6 @@ class BinaryView(object): """ return 0 - @abc.abstractmethod def perform_is_executable(self): """ ``perform_is_executable`` implements a check which returns true if the BinaryView is executable. @@ -1797,9 +1900,8 @@ class BinaryView(object): :return: true if the current BinaryView is executable, false if it is not executable or on error :rtype: bool """ - raise NotImplementedError + return False - @abc.abstractmethod def perform_get_default_endianness(self): """ ``perform_get_default_endianness`` implements a check which returns true if the BinaryView is executable. @@ -2868,7 +2970,7 @@ class BinaryView(object): result = [] for i in xrange(0, count.value): result.append(StringReference(core.BNStringType_names[strings[i].type], strings[i].start, strings[i].length)) - core.BNFreeStringList(strings) + core.BNFreeStringReferenceList(strings) return result def add_analysis_completion_event(self, callback): @@ -3387,6 +3489,73 @@ class BinaryView(object): return None return value.value + def add_auto_segment(self, start, length, data_offset, data_length, flags): + core.BNAddAutoSegment(self.handle, start, length, data_offset, data_length, flags) + + def remove_auto_segment(self, start, length): + core.BNRemoveAutoSegment(self.handle, start, length) + + def add_user_segment(self, start, length, data_offset, data_length, flags): + core.BNAddUserSegment(self.handle, start, length, data_offset, data_length, flags) + + def remove_user_segment(self, start, length): + core.BNRemoveUserSegment(self.handle, start, length) + + def get_segment_at(self, addr): + segment = core.BNSegment() + if not core.BNGetSegmentAt(self.handle, addr, segment): + return None + result = Segment(segment.start, segment.length, segment.dataOffset, segment.dataLength, + segment.flags) + return result + + def add_auto_section(self, name, start, length, type = "", align = 1, entry_size = 1, linked_section = "", + info_section = "", info_data = 0): + core.BNAddAutoSection(self.handle, name, start, length, type, align, entry_size, linked_section, + info_section, info_data) + + def remove_auto_section(self, name): + core.BNRemoveAutoSection(self.handle, name) + + def add_user_section(self, name, start, length, type = "", align = 1, entry_size = 1, linked_section = "", + info_section = "", info_data = 0): + core.BNAddUserSection(self.handle, name, start, length, type, align, entry_size, linked_section, + info_section, info_data) + + def remove_user_section(self, name): + core.BNRemoveUserSection(self.handle, name) + + def get_sections_at(self, addr): + count = ctypes.c_ulonglong(0) + section_list = core.BNGetSectionsAt(self.handle, addr, count) + result = [] + for i in xrange(0, count.value): + result.append(Section(section_list[i].name, section_list[i].type, section_list[i].start, + section_list[i].length, section_list[i].linkedSection, section_list[i].infoSection, + section_list[i].infoData, section_list[i].align, section_list[i].entrySize)) + core.BNFreeSectionList(section_list, count.value) + return result + + def get_section_by_name(self, name): + section = core.BNSection() + if not core.BNGetSectionByName(self.handle, name, section): + return None + result = Section(section.name, section.type, section.start, section.length, section.linkedSection, + section.infoSection, section.infoData, section.align, section.entrySize) + core.BNFreeSection(section) + return result + + def get_unique_section_names(self, name_list): + incoming_names = (ctypes.c_char_p * len(name_list))() + for i in xrange(0, len(name_list)): + incoming_names[i] = name_list[i] + outgoing_names = core.BNGetUniqueSectionNames(self.handle, incoming_names, len(name_list)) + result = [] + for i in xrange(0, len(name_list)): + result.append(str(outgoing_names[i])) + core.BNFreeStringList(outgoing_names, len(name_list)) + return result + def __setattr__(self, name, value): try: object.__setattr__(self,name,value) @@ -5270,7 +5439,7 @@ class FunctionGraphBlock(object): core.BNFreeBasicBlock(block) block = None else: - block = BasicBlock(BinaryView(None, handle = core.BNGetFunctionData(func)), block) + block = BasicBlock(BinaryView(handle = core.BNGetFunctionData(func)), block) core.BNFreeFunction(func) return block @@ -8723,7 +8892,7 @@ class FunctionRecognizer(object): def _recognize_low_level_il(self, ctxt, data, func, il): try: file_metadata = FileMetadata(handle = core.BNGetFileForView(data)) - view = BinaryView(file_metadata, handle = core.BNNewViewReference(data)) + view = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(data)) func = Function(view, handle = core.BNNewFunctionReference(func)) il = LowLevelILFunction(func.arch, handle = core.BNNewLowLevelILFunctionReference(il)) return self.recognize_low_level_il(view, func, il) @@ -8960,7 +9129,7 @@ class PluginCommand: def _default_action(cls, view, action): try: file_metadata = FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view)) + view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) action(view_obj) except: log_error(traceback.format_exc()) @@ -8969,7 +9138,7 @@ class PluginCommand: def _address_action(cls, view, addr, action): try: file_metadata = FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view)) + view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) action(view_obj, addr) except: log_error(traceback.format_exc()) @@ -8978,7 +9147,7 @@ class PluginCommand: def _range_action(cls, view, addr, length, action): try: file_metadata = FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view)) + view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) action(view_obj, addr, length) except: log_error(traceback.format_exc()) @@ -8987,7 +9156,7 @@ class PluginCommand: def _function_action(cls, view, func, action): try: file_metadata = FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view)) + view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) func_obj = Function(view_obj, core.BNNewFunctionReference(func)) action(view_obj, func_obj) except: @@ -8999,7 +9168,7 @@ class PluginCommand: if is_valid is None: return True file_metadata = FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view)) + view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) return is_valid(view_obj) except: log_error(traceback.format_exc()) @@ -9011,7 +9180,7 @@ class PluginCommand: if is_valid is None: return True file_metadata = FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view)) + view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) return is_valid(view_obj, addr) except: log_error(traceback.format_exc()) @@ -9023,7 +9192,7 @@ class PluginCommand: if is_valid is None: return True file_metadata = FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view)) + view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) return is_valid(view_obj, addr, length) except: log_error(traceback.format_exc()) @@ -9035,7 +9204,7 @@ class PluginCommand: if is_valid is None: return True file_metadata = FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view)) + view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) func_obj = Function(view_obj, core.BNNewFunctionReference(func)) return is_valid(view_obj, func_obj) except: @@ -9599,7 +9768,7 @@ class ScriptingInstance(object): def _set_current_binary_view(self, ctxt, view): try: if view: - view = BinaryView(None, handle = core.BNNewViewReference(view)) + view = BinaryView(handle = core.BNNewViewReference(view)) else: view = None self.perform_set_current_binary_view(view) @@ -9609,7 +9778,7 @@ class ScriptingInstance(object): def _set_current_function(self, ctxt, func): try: if func: - func = Function(BinaryView(None, handle = core.BNGetFunctionData(func)), core.BNNewFunctionReference(func)) + func = Function(BinaryView(handle = core.BNGetFunctionData(func)), core.BNNewFunctionReference(func)) else: func = None self.perform_set_current_function(func) @@ -9623,7 +9792,7 @@ class ScriptingInstance(object): if func is None: block = None else: - block = BasicBlock(BinaryView(None, handle = core.BNGetFunctionData(func)), core.BNNewBasicBlockReference(block)) + block = BasicBlock(BinaryView(handle = core.BNGetFunctionData(func)), core.BNNewBasicBlockReference(block)) core.BNFreeFunction(func) else: block = None @@ -10373,7 +10542,7 @@ class InteractionHandler(object): def _show_plain_text_report(self, ctxt, view, title, contents): try: if view: - view = BinaryView(None, handle = core.BNNewViewReference(view)) + view = BinaryView(handle = core.BNNewViewReference(view)) else: view = None self.show_plain_text_report(view, title, contents) @@ -10383,7 +10552,7 @@ class InteractionHandler(object): def _show_markdown_report(self, ctxt, view, title, contents, plaintext): try: if view: - view = BinaryView(None, handle = core.BNNewViewReference(view)) + view = BinaryView(handle = core.BNNewViewReference(view)) else: view = None self.show_markdown_report(view, title, contents, plaintext) @@ -10393,7 +10562,7 @@ class InteractionHandler(object): def _show_html_report(self, ctxt, view, title, contents, plaintext): try: if view: - view = BinaryView(None, handle = core.BNNewViewReference(view)) + view = BinaryView(handle = core.BNNewViewReference(view)) else: view = None self.show_html_report(view, title, contents, plaintext) @@ -10423,7 +10592,7 @@ class InteractionHandler(object): def _get_address_input(self, ctxt, result, prompt, title, view, current_address): try: if view: - view = BinaryView(None, handle = core.BNNewViewReference(view)) + view = BinaryView(handle = core.BNNewViewReference(view)) else: view = None value = self.get_address_input(prompt, title, view, current_address) @@ -10494,7 +10663,7 @@ class InteractionHandler(object): elif fields[i].type == core.AddressFormField: view = None if fields[i].view: - view = BinaryView(None, handle = core.BNNewViewReference(fields[i].view)) + view = BinaryView(handle = core.BNNewViewReference(fields[i].view)) field_objs.append(AddressField(fields[i].prompt, view, fields[i].currentAddress)) elif fields[i].type == core.ChoiceFormField: choices = [] diff --git a/python/examples/nds.py b/python/examples/nds.py new file mode 100644 index 00000000..5300018c --- /dev/null +++ b/python/examples/nds.py @@ -0,0 +1,88 @@ +from binaryninja import *
+import struct
+import traceback
+import os
+
+def crc16(data):
+ crc = 0xffff
+ for ch in data:
+ crc ^= ord(ch)
+ for bit in xrange(0, 8):
+ if (crc & 1) == 1:
+ crc = (crc >> 1) ^ 0xa001
+ else:
+ crc >>= 1
+ return crc
+
+class DSView(BinaryView):
+ def __init__(self, data):
+ BinaryView.__init__(self, file_metadata = data.file, parent_view = data)
+ self.raw = data
+
+ @classmethod
+ def is_valid_for_data(self, data):
+ hdr = data.read(0, 0x160)
+ if len(hdr) < 0x160:
+ return False
+ if struct.unpack("<H", hdr[0x15e:0x160])[0] != crc16(hdr[0:0x15e]):
+ return False
+ if struct.unpack("<H", hdr[0x15c:0x15e])[0] != crc16(hdr[0xc0:0x15c]):
+ return False
+ return True
+
+ def init_common(self):
+ self.platform = Architecture["armv7"].standalone_platform
+ self.hdr = self.raw.read(0, 0x160)
+
+ def init_arm9(self):
+ try:
+ self.init_common()
+ self.arm9_offset = struct.unpack("<L", self.hdr[0x20:0x24])[0]
+ self.arm_entry_addr = struct.unpack("<L", self.hdr[0x24:0x28])[0]
+ self.arm9_load_addr = struct.unpack("<L", self.hdr[0x28:0x2C])[0]
+ self.arm9_size = struct.unpack("<L", self.hdr[0x2C:0x30])[0]
+ self.add_auto_segment(self.arm9_load_addr, self.arm9_size, self.arm9_offset, self.arm9_size,
+ SegmentReadable | SegmentExecutable)
+ self.add_entry_point(Architecture['armv7'].standalone_platform, self.arm_entry_addr)
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def init_arm7(self):
+ try:
+ self.init_common()
+ self.arm7_offset = struct.unpack("<L", self.hdr[0x30:0x34])[0]
+ self.arm_entry_addr = struct.unpack("<L", self.hdr[0x34:0x38])[0]
+ self.arm7_load_addr = struct.unpack("<L", self.hdr[0x38:0x3C])[0]
+ self.arm7_size = struct.unpack("<L", self.hdr[0x3C:0x40])[0]
+ self.add_auto_segment(self.arm7_load_addr, self.arm7_size, self.arm7_offset, self.arm7_size,
+ SegmentReadable | SegmentExecutable)
+ self.add_entry_point(Architecture['armv7'].standalone_platform, self.arm_entry_addr)
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def perform_is_executable(self):
+ return True
+
+ def perform_get_entry_point(self):
+ return self.arm_entry_addr
+
+class DSARM9View(DSView):
+ name = "DSARM9"
+ long_name = "DS ARM9 ROM"
+
+ def init(self):
+ return self.init_arm9()
+
+class DSARM7View(DSView):
+ name = "DSARM7"
+ long_name = "DS ARM7 ROM"
+
+ def init(self):
+ return self.init_arm7()
+
+DSARM9View.register()
+DSARM7View.register()
diff --git a/python/examples/nes.py b/python/examples/nes.py index 00f9d8eb..23f5f3d8 100644 --- a/python/examples/nes.py +++ b/python/examples/nes.py @@ -488,42 +488,12 @@ class M6502(Architecture): return None return "\xa9" + chr(value & 0xff) + "\xea" -class NESViewUpdateNotification(BinaryDataNotification): - def __init__(self, view): - self.view = view - - def data_written(self, view, offset, length): - addr = offset - self.view.rom_offset - while length > 0: - bank_ofs = addr & 0x3fff - if (bank_ofs + length) > 0x4000: - to_read = 0x4000 - bank_ofs - else: - to_read = length - if length < to_read: - to_read = length - if (addr >= (bank_ofs + (self.view.__class__.bank * 0x4000))) and (addr < (bank_ofs + ((self.view.__class__.bank + 1) * 0x4000))): - self.view.notify_data_written(0x8000 + bank_ofs, to_read) - elif (addr >= (bank_ofs + (self.view.rom_length - 0x4000))) and (addr < (bank_ofs + self.view.rom_length)): - self.view.notify_data_written(0xc000 + bank_ofs, to_read) - length -= to_read - addr += to_read - - def data_inserted(self, view, offset, length): - self.view.notify_data_written(0x8000, 0x8000) - - def data_removed(self, view, offset, length): - self.view.notify_data_written(0x8000, 0x8000) - class NESView(BinaryView): name = "NES" long_name = "NES ROM" def __init__(self, data): - BinaryView.__init__(self, data.file) - self.raw = data - self.notification = NESViewUpdateNotification(self) - self.raw.register_notification(self.notification) + BinaryView.__init__(self, parent_view = data, file_metadata = data.file) @classmethod def is_valid_for_data(self, data): @@ -539,7 +509,7 @@ class NESView(BinaryView): def init(self): try: - hdr = self.raw.read(0, 16) + hdr = self.parent_view.read(0, 16) self.rom_banks = struct.unpack("B", hdr[4])[0] self.vrom_banks = struct.unpack("B", hdr[5])[0] self.rom_flags = struct.unpack("B", hdr[6])[0] @@ -550,6 +520,15 @@ class NESView(BinaryView): self.rom_offset += 512 self.rom_length = self.rom_banks * 0x4000 + # Add mapping for RAM and hardware registers, not backed by file contents + self.add_auto_segment(0, 0x8000, 0, 0, SegmentReadable | SegmentWritable | SegmentExecutable) + + # Add ROM mappings + self.add_auto_segment(0x8000, 0x4000, self.rom_offset + (self.__class__.bank * 0x4000), 0x4000, + SegmentReadable | SegmentExecutable) + self.add_auto_segment(0xc000, 0x4000, self.rom_offset + self.rom_length - 0x4000, 0x4000, + SegmentReadable | SegmentExecutable) + nmi = struct.unpack("<H", self.read(0xfffa, 2))[0] start = struct.unpack("<H", self.read(0xfffc, 2))[0] irq = struct.unpack("<H", self.read(0xfffe, 2))[0] @@ -592,9 +571,9 @@ class NESView(BinaryView): self.define_auto_symbol(Symbol(DataSymbol, 0x4016, "JOY1")) self.define_auto_symbol(Symbol(DataSymbol, 0x4017, "JOY2")) - sym_files = [self.raw.file.filename + ".%x.nl" % self.__class__.bank, - self.raw.file.filename + ".ram.nl", - self.raw.file.filename + ".%x.nl" % (self.rom_banks - 1)] + sym_files = [self.file.filename + ".%x.nl" % self.__class__.bank, + self.file.filename + ".ram.nl", + self.file.filename + ".%x.nl" % (self.rom_banks - 1)] for f in sym_files: if os.path.exists(f): sym_contents = open(f, "r").read() @@ -614,71 +593,6 @@ class NESView(BinaryView): log_error(traceback.format_exc()) return False - def perform_is_valid_offset(self, addr): - if (addr >= 0x8000) and (addr < 0x10000): - return True - return False - - def perform_read(self, addr, length): - if addr < 0x8000: - return None - if addr >= (0x8000 + self.rom_length): - return None - if (addr + length) > 0x10000: - length = 0x10000 - addr - result = "" - while length > 0: - bank_ofs = addr & 0x3fff - if (bank_ofs + length) > 0x4000: - to_read = 0x4000 - bank_ofs - else: - to_read = length - if addr < 0xc000: - data = self.raw.read(self.rom_offset + bank_ofs + (self.__class__.bank * 0x4000), to_read) - else: - data = self.raw.read(self.rom_offset + bank_ofs + self.rom_length - 0x4000, to_read) - result += data - if len(data) < to_read: - break - length -= to_read - addr += to_read - return result - - def perform_write(self, addr, value): - if addr < 0x8000: - return 0 - if addr >= (0x8000 + self.rom_length): - return 0 - if (addr + len(value)) > (0x8000 + self.rom_length): - length = (0x8000 + self.rom_length) - addr - else: - length = len(value) - if (addr + length) > 0x10000: - length = 0x10000 - addr - offset = 0 - while length > 0: - bank_ofs = addr & 0x3fff - if (bank_ofs + length) > 0x4000: - to_write = 0x4000 - bank_ofs - else: - to_write = length - if addr < 0xc000: - written = self.raw.write(self.rom_offset + bank_ofs + (self.__class__.bank * 0x4000), value[offset : offset + to_write]) - else: - written = self.raw.write(self.rom_offset + bank_ofs + self.rom_length - 0x4000, value[offset : offset + to_write]) - if written < to_write: - break - length -= to_write - addr += to_write - offset += to_write - return offset - - def perform_get_start(self): - return 0 - - def perform_get_length(self): - return 0x10000 - def perform_is_executable(self): return True |
