diff options
Diffstat (limited to 'python/examples')
| -rw-r--r-- | python/examples/nds.py | 88 | ||||
| -rw-r--r-- | python/examples/nes.py | 114 | ||||
| -rw-r--r-- | python/examples/nsf.py | 138 |
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() |
