From a40f0e1e494af967a35ca4a8977596f4693b5c0e Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 29 Sep 2016 18:41:13 -0400 Subject: Adding APIs for segments and sections --- python/examples/nes.py | 114 ++++++------------------------------------------- 1 file changed, 14 insertions(+), 100 deletions(-) (limited to 'python/examples') 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("= 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 -- cgit v1.3.1 From cf7832b8025c9acee11304bec0540f8896d56299 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Sun, 9 Oct 2016 16:33:22 -0400 Subject: Added NDS parser as example for segment APIs --- python/examples/nds.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 python/examples/nds.py (limited to 'python/examples') 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(" Date: Mon, 10 Oct 2016 16:46:21 -0400 Subject: Rename data to session_data, as this API is per-session and not stored in the db --- python/__init__.py | 12 ++++++------ python/examples/angr_plugin.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'python/examples') diff --git a/python/__init__.py b/python/__init__.py index f5a46798..bfd2358f 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -243,7 +243,7 @@ class FileMetadata(object): del cls._associated_data[handle.value] @classmethod - def set_default_data(cls, name, value): + def set_default_session_data(cls, name, value): _FileMetadataAssociatedDataStore.set_default(name, value) @property @@ -324,7 +324,7 @@ class FileMetadata(object): self.nav = value @property - def data(self): + def session_data(self): """Dictionary object where plugins can store arbitrary data associated with the file""" handle = ctypes.cast(self.handle, ctypes.c_void_p) if handle.value not in FileMetadata._associated_data: @@ -1096,7 +1096,7 @@ class BinaryView(object): del cls._associated_data[handle.value] @classmethod - def set_default_data(cls, name, value): + def set_default_session_data(cls, name, value): _BinaryViewAssociatedDataStore.set_default(name, value) def __del__(self): @@ -1311,7 +1311,7 @@ class BinaryView(object): return result @property - def data(self): + 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) if handle.value not in BinaryView._associated_data: @@ -4589,7 +4589,7 @@ class Function(object): del cls._associated_data[handle.value] @classmethod - def set_default_data(cls, name, value): + def set_default_session_data(cls, name, value): _FunctionAssociatedDataStore.set_default(name, value) @property @@ -4717,7 +4717,7 @@ class Function(object): return result @property - def data(self): + def session_data(self): """Dictionary object where plugins can store arbitrary data associated with the function""" handle = ctypes.cast(self.handle, ctypes.c_void_p) if handle.value not in Function._associated_data: diff --git a/python/examples/angr_plugin.py b/python/examples/angr_plugin.py index 5d567511..c6e6f87d 100644 --- a/python/examples/angr_plugin.py +++ b/python/examples/angr_plugin.py @@ -21,8 +21,8 @@ import os logging.disable(logging.WARNING) # Create sets in the BinaryView's data field to store the desired path for each view -BinaryView.set_default_data("angr_find", set()) -BinaryView.set_default_data("angr_avoid", set()) +BinaryView.set_default_session_data("angr_find", set()) +BinaryView.set_default_session_data("angr_avoid", set()) def escaped_output(str): return '\n'.join([s.encode("string_escape") for s in str.split('\n')]) @@ -89,7 +89,7 @@ def find_instr(bv, addr): block.function.set_auto_instr_highlight(block.arch, addr, GreenHighlightColor) # Add the instruction to the list associated with the current view - bv.data.angr_find.add(addr) + bv.session_data.angr_find.add(addr) def avoid_instr(bv, addr): # Highlight the instruction in red @@ -99,17 +99,17 @@ def avoid_instr(bv, addr): block.function.set_auto_instr_highlight(block.arch, addr, RedHighlightColor) # Add the instruction to the list associated with the current view - bv.data.angr_avoid.add(addr) + bv.session_data.angr_avoid.add(addr) def solve(bv): - if len(bv.data.angr_find) == 0: + if len(bv.session_data.angr_find) == 0: show_message_box("Angr Solve", "You have not specified a goal instruction.\n\n" + "Please right click on the goal instruction and select \"Find Path to This Instruction\" to " + "continue.", OKButtonSet, ErrorIcon) return # Start a solver thread for the path associated with the view - s = Solver(bv.data.angr_find, bv.data.angr_avoid, bv) + s = Solver(bv.session_data.angr_find, bv.session_data.angr_avoid, bv) s.start() # Register commands for the user to interact with the plugin -- cgit v1.3.1 From de07cda2227dfa2cd560ebb1187e3aa3946a081f Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Mon, 14 Nov 2016 21:57:57 -0500 Subject: basic NSF loader --- python/examples/nsf.py | 138 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 python/examples/nsf.py (limited to 'python/examples') 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("