-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Also fixed bug in call_table_enum.py by removing the long type carried over from converting the code to python 2. Moreover, I've ran a linter against the code and addressed recommendations.
- Loading branch information
Brandon Miller
committed
Nov 28, 2020
1 parent
f53d5b9
commit f198143
Showing
6 changed files
with
97 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,35 @@ | ||
from binaryninja import * | ||
from genesis import * | ||
from binaryninja import PluginCommand | ||
from .genesis import GenesisChecksum, GenesisAssemble, GenesisCallTableEnum | ||
|
||
|
||
def checksum(view): | ||
checksum = GenesisChecksum(view) | ||
checksum.start() | ||
|
||
|
||
def assemble(view): | ||
assemble = GenesisAssemble(view) | ||
assemble.start() | ||
|
||
|
||
def call_table_enum(view): | ||
cte = GenesisCallTableEnum(view) | ||
cte.start() | ||
|
||
|
||
PluginCommand.register( | ||
'genesis: Fixup ROM checksum', | ||
'genesis: fixup ROM checksum', | ||
'Fixup the SEGA Genesis ROM checksum', | ||
checksum | ||
) | ||
|
||
PluginCommand.register( | ||
'genesis: Assemble and patch', | ||
'genesis: assemble and patch', | ||
'Assemble M68K code and apply blob as patch', | ||
assemble | ||
) | ||
PluginCommand.register( | ||
'genesis: Enumerate call tables', | ||
'genesis: enumerate call tables', | ||
'Locate and disassemble call tables', | ||
call_table_enum | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,13 @@ | ||
'''Assembles Motorola 68000 code and drops the blob at the specified offset | ||
in the ROM | ||
''' | ||
"""Assembles M68K instructions and writes the opcode to the specified address | ||
""" | ||
|
||
from binaryninja import * | ||
from binaryninja import (BackgroundTaskThread, AddressField, | ||
MultilineTextField, get_form_input, show_message_box) | ||
import tempfile | ||
import shutil | ||
import os | ||
import subprocess | ||
|
||
__author__ = 'zznop' | ||
__copyright__ = 'Copyright 2019, zznop' | ||
__license__ = 'GPL' | ||
__version__ = '1.1' | ||
__email__ = '[email protected]' | ||
|
||
class GenesisAssemble(BackgroundTaskThread): | ||
def __init__(self, bv): | ||
|
@@ -23,10 +18,10 @@ def __init__(self, bv): | |
self.progress = 'genesis: Assembling code...' | ||
|
||
def _get_params(self): | ||
'''Launch an input box to get start offset for patch and code | ||
''' | ||
params = {} | ||
start_offset_field = AddressField('Start offset for patch (current offset: 0x{:08x})'.format(self.bv.offset), | ||
start_offset_field = AddressField( | ||
'Start offset for patch (current offset: 0x{:08x})'.format( | ||
self.bv.offset), | ||
view=self.bv, current_address=self.bv.offset) | ||
code_field = MultilineTextField('Code') | ||
get_form_input([start_offset_field, code_field], 'Patch Parameters') | ||
|
@@ -35,10 +30,9 @@ def _get_params(self): | |
return params | ||
|
||
def _assemble_code(self, dirpath): | ||
'''Assemble patch.S | ||
''' | ||
p = subprocess.Popen([self.as_path,'-m68000', '-c', '-a={}/patch.lst'.format(dirpath), | ||
'{}/patch.S'.format(dirpath), '-o', '{}/patch.o'.format(dirpath)], | ||
p = subprocess.Popen( | ||
[self.as_path, '-m68000', '-c', '-a={}/patch.lst'.format(dirpath), | ||
'{}/patch.S'.format(dirpath), '-o', '{}/patch.o'.format(dirpath)], | ||
stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
||
(out, err) = p.communicate() | ||
|
@@ -49,10 +43,9 @@ def _assemble_code(self, dirpath): | |
return True | ||
|
||
def _link_code(self, dirpath): | ||
'''Link patch.o object | ||
''' | ||
p = subprocess.Popen([self.ld_path, '-Ttext', '0', '--oformat', 'binary', '-o', | ||
'{}/patch.bin'.format(dirpath), '{}/patch.o'.format(dirpath)], | ||
p = subprocess.Popen( | ||
[self.ld_path, '-Ttext', '0', '--oformat', 'binary', '-o', | ||
'{}/patch.bin'.format(dirpath), '{}/patch.o'.format(dirpath)], | ||
stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
|
||
(out, err) = p.communicate() | ||
|
@@ -63,8 +56,6 @@ def _link_code(self, dirpath): | |
return True | ||
|
||
def _assemble_link_extract(self, code): | ||
'''Write code to tempdir/patch.S and assemble it | ||
''' | ||
blob = None | ||
try: | ||
template = '.section .text\n' \ | ||
|
@@ -75,7 +66,7 @@ def _assemble_link_extract(self, code): | |
dirpath = tempfile.mkdtemp() | ||
print(dirpath) | ||
with open(dirpath + '/patch.S', 'w+b') as f: | ||
f.write(template) | ||
f.write(template.encode('utf-8')) | ||
|
||
if not self._assemble_code(dirpath): | ||
raise OSError('Failed to assemble code') | ||
|
@@ -91,8 +82,6 @@ def _assemble_link_extract(self, code): | |
return blob | ||
|
||
def run(self): | ||
'''Assemble code and patch offset | ||
''' | ||
params = self._get_params() | ||
blob = self._assemble_link_extract(params['code']) | ||
if blob is None: | ||
|
@@ -101,9 +90,14 @@ def run(self): | |
blob_len = len(blob) | ||
if blob_len > 0: | ||
self.bv.write(params['start_offset'], blob) | ||
show_message_box('genesis', 'Wrote {} bytes beginning at {:08x}'.format(blob_len, params['start_offset'])) | ||
show_message_box( | ||
'genesis', | ||
'Wrote {} bytes beginning at {:08x}'.format( | ||
blob_len, params['start_offset']) | ||
) | ||
else: | ||
show_message_box('genesis', 'Patch is 0 bytes in size') | ||
|
||
|
||
if __name__ == '__main__': | ||
print('! this plugin does not run headless') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,43 @@ | ||
'''Locates and disassembles common call tables present in certain ROM's | ||
''' | ||
"""Locates and disassembles common call tables present in certain ROM's | ||
""" | ||
|
||
from binaryninja import * | ||
import struct | ||
from binaryninja import (BackgroundTaskThread, BinaryReader, | ||
MediumLevelILOperation, Platform, show_message_box) | ||
|
||
__author__ = 'zznop' | ||
__copyright__ = 'Copyright 2019, zznop' | ||
__license__ = 'GPL' | ||
__version__ = '1.1' | ||
__email__ = '[email protected]' | ||
|
||
class GenesisCallTableEnum(BackgroundTaskThread): | ||
def __init__(self, bv): | ||
BackgroundTaskThread.__init__(self, "", True) | ||
self.progress = 'gensis: Enumerating call tables...' | ||
self.progress = 'genesis: Enumerating call tables...' | ||
self.bv = bv | ||
self.br = BinaryReader(self.bv) | ||
|
||
def find_call_tables(self): | ||
'''Find call table base addresses using MLIL | ||
''' | ||
base_addrs = [] | ||
for func in self.bv: | ||
if not func.medium_level_il.ssa_form: | ||
continue | ||
|
||
for block in func.medium_level_il.ssa_form: | ||
for instr in block: | ||
branch_operations = [ | ||
MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA, | ||
MediumLevelILOperation.MLIL_JUMP, | ||
MediumLevelILOperation.MLIL_GOTO | ||
] | ||
if instr.operation in branch_operations: | ||
if type(instr.dest) == long: | ||
continue | ||
|
||
if instr.dest.operation == MediumLevelILOperation.MLIL_ADD: | ||
if instr.dest.operands[0].operation == MediumLevelILOperation.MLIL_CONST: | ||
base_addrs.append(instr.dest.operands[0].constant) | ||
if instr.operation not in branch_operations: | ||
continue | ||
|
||
if type(instr.dest) == int: | ||
continue | ||
|
||
if instr.dest.operation == MediumLevelILOperation.MLIL_ADD: | ||
if instr.dest.operands[0].operation == MediumLevelILOperation.MLIL_CONST: | ||
base_addrs.append(instr.dest.operands[0].constant) | ||
return base_addrs | ||
|
||
def disas_call_tables(self, base_addrs): | ||
'''Disassemble the instructions in the call table | ||
''' | ||
count = 0 | ||
for addr in base_addrs: | ||
i = addr | ||
|
@@ -58,12 +55,16 @@ def disas_call_tables(self, base_addrs): | |
return count | ||
|
||
def run(self): | ||
'''Locate and disassemble call tables | ||
''' | ||
self.bv.platform = Platform['M68000'] | ||
call_table_addrs = self.find_call_tables() | ||
if not call_table_addrs: | ||
return | ||
count = self.disas_call_tables(call_table_addrs) | ||
show_message_box('genesis', 'Disassembled {} call table instructions'.format(count)) | ||
show_message_box( | ||
'genesis', | ||
'Disassembled {} call table instructions'.format(count) | ||
) | ||
|
||
|
||
if __name__ == '__main__': | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,9 @@ | ||
'''Calculates the new ROM checksum and writes it back to the binary | ||
''' | ||
"""Calculates the new ROM checksum and writes it back to the binary | ||
""" | ||
|
||
from binaryninja import * | ||
from binaryninja import BackgroundTaskThread, BinaryReader, show_message_box | ||
import struct | ||
|
||
__author__ = 'zznop' | ||
__copyright__ = 'Copyright 2019, zznop' | ||
__license__ = 'GPL' | ||
__version__ = '1.1' | ||
__email__ = '[email protected]' | ||
|
||
class GenesisChecksum(BackgroundTaskThread): | ||
def __init__(self, bv): | ||
|
@@ -20,8 +15,6 @@ def __init__(self, bv): | |
self.br = BinaryReader(self.bv) | ||
|
||
def _calculate_checksum(self): | ||
'''Calculate the ROM checksum | ||
''' | ||
self.br.seek(self.rom_start) | ||
checksum = self.br.read16be() | ||
while True: | ||
|
@@ -32,11 +25,10 @@ def _calculate_checksum(self): | |
return checksum | ||
|
||
def run(self): | ||
'''Calculate new checksum and overwrite the existing | ||
''' | ||
checksum = self._calculate_checksum() | ||
self.bv.write(self.checksum_off, struct.pack('>H', checksum)) | ||
show_message_box('genesis', 'ROM checksum has been updated') | ||
|
||
|
||
if __name__ == '__main__': | ||
print('! this plugin does not run headless') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,16 @@ | ||
from binaryninja import * | ||
from binaryninja import (binaryview, Architecture, core, SegmentFlag, | ||
SectionSemantics, Symbol, SymbolType, log) | ||
import struct | ||
import traceback | ||
|
||
__author__ = 'zznop' | ||
__copyright__ = 'Copyright 2019, zznop' | ||
__license__ = 'GPL' | ||
__version__ = '1.1' | ||
__email__ = '[email protected]' | ||
|
||
class GenesisView(binaryview.BinaryView): | ||
name = 'SG/SMD' | ||
long_name = 'SEGA Genesis/Megadrive ROM' | ||
|
||
def __init__(self, data): | ||
binaryview.BinaryView.__init__(self, parent_view=data, file_metadata=data.file) | ||
binaryview.BinaryView.__init__(self, parent_view=data, | ||
file_metadata=data.file) | ||
self.platform = Architecture['M68000'].standalone_platform | ||
self.raw = data | ||
|
||
|
@@ -39,41 +36,49 @@ def get_load_settings_for_data(self, data): | |
return core.BNAllocString(load_settings_id) | ||
|
||
def create_segments(self): | ||
self.add_auto_segment(0, len(self.raw), 0, | ||
len(self.raw), SegmentFlag.SegmentReadable|SegmentFlag.SegmentExecutable) | ||
self.add_auto_segment( | ||
0, len(self.raw), 0, len(self.raw), | ||
SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable | ||
) | ||
|
||
# RAM Segment | ||
self.add_auto_segment(0xff0000, 0xffff, 0, | ||
0, SegmentFlag.SegmentReadable|SegmentFlag.SegmentWritable) | ||
self.add_auto_segment( | ||
0xff0000, 0xffff, 0, 0, | ||
SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | ||
) | ||
|
||
# Z80 Segment | ||
self.add_auto_segment(0xa00000, 0x1ffff, 0, | ||
0, SegmentFlag.SegmentReadable|SegmentFlag.SegmentWritable) | ||
self.add_auto_segment( | ||
0xa00000, 0x1ffff, 0, 0, | ||
SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | ||
) | ||
|
||
# VDP Segment | ||
self.add_auto_segment(0xc00000, 0x20, 0, | ||
0, SegmentFlag.SegmentReadable|SegmentFlag.SegmentWritable) | ||
self.add_auto_segment( | ||
0xc00000, 0x20, 0, 0, | ||
SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | ||
) | ||
|
||
def create_sections(self): | ||
self.add_auto_section( | ||
self.add_auto_section( | ||
"header", 0, 8, | ||
SectionSemantics.ReadOnlyDataSectionSemantics) | ||
self.add_auto_section( | ||
self.add_auto_section( | ||
"ivt", 8, 248, | ||
SectionSemantics.ReadOnlyDataSectionSemantics) | ||
self.add_auto_section( | ||
self.add_auto_section( | ||
"info", 256, 256, | ||
SectionSemantics.ReadOnlyDataSectionSemantics) | ||
self.add_auto_section( | ||
self.add_auto_section( | ||
"code", 512, len(self.raw)-512, | ||
SectionSemantics.ReadOnlyCodeSectionSemantics) | ||
self.add_auto_section( | ||
self.add_auto_section( | ||
"ram", 0xff0000, 0xffff, | ||
SectionSemantics.ReadWriteDataSectionSemantics) | ||
self.add_auto_section( | ||
self.add_auto_section( | ||
"z80", 0xa00000, 0x1ffff, | ||
SectionSemantics.ReadWriteDataSectionSemantics) | ||
self.add_auto_section( | ||
self.add_auto_section( | ||
"vdp", 0xc00000, 0x20, | ||
SectionSemantics.ReadWriteDataSectionSemantics) | ||
|
||
|
@@ -83,14 +88,20 @@ def create_functions(self): | |
self.add_function(addr) | ||
if idx == 4: | ||
self.add_entry_point(addr) | ||
self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, addr, "_start")) | ||
self.define_auto_symbol( | ||
Symbol(SymbolType.FunctionSymbol, addr, "_start") | ||
) | ||
elif idx == 112: | ||
self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, addr, "hblank")) | ||
self.define_auto_symbol( | ||
Symbol(SymbolType.FunctionSymbol, addr, "hblank") | ||
) | ||
elif idx == 120: | ||
self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, addr, "vblank")) | ||
self.define_auto_symbol( | ||
Symbol(SymbolType.FunctionSymbol, addr, "vblank") | ||
) | ||
|
||
def create_datatype_and_name(self, addr, name, _type): | ||
self.define_user_data_var(addr, _type) | ||
self.define_user_data_var(addr, _type) | ||
self.define_auto_symbol(Symbol(SymbolType.DataSymbol, addr, name)) | ||
|
||
def create_vector_table(self): | ||
|
Oops, something went wrong.