summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/__init__.py434
-rw-r--r--python/examples/nds.py88
-rw-r--r--python/examples/nes.py114
-rw-r--r--python/examples/nsf.py138
4 files changed, 593 insertions, 181 deletions
diff --git a/python/__init__.py b/python/__init__.py
index 087c31af..9afd22c2 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
@@ -1097,6 +1157,16 @@ class BinaryView(object):
@classmethod
def set_default_session_data(cls, name, value):
+ """
+ ```set_default_session_data``` saves a variable to the BinaryView.
+ :param name: name of the variable to be saved
+ :param value: value of the variable to be saved
+
+ :Example:
+ >>> BinaryView.set_default_session_data("variable_name", "value")
+ >>> bv.session_data.variable_name
+ 'value'
+ """
_BinaryViewAssociatedDataStore.set_default(name, value)
def __del__(self):
@@ -1114,6 +1184,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 +1389,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 +1701,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 +1754,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 +1769,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 +1784,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 +1800,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 +1815,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 +1829,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 +1843,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 +1857,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 +1874,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 +1888,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 +1900,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 +1910,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.
@@ -2388,6 +2500,19 @@ class BinaryView(object):
return BasicBlock(self, block)
def get_code_refs(self, addr, length = None):
+ """
+ ``get_code_refs`` returns a list of ReferenceSource objects (xrefs or cross-references) that point to the provided virtual address.
+
+ :param int addr: virtual address to query for references
+ :return: List of References for the given virtual address
+ :rtype: list(ReferenceSource)
+ :Example:
+
+ >>> bv.get_code_refs(here)
+ [<ref: x86@0x4165ff>]
+ >>>
+
+ """
count = ctypes.c_ulonglong(0)
if length is None:
refs = core.BNGetCodeReferences(self.handle, addr, count)
@@ -2528,6 +2653,21 @@ class BinaryView(object):
"""
core.BNDefineAutoSymbol(self.handle, sym.handle)
+ def define_auto_symbol_and_var_or_function(self, sym, sym_type, platform = None):
+ """
+ ``define_auto_symbol`` adds a symbol to the internal list of automatically discovered Symbol objects.
+
+ :param Symbol sym: the symbol to define
+ :rtype: None
+ """
+ if platform is None:
+ platform = self.platform
+ if platform is not None:
+ platform = platform.handle
+ if sym_type is not None:
+ sym_type = sym_type.handle
+ core.BNDefineAutoSymbolAndVariableOrFunction(self.handle, platform, sym.handle, sym_type)
+
def undefine_auto_symbol(self, sym):
"""
``undefine_auto_symbol`` removes a symbol from the internal list of automatically discovered Symbol objects.
@@ -2868,7 +3008,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 +3527,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)
@@ -3799,7 +4006,7 @@ class BinaryWriter(object):
def write16(self, value):
"""
- ```` writes the lowest order two bytes from the integer ``value`` to the current offset, using internal endianness.
+ ``write16`` writes the lowest order two bytes from the integer ``value`` to the current offset, using internal endianness.
:param int value: integer value to write.
:return: boolean True on success, False on failure.
@@ -3809,7 +4016,7 @@ class BinaryWriter(object):
def write32(self, value):
"""
- ```` writes the lowest order four bytes from the integer ``value`` to the current offset, using internal endianness.
+ ``write32`` writes the lowest order four bytes from the integer ``value`` to the current offset, using internal endianness.
:param int value: integer value to write.
:return: boolean True on success, False on failure.
@@ -3819,7 +4026,7 @@ class BinaryWriter(object):
def write64(self, value):
"""
- ```` writes the lowest order eight bytes from the integer ``value`` to the current offset, using internal endianness.
+ ``write64`` writes the lowest order eight bytes from the integer ``value`` to the current offset, using internal endianness.
:param int value: integer value to write.
:return: boolean True on success, False on failure.
@@ -4135,14 +4342,16 @@ class Type(object):
return Type(core.BNCreateBoolType())
@classmethod
- def int(self, width, sign = True):
+ def int(self, width, sign = True, altname = ""):
"""
``int`` class method for creating an int Type.
:param int width: width of the integer in bytes
:param bool sign: optional variable representing signedness
+ :param str altname: optional name of integer type
"""
- return Type(core.BNCreateIntegerType(width, sign))
+ return Type(core.BNCreateIntegerType(width, sign,
+ ctypes.create_string_buffer(altname)))
@classmethod
def float(self, width):
@@ -4157,6 +4366,10 @@ class Type(object):
return Type(core.BNCreateUnknownType(unknown_type.handle))
@classmethod
+ def unknown_type(self, s):
+ return Type(core.BNCreateUnknownType(s.handle))
+
+ @classmethod
def enumeration_type(self, arch, e, width = None):
if width is None:
width = arch.default_int_size
@@ -4174,12 +4387,12 @@ class Type(object):
def function(self, ret, params, calling_convention = None, variable_arguments = False):
"""
``function`` class method for creating an function Type.
-
+
:param Type ret: width of the integer in bytes
:param list(Type) params: list of parameter Types
:param CallingConvention calling_convention: optional argument for function calling convention
:param bool variable_arguments: optional argument for functions that have a variable number of arguments
-
+
"""
param_buf = (core.BNNameAndType * len(params))()
for i in xrange(0, len(params)):
@@ -4631,6 +4844,14 @@ class Function(object):
return Architecture(arch)
@property
+ def platform(self):
+ """Function platform (read-only)"""
+ platform = core.BNGetFunctionPlatform(self.handle)
+ if platform is None:
+ return None
+ return Platform(None, handle = platform)
+
+ @property
def start(self):
"""Function start (read-only)"""
return core.BNGetFunctionStart(self.handle)
@@ -5281,7 +5502,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
@@ -5853,6 +6074,8 @@ class Architecture(object):
self._cb.getDefaultIntegerSize = self._cb.getDefaultIntegerSize.__class__(self._get_default_integer_size)
self._cb.getMaxInstructionLength = self._cb.getMaxInstructionLength.__class__(self._get_max_instruction_length)
self._cb.getOpcodeDisplayLength = self._cb.getOpcodeDisplayLength.__class__(self._get_opcode_display_length)
+ self._cb.getAssociatedArchitectureByAddress = self._cb.getAssociatedArchitectureByAddress.__class__(
+ self._get_associated_arch_by_address)
self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__(self._get_instruction_info)
self._cb.getInstructionText = self._cb.getInstructionText.__class__(self._get_instruction_text)
self._cb.freeInstructionText = self._cb.freeInstructionText.__class__(self._free_instruction_text)
@@ -6042,6 +6265,15 @@ class Architecture(object):
log_error(traceback.format_exc())
return 8
+ def _get_associated_arch_by_address(self, ctxt, addr):
+ try:
+ result, new_addr = self.perform_get_associated_arch_by_address(addr[0])
+ addr[0] = new_addr
+ return ctypes.cast(result.handle, ctypes.c_void_p).value
+ except:
+ log_error(traceback.format_exc())
+ return ctypes.cast(self.handle, ctypes.c_void_p).value
+
def _get_instruction_info(self, ctxt, data, addr, max_len, result):
try:
buf = ctypes.create_string_buffer(max_len)
@@ -6451,6 +6683,9 @@ class Architecture(object):
log_error(traceback.format_exc())
return False
+ def perform_get_associated_arch_by_address(self, addr):
+ return self, addr
+
@abc.abstractmethod
def perform_get_instruction_info(self, data, addr):
"""
@@ -6701,6 +6936,12 @@ class Architecture(object):
"""
return None
+ def get_associated_arch_by_address(self, addr):
+ new_addr = ctypes.c_ulonglong()
+ new_addr.value = addr
+ result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr)
+ return Architecture(handle = result), new_addr.value
+
def get_instruction_info(self, data, addr):
"""
``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address
@@ -8133,16 +8374,17 @@ class LowLevelILFunction(object):
"""
return self.expr(core.LLIL_NOT, value.index, size = size, flags = flags)
- def sign_extend(self, size, value):
+ def sign_extend(self, size, value, flags = None):
"""
``sign_extend`` two's complement sign-extends the expression in ``value`` to ``size`` bytes
:param int size: the size of the result in bytes
:param LowLevelILExpr value: the expression to sign extend
+ :param str flags: optional, flags to set
:return: The expression ``sx.<size>(value)``
:rtype: LowLevelILExpr
"""
- return self.expr(core.LLIL_SX, value.index, size = size)
+ return self.expr(core.LLIL_SX, value.index, size = size, flags = flags)
def zero_extend(self, size, value):
"""
@@ -8734,7 +8976,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)
@@ -8971,7 +9213,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())
@@ -8980,7 +9222,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())
@@ -8989,7 +9231,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())
@@ -8998,7 +9240,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:
@@ -9010,7 +9252,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())
@@ -9022,7 +9264,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())
@@ -9034,7 +9276,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())
@@ -9046,7 +9288,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:
@@ -9535,6 +9777,21 @@ class Platform(object):
"""
core.BNRegisterPlatformCallingConvention(self.handle, cc.handle)
+ def get_related_platform(self, arch):
+ result = core.BNGetRelatedPlatform(self.handle, arch.handle)
+ if not result:
+ return None
+ return Platform(None, handle = result)
+
+ def add_related_platform(self, arch, platform):
+ core.BNAddRelatedPlatform(self.handle, arch.handle, platform.handle)
+
+ def get_associated_platform_by_address(self, addr):
+ new_addr = ctypes.c_ulonglong()
+ new_addr.value = addr
+ result = core.BNGetAssociatedPlatformByAddress(self.handle, new_addr)
+ return Platform(None, handle = result), new_addr.value
+
class ScriptingOutputListener(object):
def _register(self, handle):
self._cb = core.BNScriptingOutputListener()
@@ -9610,7 +9867,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)
@@ -9620,7 +9877,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)
@@ -9634,7 +9891,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
@@ -10384,7 +10641,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)
@@ -10394,7 +10651,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)
@@ -10404,7 +10661,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)
@@ -10434,7 +10691,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)
@@ -10505,7 +10762,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 = []
@@ -10854,6 +11111,21 @@ def demangle_ms(arch, mangled_name):
names.append(outName[i])
#core.BNFreeDemangledName(outName.value, outSize.value)
return (Type(handle), names)
+ return (None, mangledName)
+
+
+def demangle_gnu3(arch, mangled_name):
+ handle = ctypes.POINTER(core.BNType)()
+ outName = ctypes.POINTER(ctypes.c_char_p)()
+ outSize = ctypes.c_ulonglong()
+ names = []
+ if core.BNDemangleGNU3(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)):
+ for i in xrange(outSize.value):
+ names.append(outName[i])
+ #core.BNFreeDemangledName(outName.value, outSize.value)
+ if not handle:
+ return (None, names)
+ return (Type(handle), names)
return (None, mangled_name)
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
diff --git a/python/examples/nsf.py b/python/examples/nsf.py
new file mode 100644
index 00000000..9d4ebd5c
--- /dev/null
+++ b/python/examples/nsf.py
@@ -0,0 +1,138 @@
+# Copyright (c) 2015-2016 Vector 35 LLC
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+#
+# Simple NSF file loader, primarily for analyzing:
+# https://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-compromising-linux-desktop.html
+#
+
+from binaryninja import *
+import struct
+import traceback
+import os
+
+class NSFView(BinaryView):
+ name = "NSF"
+ long_name = "Nintendo Sound Format"
+
+ def __init__(self, data):
+ BinaryView.__init__(self, parent_view = data, file_metadata = data.file)
+
+ @classmethod
+ def is_valid_for_data(self, data):
+ hdr = data.read(0, 128)
+ if len(hdr) < 128:
+ return False
+ if hdr[0:5] != "NESM\x1a":
+ return False
+ song_count = struct.unpack("B", hdr[6])[0]
+ if song_count < 1:
+ log_info("Appears to be an NSF, but no songs.")
+ return False
+ return True
+
+ def init(self):
+ try:
+ hdr = self.parent_view.read(0, 128)
+ self.version = struct.unpack("B", hdr[5])[0]
+ self.song_count = struct.unpack("B", hdr[6])[0]
+ self.starting_song = struct.unpack("B", hdr[7])[0]
+ self.load_address = struct.unpack("<H", hdr[8:10])[0]
+ self.init_address = struct.unpack("<H", hdr[10:12])[0]
+ self.play_address = struct.unpack("<H", hdr[12:14])[0]
+ self.song_name = hdr[15].split('\0')[0]
+ self.artist_name = hdr[46].split('\0')[0]
+ self.copyright_name = hdr[78].split('\0')[0]
+ self.play_speed_ntsc = struct.unpack("<H", hdr[110:112])[0]
+ self.bank_switching = hdr[112:120]
+ self.play_speed_pal = struct.unpack("<H", hdr[120:122])[0]
+ self.pal_ntsc_bits = struct.unpack("B", hdr[122])[0]
+ self.pal = True if (self.pal_ntsc_bits & 1) == 1 else False
+ self.ntsc = not self.pal
+ if self.pal_ntsc_bits & 2 == 2:
+ self.pal = True
+ self.ntsc = True
+ self.extra_sound_bits = struct.unpack("B", hdr[123])[0]
+
+ if self.bank_switching == "\0"*8:
+ #no bank switching
+ self.load_address & 0xFFF
+ self.rom_offset = 128
+
+ else:
+ #bank switching not implemented
+ log_info("Bank switching not implemented in this loader.")
+
+ # 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, 0x4000,
+ SegmentReadable | SegmentExecutable)
+
+ self.define_auto_symbol(Symbol(FunctionSymbol, self.play_address, "_play"))
+ self.define_auto_symbol(Symbol(FunctionSymbol, self.init_address, "_init"))
+ self.add_entry_point(Architecture['6502'].standalone_platform, self.init_address)
+ self.add_function(Architecture['6502'].standalone_platform, self.play_address)
+
+ # Hardware registers
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2000, "PPUCTRL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2001, "PPUMASK"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2002, "PPUSTATUS"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2003, "OAMADDR"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2004, "OAMDATA"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2005, "PPUSCROLL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2006, "PPUADDR"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2007, "PPUDATA"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4000, "SQ1_VOL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4001, "SQ1_SWEEP"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4002, "SQ1_LO"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4003, "SQ1_HI"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4004, "SQ2_VOL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4005, "SQ2_SWEEP"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4006, "SQ2_LO"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4007, "SQ2_HI"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4008, "TRI_LINEAR"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400a, "TRI_LO"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400b, "TRI_HI"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400c, "NOISE_VOL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400e, "NOISE_LO"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400f, "NOISE_HI"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4010, "DMC_FREQ"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4011, "DMC_RAW"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4012, "DMC_START"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4013, "DMC_LEN"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4014, "OAMDMA"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4015, "SND_CHN"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4016, "JOY1"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4017, "JOY2"))
+
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def perform_is_executable(self):
+ return True
+
+ def perform_get_entry_point(self):
+ return struct.unpack("<H", str(self.perform_read(0x0a, 2)))[0]
+
+NSFView.register()