summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRusty Wagner <rusty@vector35.com>2016-10-10 21:28:16 -0400
committerRusty Wagner <rusty@vector35.com>2016-10-10 21:28:16 -0400
commit7e4cbbbf09e8dcda20f552a937b458aa09c28cf9 (patch)
tree95e0ef73cddbf83936d772a3f0bec64ce6d8c8a3
parent70dd487931d7bcd75e10753a741fba3299488327 (diff)
parentcf7832b8025c9acee11304bec0540f8896d56299 (diff)
Merge branch 'segments' into dev
-rw-r--r--binaryninjaapi.h45
-rw-r--r--binaryninjacore.h81
-rw-r--r--binaryview.cpp220
-rw-r--r--python/__init__.py313
-rw-r--r--python/examples/nds.py88
-rw-r--r--python/examples/nes.py114
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(), &section))
+ 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(&section);
+ 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