summaryrefslogtreecommitdiff
path: root/python/examples
diff options
context:
space:
mode:
authorRusty Wagner <rusty@vector35.com>2016-12-01 18:13:54 -0500
committerRusty Wagner <rusty@vector35.com>2016-12-01 18:13:54 -0500
commit8c42dabe92340b4d342f3b4e7594fb70f1890e41 (patch)
tree406a4a0e0486b00a71b3d0bb65a3dd15cdf91981 /python/examples
parentf69430aedd957f5e8f221488cd6acb9031d3c1c1 (diff)
parent3b719e990e3e01242918bf66d5a1fb6032517641 (diff)
Merge branch 'dev'
Diffstat (limited to 'python/examples')
-rw-r--r--python/examples/nds.py88
-rw-r--r--python/examples/nes.py114
-rw-r--r--python/examples/nsf.py138
3 files changed, 240 insertions, 100 deletions
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()