summaryrefslogtreecommitdiff
path: root/python/examples
diff options
context:
space:
mode:
Diffstat (limited to 'python/examples')
-rw-r--r--python/examples/README.md27
-rw-r--r--python/examples/angr_plugin.py153
-rw-r--r--python/examples/arm-syscall.py18
-rw-r--r--python/examples/bin-info.py34
-rw-r--r--python/examples/bin_info.py73
-rw-r--r--python/examples/breakpoint.py48
-rwxr-xr-xpython/examples/export-svg.py166
-rwxr-xr-xpython/examples/export_svg.py214
-rw-r--r--python/examples/instruction-iterator.py49
-rw-r--r--python/examples/instruction_iterator.py53
-rw-r--r--python/examples/jump_table.py (renamed from python/examples/jump-table.py)29
-rw-r--r--python/examples/nds.py117
-rw-r--r--python/examples/nes.py554
-rw-r--r--python/examples/nsf.py145
-rw-r--r--python/examples/print_syscalls.py55
-rw-r--r--python/examples/version_switcher.py (renamed from python/examples/version-switcher.py)71
16 files changed, 1194 insertions, 612 deletions
diff --git a/python/examples/README.md b/python/examples/README.md
index 7fd3ab6b..43af34be 100644
--- a/python/examples/README.md
+++ b/python/examples/README.md
@@ -4,11 +4,14 @@ The following examples demonstrate some of the Binary Ninja API. They include bo
## Stand-alone
-* bin-info.py - general binary information
-* arm-syscall.py - extract syscall numbers from IL for arm Mach-O files
-* version-switcher.py - uses the update API to see raw version notes and manually downgrade or upgrade
+These plugins only operate when run directly outside of the UI
-To use the stand-alone Python examples, make sure your `PYTHON_PATH` includes the API, like:
+* bin_info.py - general binary information
+* print_syscalls.py - extract syscall numbers from IL on specified file. Can be run both headless and in Binary Ninja
+* version_switcher.py - uses the update API to see raw version notes and manually downgrade or upgrade
+* instruction_iterator.py - very simple plugin that iterates through functions, blocks, and instructions
+
+To use the stand-alone Python examples, make sure your `PYTHON_PATH` includes the API, as shown below. Please note, this is a feature that requires the "GUI-less processing" capability not available in the personal edition. In the personal edition, all scripts must by run from the integrated python console (follow the directions below under "Loading Plugins" section)
```
PYTHONPATH=$PYTHONPATH:/Applications/Binary\ Ninja.app/Contents/Resources/python
@@ -16,9 +19,21 @@ PYTHONPATH=$PYTHONPATH:/Applications/Binary\ Ninja.app/Contents/Resources/python
## GUI Plugins
-* nes.py - 6502 CPU architecture including LLIL lifting and `.NES` file format parser
+These plugins require the UI to be running
+
* breakpoint.py - small example showing how to modify a file and register a GUI menu item
-* jump-table.py - stop-gap jump table plugin triggered via right-click menu at an indirect jump
+* jump_table.py - heuristic based jump table detection for when the data-flow based computation fails, triggered by right-clicking on the location where the jump value is computed
+* angr_plugin.py - a plugin to demonstrate both background threads, the simplified plugin UI elements, and highlighting
+* export_svg.py - exports the graph view of a function to an SVG file for including in reports
+
+## Both
+
+These plugins are able to operate in either the GUI or as stand-alone plugins
+
+* nes.py - 6502 CPU architecture including LLIL lifting and `.NES` file format parser
+
+
+## Loading Plugins
Plugins are meant to be loaded into a running Binary Ninja GUI and should either be copied or symlinked into the appropriate plugin folder. You'll need to then re-start Binary Ninja.
diff --git a/python/examples/angr_plugin.py b/python/examples/angr_plugin.py
new file mode 100644
index 00000000..90217d65
--- /dev/null
+++ b/python/examples/angr_plugin.py
@@ -0,0 +1,153 @@
+# 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.
+
+
+# This plugin assumes angr is already installed and available on the system. See the angr documentation
+# for information about installing angr. It should be installed using the virtualenv method.
+#
+# This plugin is currently only known to work on Linux using virtualenv. Switch to the virtual environment
+# (using a command such as "workon angr"), then run the Binary Ninja UI from the command line.
+#
+# This method is known to fail on Mac OS X as the virtualenv used by angr does not appear to provide a
+# way to automatically link to the correct version of Python, even when running the UI from within the
+# virtual environment. A later update may allow for a manual override to link to the required version
+# of Python.
+
+import tempfile
+import logging
+import os
+
+__name__ = "__console__" # angr looks for this, it won't load from within a UI without it
+
+import angr
+# For the lazy instead you can just import everything 'from binaryninja import *''
+from binaryninja.binaryview import BinaryView
+from binaryninja.plugin import BackgroundTaskThread, PluginCommand
+from binaryninja.interaction import show_plain_text_report, show_message_box
+from binaryninja.highlight import HighlightColor
+from binaryninja.enums import HighlightStandardColor, MessageBoxButtonSet
+
+# Disable warning logs as they show up as errors in the UI
+logging.disable(logging.WARNING)
+
+# Create sets in the BinaryView's data field to store the desired path for each view
+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')])
+
+
+# Define a background thread object for solving in the background
+class Solver(BackgroundTaskThread):
+ def __init__(self, find, avoid, view):
+ BackgroundTaskThread.__init__(self, "Solving with angr...", True)
+ self.find = tuple(find)
+ self.avoid = tuple(avoid)
+ self.view = view
+
+ # Write the binary to disk so that the angr API can read it
+ self.binary = tempfile.NamedTemporaryFile()
+ self.binary.write(view.file.raw.read(0, len(view.file.raw)))
+ self.binary.flush()
+
+ def run(self):
+ # Create an angr project and an explorer with the user's settings
+ p = angr.Project(self.binary.name)
+ e = p.surveyors.Explorer(find = self.find, avoid = self.avoid)
+
+ # Solve loop
+ while not e.done:
+ if self.cancelled:
+ # Solve cancelled, show results if there were any
+ if len(e.found) > 0:
+ break
+ return
+
+ # Perform the next step in the solve
+ e.step()
+
+ # Update status
+ active_count = len(e.active)
+ found_count = len(e.found)
+
+ progress = "Solving with angr (%d active path%s" % (active_count, "s" if active_count != 1 else "")
+ if found_count > 0:
+ progress += ", %d path%s found" % (found_count, "s" if found_count != 1 else "")
+ self.progress = progress + ")..."
+
+ # Solve complete, show report
+ text_report = "Found %d path%s.\n\n" % (len(e.found), "s" if len(e.found) != 1 else "")
+ i = 1
+ for f in e.found:
+ text_report += "Path %d\n" % i + "=" * 10 + "\n"
+ text_report += "stdin:\n" + escaped_output(f.state.posix.dumps(0)) + "\n\n"
+ text_report += "stdout:\n" + escaped_output(f.state.posix.dumps(1)) + "\n\n"
+ text_report += "stderr:\n" + escaped_output(f.state.posix.dumps(2)) + "\n\n"
+ i += 1
+
+ name = self.view.file.filename
+ if len(name) > 0:
+ show_plain_text_report("Results from angr - " + os.path.basename(self.view.file.filename), text_report)
+ else:
+ show_plain_text_report("Results from angr", text_report)
+
+
+def find_instr(bv, addr):
+ # Highlight the instruction in green
+ blocks = bv.get_basic_blocks_at(addr)
+ for block in blocks:
+ block.set_auto_highlight(HighlightColor(HighlightStandardColor.GreenHighlightColor, alpha = 128))
+ block.function.set_auto_instr_highlight(addr, HighlightStandardColor.GreenHighlightColor)
+
+ # Add the instruction to the list associated with the current view
+ bv.session_data.angr_find.add(addr)
+
+
+def avoid_instr(bv, addr):
+ # Highlight the instruction in red
+ blocks = bv.get_basic_blocks_at(addr)
+ for block in blocks:
+ block.set_auto_highlight(HighlightColor(HighlightStandardColor.RedHighlightColor, alpha = 128))
+ block.function.set_auto_instr_highlight(addr, HighlightStandardColor.RedHighlightColor)
+
+ # Add the instruction to the list associated with the current view
+ bv.session_data.angr_avoid.add(addr)
+
+
+def solve(bv):
+ 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.", MessageBoxButtonSet.OKButtonSet, MessageBoxButtonSet.ErrorIcon)
+ return
+
+ # Start a solver thread for the path associated with the view
+ 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
+PluginCommand.register_for_address("Find Path to This Instruction",
+ "When solving, find a path that gets to this instruction", find_instr)
+PluginCommand.register_for_address("Avoid This Instruction",
+ "When solving, avoid paths that reach this instruction", avoid_instr)
+PluginCommand.register("Solve With Angr", "Attempt to solve for a path that satisfies the constraints given", solve)
diff --git a/python/examples/arm-syscall.py b/python/examples/arm-syscall.py
deleted file mode 100644
index f94b8531..00000000
--- a/python/examples/arm-syscall.py
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env python
-"""
- Thanks to @theqlabs from arm.ninja for the nice writeup and idea for this plugin:
- http://arm.ninja/2016/03/08/intro-to-binary-ninja-api/
-"""
-import sys, binaryninja, time
-if len(sys.argv) > 1:
- target = sys.argv[1]
-else:
- raise ValueError("Missing argument to binary.")
-
-bv = binaryninja.BinaryViewType["Mach-O"].open(target)
-bv.update_analysis_and_wait()
-
-for func in bv.functions:
- for il in func.low_level_il:
- if il.operation == core.LLIL_SYSCALL:
- print "System call address: %x - %d" % (il.address, func.get_reg_value_at_low_level_il_instruction(il.address, bv.platform.system_call_convention.int_arg_regs[0]).value)
diff --git a/python/examples/bin-info.py b/python/examples/bin-info.py
deleted file mode 100644
index 48073894..00000000
--- a/python/examples/bin-info.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env python
-import sys, binaryninja, time
-if sys.platform.lower().startswith("linux"):
- bintype="ELF"
-elif sys.platform.lower() == "darwin":
- bintype="Mach-O"
-else:
- raise Exception, "%s is not supported on this plugin" % sys.platform
-
-if len(sys.argv) > 1:
- target = sys.argv[1]
-else:
- target = "/bin/ls"
-
-bv = binaryninja.BinaryViewType[bintype].open(target)
-bv.update_analysis_and_wait()
-
-print "-------- %s --------" % target
-print "START: 0x%x" % bv.start
-print "ENTRY: 0x%x" % bv.entry_point
-print "ARCH: %s" % bv.arch.name
-print "\n-------- Function List --------"
-
-for func in bv.functions:
- print func.symbol.name
-
-
-print "\n-------- First 10 strings --------"
-
-for i in xrange(10):
- start = bv.strings[i].start
- length = bv.strings[i].length
- string = bv.read(start,length)
- print "0x%x (%d):\t%s" % (start, length, string)
diff --git a/python/examples/bin_info.py b/python/examples/bin_info.py
new file mode 100644
index 00000000..4c4ab8fd
--- /dev/null
+++ b/python/examples/bin_info.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# 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.
+
+import sys
+import binaryninja.log as log
+from binaryninja.binaryview import BinaryViewType
+import binaryninja.interaction as interaction
+from binaryninja.plugin import PluginCommand
+
+
+def get_bininfo(bv):
+ if bv is None:
+ filename = ""
+ if len(sys.argv) > 1:
+ filename = sys.argv[1]
+ else:
+ filename = interaction.get_open_filename_input("Filename:")
+ if filename is None:
+ log.log_warn("No file specified")
+ sys.exit(1)
+
+ bv = BinaryViewType.get_view_of_file(filename)
+ log.redirect_output_to_log()
+ log.log_to_stdout(True)
+
+ contents = "## %s ##\n" % bv.file.filename
+ contents += "- START: 0x%x\n\n" % bv.start
+ contents += "- ENTRY: 0x%x\n\n" % bv.entry_point
+ contents += "- ARCH: %s\n\n" % bv.arch.name
+ contents += "### First 10 Functions ###\n"
+
+ contents += "| Start | Name |\n"
+ contents += "|------:|:-------|\n"
+ for i in xrange(min(10, len(bv.functions))):
+ contents += "| 0x%x | %s |\n" % (bv.functions[i].start, bv.functions[i].symbol.full_name)
+
+ contents += "### First 10 Strings ###\n"
+ contents += "| Start | Length | String |\n"
+ contents += "|------:|-------:|:-------|\n"
+ for i in xrange(min(10, len(bv.strings))):
+ start = bv.strings[i].start
+ length = bv.strings[i].length
+ string = bv.read(start, length)
+ contents += "| 0x%x |%d | %s |\n" % (start, length, string)
+ return contents
+
+
+def display_bininfo(bv):
+ interaction.show_markdown_report("Binary Info Report", get_bininfo(bv))
+
+
+if __name__ == "__main__":
+ print get_bininfo(None)
+else:
+ PluginCommand.register("Binary Info", "Display basic info about the binary", display_bininfo)
diff --git a/python/examples/breakpoint.py b/python/examples/breakpoint.py
index 44df19e2..b1297e26 100644
--- a/python/examples/breakpoint.py
+++ b/python/examples/breakpoint.py
@@ -1,4 +1,27 @@
-from binaryninja import *
+# 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.
+
+
+from binaryninja.plugin import PluginCommand
+from binaryninja.log import log_error
+
def write_breakpoint(view, start, length):
"""Sample function to show registering a plugin menu item for a range of bytes. Also possible:
@@ -6,11 +29,22 @@ def write_breakpoint(view, start, length):
register_for_address
register_for_function
"""
- if view.arch.name.startswith("x86"):
- view.write(start, "\xcc" * length)
- elif view.arch.name == "armv7":
- view.write(start, "\x7a\x00\x20\xe1" * (length/4))
- else:
- log_error("No support for breakpoint on %s" % view.arch.name)
+ bkpt_str = {
+ "x86": "int3",
+ "x86_64": "int3",
+ "armv7": "bkpt",
+ "aarch64": "brk #0",
+ "mips32": "break"}
+
+ if view.arch.name not in bkpt_str:
+ log_error("Architecture %s not supported" % view.arch.name)
+ return
+
+ bkpt, err = view.arch.assemble(bkpt_str[view.arch.name])
+ if bkpt is None:
+ log_error(err)
+ return
+ view.write(start, bkpt * length / len(bkpt))
+
PluginCommand.register_for_range("Convert to breakpoint", "Fill region with breakpoint instructions.", write_breakpoint)
diff --git a/python/examples/export-svg.py b/python/examples/export-svg.py
deleted file mode 100755
index 3800edf7..00000000
--- a/python/examples/export-svg.py
+++ /dev/null
@@ -1,166 +0,0 @@
-from binaryninja import *
-import os,sys
-
-escape_table = {
- "'": "'",
- ">": ">",
- "<": "&#60;",
- '"': "&#34;",
- ' ': "&#160;"
-}
-
-def escape(string):
- string=string.decode('utf-8').encode('ascii','xmlcharrefreplace') #handle extended unicode
- return ''.join(escape_table.get(i,i) for i in string) #still escape the basics
-
-def save_svg(bv,function):
- filename = bv.file.filename.split(os.sep)[-1]
- address = hex(function.start).replace('L','')
- outputfile = os.path.join(os.path.expanduser('~'), 'binaryninja-{filename}-{function}.html'.format(filename=filename,function=address))
- content = render_svg(function)
- output = open(outputfile,'w')
- output.write(content)
- output.close()
- #os.system('open %s' % outputfile)
-
-def instruction_data_flow(function,address):
- ''' TODO: Extract data flow information '''
- length = function.view.get_instruction_length(function.arch,address)
- bytes = function.view.read(address, length)
- hex = bytes.encode('hex')
- padded = ' '.join([hex[i:i+2] for i in range(0, len(hex), 2)])
- return 'Opcode: {bytes}'.format(bytes=padded)
-
-def render_svg(function):
- graph = function.create_graph()
- graph.layout_and_wait()
- heightconst = 15
- ratio = 0.48
- widthconst = heightconst*ratio
-
- output = '''<html>
- <head>
- <style type="text/css">
- @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro);
- svg {
- background-color: rgb(42, 42, 42);
- }
- .basicblock {
- fill: rgb(74, 74, 74);
- stroke: rgb(224, 224, 224);
- }
- .edge {
- fill: none;
- stroke-width: 1px;
- }
- .UnconditionalBranch, .IndirectBranch {
- stroke: rgb(128, 198, 233);
- color: rgb(128, 198, 233);
- }
- .FalseBranch {
- stroke: rgb(222, 143, 151);
- color: rgb(222, 143, 151);
- }
- .TrueBranch {
- stroke: rgb(162, 217, 175);
- color: rgb(162, 217, 175);
- }
- .arrow {
- stroke-width: 1;
- fill: currentColor;
- }
- text {
- font-family: 'Source Code Pro';
- font-size: 9pt;
- fill: rgb(224, 224, 224);
- }
- .CodeSymbolToken {
- fill: rgb(128, 198, 223);
- }
- .DataSymbolToken {
- fill: rgb(142, 230, 237);
- }
- .TextToken, .InstructionToken, .BeginMemoryOperandToken, .EndMemoryOperandToken {
- fill: rgb(224, 224, 224);
- }
- .PossibleAddressToken, .IntegerToken {
- fill: rgb(162, 217, 175);
- }
- .RegisterToken {
- fill: rgb(237, 223, 179);
- }
- .AnnotationToken {
- fill: rgb(218, 196, 209);
- }
- .ImportToken {
- fill: rgb(237, 189, 129);
- }
- .StackVariableToken {
- fill: rgb(193, 220, 199);
- }
- </style>
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
- </head>
-'''
- output += '''<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}">
- <defs>
- <marker id="arrow-TrueBranch" class="arrow TrueBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
- <path d="M 0 0 L 10 5 L 0 10 z" />
- </marker>
- <marker id="arrow-FalseBranch" class="arrow FalseBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
- <path d="M 0 0 L 10 5 L 0 10 z" />
- </marker>
- <marker id="arrow-UnconditionalBranch" class="arrow UnconditionalBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
- <path d="M 0 0 L 10 5 L 0 10 z" />
- </marker>
- <marker id="arrow-IndirectBranch" class="arrow IndirectBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
- <path d="M 0 0 L 10 5 L 0 10 z" />
- </marker>
- </defs>
- '''.format(width=graph.width*widthconst, height=graph.height*heightconst)
- output += ''' <g id="functiongraph0" class="functiongraph">
- <title>Function Graph 0</title>
- '''
- edges = ''
- for i,block in enumerate(graph.blocks):
-
- #Calculate basic block location and coordinates
- x = ((block.x) * widthconst)
- y = ((block.y) * heightconst)
- width = ((block.width) * widthconst)
- height = ((block.height) * heightconst)
-
- #Render block
- output += ' <g id="basicblock{i}">\n'.format(i=i)
- output += ' <title>Basic Block {i}</title>\n'.format(i=i)
- output += ' <rect class="basicblock" x="{x}" y="{y}" height="{height}" width="{width}"/>\n'.format(x=x,y=y,width=width,height=height)
-
- #Render instructions, unfortunately tspans don't allow copying/pasting more
- #than one line at a time, need SVG 1.2 textarea tags for that it looks like
-
- output += ' <text x="{x}" y="{y}">\n'.format(x=x,y=y + (i + 1) * heightconst)
- for i,line in enumerate(block.lines):
- output += ' <tspan id="instr-{address}" x="{x}" y="{y}">'.format(x=x,y=y + (i + 0.7) * heightconst,address=hex(line.address)[:-1])
- hover = instruction_data_flow(function, line.address)
- output += '<title>{hover}</title>'.format(hover=hover)
- for token in line.tokens:
- # TODO: add hover for hex, function, and reg tokens
- output+='<tspan class="{tokentype}">{text}</tspan>'.format(text=escape(token.text),tokentype=token.type)
- output += '</tspan>\n'
- output += ' </text>\n'
- output += ' </g>\n'
-
- #Edges are rendered in a seperate chunk so they have priority over the
- #basic blocks or else they'd render below them
-
- for edge in block.outgoing_edges:
- points = ""
- for x,y in edge.points:
- points += str(x*widthconst)+","+str(y*heightconst) + " "
- edges += ' <polyline class="edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format(type=edge.type,points=points)
- output += ' ' + edges + '\n'
- output += ' </g>\n'
- output += '</svg></html>'
- return output
-
-PluginCommand.register_for_function("Export to SVG", "Exports an SVG of the current function to your home folder.", save_svg)
diff --git a/python/examples/export_svg.py b/python/examples/export_svg.py
new file mode 100755
index 00000000..95e2d62d
--- /dev/null
+++ b/python/examples/export_svg.py
@@ -0,0 +1,214 @@
+# from binaryninja import *
+import os
+import webbrowser
+try:
+ from urllib import pathname2url # Python 2.x
+except:
+ from urllib.request import pathname2url # Python 3.x
+
+from binaryninja.interaction import get_save_filename_input, show_message_box
+from binaryninja.enums import MessageBoxButtonSet, MessageBoxIcon, MessageBoxButtonResult, InstructionTextTokenType, BranchType
+from binaryninja.plugin import PluginCommand
+
+colors = {'green': [162, 217, 175], 'red': [222, 143, 151], 'blue': [128, 198, 233], 'cyan': [142, 230, 237], 'lightCyan': [176, 221, 228], 'orange': [237, 189, 129], 'yellow': [237, 223, 179], 'magenta': [218, 196, 209], 'none': [74, 74, 74]}
+
+escape_table = {
+ "'": "&#39;",
+ ">": "&#62;",
+ "<": "&#60;",
+ '"': "&#34;",
+ ' ': "&#160;"
+}
+
+
+def escape(toescape):
+ toescape = toescape.decode('utf-8').encode('ascii', 'xmlcharrefreplace') # handle extended unicode
+ return ''.join(escape_table.get(i, i) for i in toescape) # still escape the basics
+
+
+def save_svg(bv, function):
+ address = hex(function.start).replace('L', '')
+ path = os.path.dirname(bv.file.filename)
+ origname = os.path.basename(bv.file.filename)
+ filename = os.path.join(path, 'binaryninja-{filename}-{function}.html'.format(filename=origname, function=address))
+ outputfile = get_save_filename_input('File name for export_svg', 'HTML files (*.html)', filename)
+ if outputfile is None:
+ return
+ content = render_svg(function)
+ output = open(outputfile, 'w')
+ output.write(content)
+ output.close()
+ result = show_message_box("Open SVG", "Would you like to view the exported SVG?",
+ buttons = MessageBoxButtonSet.YesNoButtonSet, icon = MessageBoxIcon.QuestionIcon)
+ if result == MessageBoxButtonResult.YesButton:
+ url = 'file:{}'.format(pathname2url(outputfile))
+ webbrowser.open(url)
+
+
+def instruction_data_flow(function, address):
+ ''' TODO: Extract data flow information '''
+ length = function.view.get_instruction_length(address)
+ bytes = function.view.read(address, length)
+ hex = bytes.encode('hex')
+ padded = ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)])
+ return 'Opcode: {bytes}'.format(bytes=padded)
+
+
+def render_svg(function):
+ graph = function.create_graph()
+ graph.layout_and_wait()
+ heightconst = 15
+ ratio = 0.48
+ widthconst = heightconst * ratio
+
+ output = '''<html>
+ <head>
+ <style type="text/css">
+ @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro);
+ body {
+ background-color: rgb(42, 42, 42);
+ }
+ svg {
+ background-color: rgb(42, 42, 42);
+ display: block;
+ margin: 0 auto;
+ }
+ .basicblock {
+ stroke: rgb(224, 224, 224);
+ }
+ .edge {
+ fill: none;
+ stroke-width: 1px;
+ }
+ .back_edge {
+ fill: none;
+ stroke-width: 2px;
+ }
+ .UnconditionalBranch, .IndirectBranch {
+ stroke: rgb(128, 198, 233);
+ color: rgb(128, 198, 233);
+ }
+ .FalseBranch {
+ stroke: rgb(222, 143, 151);
+ color: rgb(222, 143, 151);
+ }
+ .TrueBranch {
+ stroke: rgb(162, 217, 175);
+ color: rgb(162, 217, 175);
+ }
+ .arrow {
+ stroke-width: 1;
+ fill: currentColor;
+ }
+ text {
+ font-family: 'Source Code Pro';
+ font-size: 9pt;
+ fill: rgb(224, 224, 224);
+ }
+ .CodeSymbolToken {
+ fill: rgb(128, 198, 223);
+ }
+ .DataSymbolToken {
+ fill: rgb(142, 230, 237);
+ }
+ .TextToken, .InstructionToken, .BeginMemoryOperandToken, .EndMemoryOperandToken {
+ fill: rgb(224, 224, 224);
+ }
+ .PossibleAddressToken, .IntegerToken {
+ fill: rgb(162, 217, 175);
+ }
+ .RegisterToken {
+ fill: rgb(237, 223, 179);
+ }
+ .AnnotationToken {
+ fill: rgb(218, 196, 209);
+ }
+ .ImportToken {
+ fill: rgb(237, 189, 129);
+ }
+ .StackVariableToken {
+ fill: rgb(193, 220, 199);
+ }
+ </style>
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
+ </head>
+'''
+ output += '''<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}">
+ <defs>
+ <marker id="arrow-TrueBranch" class="arrow TrueBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
+ <path d="M 0 0 L 10 5 L 0 10 z" />
+ </marker>
+ <marker id="arrow-FalseBranch" class="arrow FalseBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
+ <path d="M 0 0 L 10 5 L 0 10 z" />
+ </marker>
+ <marker id="arrow-UnconditionalBranch" class="arrow UnconditionalBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
+ <path d="M 0 0 L 10 5 L 0 10 z" />
+ </marker>
+ <marker id="arrow-IndirectBranch" class="arrow IndirectBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
+ <path d="M 0 0 L 10 5 L 0 10 z" />
+ </marker>
+ </defs>
+ '''.format(width=graph.width * widthconst + 20, height=graph.height * heightconst + 20)
+ output += ''' <g id="functiongraph0" class="functiongraph">
+ <title>Function Graph 0</title>
+ '''
+ edges = ''
+ for i, block in enumerate(graph.blocks):
+
+ # Calculate basic block location and coordinates
+ x = ((block.x) * widthconst)
+ y = ((block.y) * heightconst)
+ width = ((block.width) * widthconst)
+ height = ((block.height) * heightconst)
+
+ # Render block
+ output += ' <g id="basicblock{i}">\n'.format(i=i)
+ output += ' <title>Basic Block {i}</title>\n'.format(i=i)
+ rgb = colors['none']
+ try:
+ bb = block.basic_block
+ color_code = bb.highlight.color
+ color_str = bb.highlight._standard_color_to_str(color_code)
+ if color_str in colors:
+ rgb = colors[color_str]
+ except:
+ pass
+ output += ' <rect class="basicblock" x="{x}" y="{y}" fill-opacity="0.4" height="{height}" width="{width}" fill="rgb({r},{g},{b})"/>\n'.format(x=x, y=y, width=width + 16, height=height + 12, r=rgb[0], g=rgb[1], b=rgb[2])
+
+ # Render instructions, unfortunately tspans don't allow copying/pasting more
+ # than one line at a time, need SVG 1.2 textarea tags for that it looks like
+
+ output += ' <text x="{x}" y="{y}">\n'.format(x=x, y=y + (i + 1) * heightconst)
+ for i, line in enumerate(block.lines):
+ output += ' <tspan id="instr-{address}" x="{x}" y="{y}">'.format(x=x + 6, y=y + 6 + (i + 0.7) * heightconst, address=hex(line.address)[:-1])
+ hover = instruction_data_flow(function, line.address)
+ output += '<title>{hover}</title>'.format(hover=hover)
+ for token in line.tokens:
+ # TODO: add hover for hex, function, and reg tokens
+ output += '<tspan class="{tokentype}">{text}</tspan>'.format(text=escape(token.text), tokentype=InstructionTextTokenType(token.type).name)
+ output += '</tspan>\n'
+ output += ' </text>\n'
+ output += ' </g>\n'
+
+ # Edges are rendered in a seperate chunk so they have priority over the
+ # basic blocks or else they'd render below them
+
+ for edge in block.outgoing_edges:
+ points = ""
+ x, y = edge.points[0]
+ points += str(x * widthconst) + "," + str(y * heightconst + 12) + " "
+ for x, y in edge.points[1:-1]:
+ points += str(x * widthconst) + "," + str(y * heightconst) + " "
+ x, y = edge.points[-1]
+ points += str(x * widthconst) + "," + str(y * heightconst + 0) + " "
+ if edge.back_edge:
+ edges += ' <polyline class="back_edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format(type=BranchType(edge.type).name, points=points)
+ else:
+ edges += ' <polyline class="edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format(type=BranchType(edge.type).name, points=points)
+ output += ' ' + edges + '\n'
+ output += ' </g>\n'
+ output += '</svg></html>'
+ return output
+
+
+PluginCommand.register_for_function("Export to SVG", "Exports an SVG of the current function", save_svg)
diff --git a/python/examples/instruction-iterator.py b/python/examples/instruction-iterator.py
deleted file mode 100644
index 43bc000e..00000000
--- a/python/examples/instruction-iterator.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-try:
- import binaryninja
-except ImportError:
- sys.path.append("/Applications/Binary Ninja.app/Contents/Resources/python/")
- import binaryninja
-import time
-
-if sys.platform.lower().startswith("linux"):
- bintype="ELF"
-elif sys.platform.lower() == "darwin":
- bintype="Mach-O"
-else:
- raise Exception, "%s is not supported on this plugin" % sys.platform
-
-if len(sys.argv) > 1:
- target = sys.argv[1]
-else:
- target = "/bin/ls"
-
-bv = binaryninja.BinaryViewType[bintype].open(target)
-bv.update_analysis_and_wait()
-
-print "-------- %s --------" % target
-print "START: 0x%x" % bv.start
-print "ENTRY: 0x%x" % bv.entry_point
-print "ARCH: %s" % bv.arch.name
-print "\n-------- Function List --------"
-
-""" print all the functions, their basic blocks, and their il instructions """
-for func in bv.functions:
- print repr(func)
- for block in func.low_level_il:
- print "\t{0}".format(block)
-
- for insn in block:
- print "\t\t{0}".format(insn)
-
-
-""" print all the functions, their basic blocks, and their mc instructions """
-for func in bv.functions:
- print repr(func)
- for block in func:
- print "\t{0}".format(block)
-
- for insn in block:
- print "\t\t{0}".format(insn)
diff --git a/python/examples/instruction_iterator.py b/python/examples/instruction_iterator.py
new file mode 100644
index 00000000..7ff2d692
--- /dev/null
+++ b/python/examples/instruction_iterator.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# 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.
+
+import sys
+import binaryninja as binja
+
+if len(sys.argv) > 1:
+ target = sys.argv[1]
+
+bv = binja.BinaryViewType.get_view_of_file(target)
+binja.log_to_stdout(True)
+binja.log_info("-------- %s --------" % target)
+binja.log_info("START: 0x%x" % bv.start)
+binja.log_info("ENTRY: 0x%x" % bv.entry_point)
+binja.log_info("ARCH: %s" % bv.arch.name)
+binja.log_info("\n-------- Function List --------")
+
+""" print all the functions, their basic blocks, and their il instructions """
+for func in bv.functions:
+ binja.log_info(repr(func))
+ for block in func.low_level_il:
+ binja.log_info("\t{0}".format(block))
+
+ for insn in block:
+ binja.log_info("\t\t{0}".format(insn))
+
+
+""" print all the functions, their basic blocks, and their mc instructions """
+for func in bv.functions:
+ binja.log_info(repr(func))
+ for block in func:
+ binja.log_info("\t{0}".format(block))
+
+ for insn in block:
+ binja.log_info("\t\t{0}".format(insn))
diff --git a/python/examples/jump-table.py b/python/examples/jump_table.py
index 39fed1a5..439e2ab6 100644
--- a/python/examples/jump-table.py
+++ b/python/examples/jump_table.py
@@ -1,8 +1,30 @@
+# 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.
+
# This plugin will attempt to resolve simple jump tables (an array of code pointers) and add the destinations
# as indirect branch targets so that the flow graph reflects the jump table's control flow.
-from binaryninja import *
+from binaryninja.plugin import PluginCommand
+from binaryninja.enums import InstructionTextTokenType
import struct
+
def find_jump_table(bv, addr):
for block in bv.get_basic_blocks_at(addr):
func = block.function
@@ -28,7 +50,7 @@ def find_jump_table(bv, addr):
# Collect the branch targets for any tables referenced by the clicked instruction
branches = []
for token in tokens:
- if token.type == "PossibleAddressToken": # Table addresses will be a "possible address" token
+ if InstructionTextTokenType(token.type) == InstructionTextTokenType.PossibleAddressToken: # Table addresses will be a "possible address" token
tbl = token.value
print "Found possible table at 0x%x" % tbl
i = 0
@@ -56,7 +78,8 @@ def find_jump_table(bv, addr):
i += 1
# Set the indirect branch targets on the jump instruction to be the list of targets discovered
- func.set_user_indirect_branches(arch, jump_addr, branches)
+ func.set_user_indirect_branches(jump_addr, branches)
+
# Create a plugin command so that the user can right click on an instruction referencing a jump table and
# invoke the command
diff --git a/python/examples/nds.py b/python/examples/nds.py
new file mode 100644
index 00000000..ff137b4b
--- /dev/null
+++ b/python/examples/nds.py
@@ -0,0 +1,117 @@
+# 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.
+
+# from binaryninja import *
+from binaryninja.binaryview import BinaryView
+from binaryninja.architecture import Architecture
+from binaryninja.enums import SegmentFlag
+from binaryninja.log import log_error
+
+import struct
+import traceback
+
+
+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,
+ SegmentFlag.SegmentReadable | SegmentFlag.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,
+ SegmentFlag.SegmentReadable | SegmentFlag.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 21b02dfa..4122cde0 100644
--- a/python/examples/nes.py
+++ b/python/examples/nes.py
@@ -18,44 +18,52 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
-from binaryninja import *
import struct
import traceback
import os
+from binaryninja.architecture import Architecture
+from binaryninja.lowlevelil import LowLevelILLabel, LLIL_TEMP
+from binaryninja.function import RegisterInfo, InstructionInfo, InstructionTextToken
+from binaryninja.binaryview import BinaryView
+from binaryninja.types import Symbol
+from binaryninja.log import log_error
+from binaryninja.enums import (BranchType, InstructionTextTokenType,
+ LowLevelILOperation, LowLevelILFlagCondition, FlagRole, SegmentFlag, SymbolType)
+
InstructionNames = [
- "brk", "ora", None, None, None, "ora", "asl", None, # 0x00
- "php", "ora", "asl@", None, None, "ora", "asl", None, # 0x08
- "bpl", "ora", None, None, None, "ora", "asl", None, # 0x10
- "clc", "ora", None, None, None, "ora", "asl", None, # 0x18
- "jsr", "and", None, None, "bit", "and", "rol", None, # 0x20
- "plp", "and", "rol@", None, "bit", "and", "rol", None, # 0x28
- "bmi", "and", None, None, None, "and", "rol", None, # 0x30
- "sec", "and", None, None, None, "and", "rol", None, # 0x38
- "rti", "eor", None, None, None, "eor", "lsr", None, # 0x40
- "pha", "eor", "lsr@", None, "jmp", "eor", "lsr", None, # 0x48
- "bvc", "eor", None, None, None, "eor", "lsr", None, # 0x50
- "cli", "eor", None, None, None, "eor", "lsr", None, # 0x58
- "rts", "adc", None, None, None, "adc", "ror", None, # 0x60
- "pla", "adc", "ror@", None, "jmp", "adc", "ror", None, # 0x68
- "bvs", "adc", None, None, None, "adc", "ror", None, # 0x70
- "sei", "adc", None, None, None, "adc", "ror", None, # 0x78
- None, "sta", None, None, "sty", "sta", "stx", None, # 0x80
- "dey", None, "txa", None, "sty", "sta", "stx", None, # 0x88
- "bcc", "sta", None, None, "sty", "sta", "stx", None, # 0x90
- "tya", "sta", "txs", None, None, "sta", None, None, # 0x98
- "ldy", "lda", "ldx", None, "ldy", "lda", "ldx", None, # 0xa0
- "tay", "lda", "tax", None, "ldy", "lda", "ldx", None, # 0xa8
- "bcs", "lda", None, None, "ldy", "lda", "ldx", None, # 0xb0
- "clv", "lda", "tsx", None, "ldy", "lda", "ldx", None, # 0xb8
- "cpy", "cmp", None, None, "cpy", "cmp", "dec", None, # 0xc0
- "iny", "cmp", "dex", None, "cpy", "cmp", "dec", None, # 0xc8
- "bne", "cmp", None, None, None, "cmp", "dec", None, # 0xd0
- "cld", "cmp", None, None, None, "cmp", "dec", None, # 0xd8
- "cpx", "sbc", None, None, "cpx", "sbc", "inc", None, # 0xe0
- "inx", "sbc", "nop", None, "cpx", "sbc", "inc", None, # 0xe8
- "beq", "sbc", None, None, None, "sbc", "inc", None, # 0xf0
- "sed", "sbc", None, None, None, "sbc", "inc", None # 0xf8
+ "brk", "ora", None, None, None, "ora", "asl", None, # 0x00
+ "php", "ora", "asl@", None, None, "ora", "asl", None, # 0x08
+ "bpl", "ora", None, None, None, "ora", "asl", None, # 0x10
+ "clc", "ora", None, None, None, "ora", "asl", None, # 0x18
+ "jsr", "and", None, None, "bit", "and", "rol", None, # 0x20
+ "plp", "and", "rol@", None, "bit", "and", "rol", None, # 0x28
+ "bmi", "and", None, None, None, "and", "rol", None, # 0x30
+ "sec", "and", None, None, None, "and", "rol", None, # 0x38
+ "rti", "eor", None, None, None, "eor", "lsr", None, # 0x40
+ "pha", "eor", "lsr@", None, "jmp", "eor", "lsr", None, # 0x48
+ "bvc", "eor", None, None, None, "eor", "lsr", None, # 0x50
+ "cli", "eor", None, None, None, "eor", "lsr", None, # 0x58
+ "rts", "adc", None, None, None, "adc", "ror", None, # 0x60
+ "pla", "adc", "ror@", None, "jmp", "adc", "ror", None, # 0x68
+ "bvs", "adc", None, None, None, "adc", "ror", None, # 0x70
+ "sei", "adc", None, None, None, "adc", "ror", None, # 0x78
+ None, "sta", None, None, "sty", "sta", "stx", None, # 0x80
+ "dey", None, "txa", None, "sty", "sta", "stx", None, # 0x88
+ "bcc", "sta", None, None, "sty", "sta", "stx", None, # 0x90
+ "tya", "sta", "txs", None, None, "sta", None, None, # 0x98
+ "ldy", "lda", "ldx", None, "ldy", "lda", "ldx", None, # 0xa0
+ "tay", "lda", "tax", None, "ldy", "lda", "ldx", None, # 0xa8
+ "bcs", "lda", None, None, "ldy", "lda", "ldx", None, # 0xb0
+ "clv", "lda", "tsx", None, "ldy", "lda", "ldx", None, # 0xb8
+ "cpy", "cmp", None, None, "cpy", "cmp", "dec", None, # 0xc0
+ "iny", "cmp", "dex", None, "cpy", "cmp", "dec", None, # 0xc8
+ "bne", "cmp", None, None, None, "cmp", "dec", None, # 0xd0
+ "cld", "cmp", None, None, None, "cmp", "dec", None, # 0xd8
+ "cpx", "sbc", None, None, "cpx", "sbc", "inc", None, # 0xe0
+ "inx", "sbc", "nop", None, "cpx", "sbc", "inc", None, # 0xe8
+ "beq", "sbc", None, None, None, "sbc", "inc", None, # 0xf0
+ "sed", "sbc", None, None, None, "sbc", "inc", None # 0xf8
]
NONE = 0
@@ -81,105 +89,106 @@ ZERO_X_DEST = 19
ZERO_Y = 20
ZERO_Y_DEST = 21
InstructionOperandTypes = [
- NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x00
- NONE, IMMED, ACCUM, NONE, NONE, ABS, ABS_DEST, NONE, # 0x08
- REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x10
- NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x18
- ADDR, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0x20
- NONE, IMMED, ACCUM, NONE, ABS, ABS, ABS_DEST, NONE, # 0x28
- REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x30
- NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x38
- NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x40
- NONE, IMMED, ACCUM, NONE, ADDR, ABS, ABS_DEST, NONE, # 0x48
- REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x50
- NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x58
- NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x60
- NONE, IMMED, ACCUM, NONE, IND, ABS, ABS_DEST, NONE, # 0x68
- REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x70
- NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x78
- NONE, IND_X_DEST, NONE, NONE, ZERO_DEST, ZERO_DEST, ZERO_DEST, NONE, # 0x80
- NONE, NONE, NONE, NONE, ABS_DEST, ABS_DEST, ABS_DEST, NONE, # 0x88
- REL, IND_Y_DEST, NONE, NONE, ZERO_X_DEST, ZERO_X_DEST, ZERO_Y_DEST, NONE, # 0x90
- NONE, ABS_Y_DEST, NONE, NONE, NONE, ABS_X_DEST, NONE, NONE, # 0x98
- IMMED, IND_X, IMMED, NONE, ZERO, ZERO, ZERO, NONE, # 0xa0
- NONE, IMMED, NONE, NONE, ABS, ABS, ABS, NONE, # 0xa8
- REL, IND_Y, NONE, NONE, ZERO_X, ZERO_X, ZERO_Y, NONE, # 0xb0
- NONE, ABS_Y, NONE, NONE, ABS_X, ABS_X, ABS_Y, NONE, # 0xb8
- IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xc0
- NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xc8
- REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xd0
- NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0xd8
- IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xe0
- NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xe8
- REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xf0
- NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE # 0xf8
+ NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x00
+ NONE, IMMED, ACCUM, NONE, NONE, ABS, ABS_DEST, NONE, # 0x08
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x10
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x18
+ ADDR, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0x20
+ NONE, IMMED, ACCUM, NONE, ABS, ABS, ABS_DEST, NONE, # 0x28
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x30
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x38
+ NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x40
+ NONE, IMMED, ACCUM, NONE, ADDR, ABS, ABS_DEST, NONE, # 0x48
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x50
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x58
+ NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x60
+ NONE, IMMED, ACCUM, NONE, IND, ABS, ABS_DEST, NONE, # 0x68
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x70
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x78
+ NONE, IND_X_DEST, NONE, NONE, ZERO_DEST, ZERO_DEST, ZERO_DEST, NONE, # 0x80
+ NONE, NONE, NONE, NONE, ABS_DEST, ABS_DEST, ABS_DEST, NONE, # 0x88
+ REL, IND_Y_DEST, NONE, NONE, ZERO_X_DEST, ZERO_X_DEST, ZERO_Y_DEST, NONE, # 0x90
+ NONE, ABS_Y_DEST, NONE, NONE, NONE, ABS_X_DEST, NONE, NONE, # 0x98
+ IMMED, IND_X, IMMED, NONE, ZERO, ZERO, ZERO, NONE, # 0xa0
+ NONE, IMMED, NONE, NONE, ABS, ABS, ABS, NONE, # 0xa8
+ REL, IND_Y, NONE, NONE, ZERO_X, ZERO_X, ZERO_Y, NONE, # 0xb0
+ NONE, ABS_Y, NONE, NONE, ABS_X, ABS_X, ABS_Y, NONE, # 0xb8
+ IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xc0
+ NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xc8
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xd0
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0xd8
+ IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xe0
+ NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xe8
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xf0
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE # 0xf8
]
OperandLengths = [
- 0, # NONE
- 2, # ABS
- 2, # ABS_DEST
- 2, # ABS_X
- 2, # ABS_X_DEST
- 2, # ABS_Y
- 2, # ABS_Y_DEST
- 0, # ACCUM
- 2, # ADDR
- 1, # IMMED
- 2, # IND
- 1, # IND_X
- 1, # IND_X_DEST
- 1, # IND_Y
- 1, # IND_Y_DEST
- 1, # REL
- 1, # ZERO
- 1, # ZREO_DEST
- 1, # ZERO_X
- 1, # ZERO_X_DEST
- 1, # ZERO_Y
- 1 # ZERO_Y_DEST
+ 0, # NONE
+ 2, # ABS
+ 2, # ABS_DEST
+ 2, # ABS_X
+ 2, # ABS_X_DEST
+ 2, # ABS_Y
+ 2, # ABS_Y_DEST
+ 0, # ACCUM
+ 2, # ADDR
+ 1, # IMMED
+ 2, # IND
+ 1, # IND_X
+ 1, # IND_X_DEST
+ 1, # IND_Y
+ 1, # IND_Y_DEST
+ 1, # REL
+ 1, # ZERO
+ 1, # ZREO_DEST
+ 1, # ZERO_X
+ 1, # ZERO_X_DEST
+ 1, # ZERO_Y
+ 1 # ZERO_Y_DEST
]
OperandTokens = [
- lambda value: [], # NONE
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value)], # ABS
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value)], # ABS_DEST
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x")], # ABS_X
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x")], # ABS_X_DEST
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "y")], # ABS_Y
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "y")], # ABS_Y_DEST
- lambda value: [InstructionTextToken(RegisterToken, "a")], # ACCUM
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value)], # ADDR
- lambda value: [InstructionTextToken(TextToken, "#"), InstructionTextToken(IntegerToken, "$%.2x" % value, value)], # IMMED
- lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
- InstructionTextToken(TextToken, "]")], # IND
- lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x"),
- InstructionTextToken(TextToken, "]")], # IND_X
- lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x"),
- InstructionTextToken(TextToken, "]")], # IND_X_DEST
- lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
- InstructionTextToken(TextToken, "], "), InstructionTextToken(RegisterToken, "y")], # IND_Y
- lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
- InstructionTextToken(TextToken, "], "), InstructionTextToken(RegisterToken, "y")], # IND_Y_DEST
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value)], # REL
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value)], # ZERO
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value)], # ZERO_DEST
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x")], # ZERO_X
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x")], # ZERO_X_DEST
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "y")], # ZERO_Y
- lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
- InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "y")] # ZERO_Y_DEST
+ lambda value: [], # NONE
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # ABS
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # ABS_DEST
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "x")], # ABS_X
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "x")], # ABS_X_DEST
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "y")], # ABS_Y
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "y")], # ABS_Y_DEST
+ lambda value: [InstructionTextToken(InstructionTextTokenType.RegisterToken, "a")], # ACCUM
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # ADDR
+ lambda value: [InstructionTextToken(InstructionTextTokenType.TextToken, "#"), InstructionTextToken(InstructionTextTokenType.IntegerToken, "$%.2x" % value, value)], # IMMED
+ lambda value: [InstructionTextToken(InstructionTextTokenType.TextToken, "["), InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, "]")], # IND
+ lambda value: [InstructionTextToken(InstructionTextTokenType.TextToken, "["), InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "x"),
+ InstructionTextToken(InstructionTextTokenType.TextToken, "]")], # IND_X
+ lambda value: [InstructionTextToken(InstructionTextTokenType.TextToken, "["), InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "x"),
+ InstructionTextToken(InstructionTextTokenType.TextToken, "]")], # IND_X_DEST
+ lambda value: [InstructionTextToken(InstructionTextTokenType.TextToken, "["), InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, "], "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "y")], # IND_Y
+ lambda value: [InstructionTextToken(InstructionTextTokenType.TextToken, "["), InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, "], "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "y")], # IND_Y_DEST
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # REL
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value)], # ZERO
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value)], # ZERO_DEST
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "x")], # ZERO_X
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "x")], # ZERO_X_DEST
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "y")], # ZERO_Y
+ lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(InstructionTextTokenType.TextToken, ", "), InstructionTextToken(InstructionTextTokenType.RegisterToken, "y")] # ZERO_Y_DEST
]
+
def indirect_load(il, value):
if (value & 0xff) == 0xff:
lo_addr = il.const(2, value)
@@ -189,8 +198,9 @@ def indirect_load(il, value):
return il.or_expr(2, lo, hi)
return il.load(2, il.const(2, value))
+
def load_zero_page_16(il, value):
- if il[value].operation == "LLIL_CONST":
+ if il[value].operation == LowLevelILOperation.LLIL_CONST:
if il[value].value == 0xff:
lo = il.zero_extend(2, il.load(1, il.const(2, 0xff)))
hi = il.shift_left(2, il.zero_extend(2, il.load(1, il.const(2, 0)), il.const(2, 8)))
@@ -204,34 +214,36 @@ def load_zero_page_16(il, value):
hi = il.shift_left(2, il.zero_extend(2, il.load(1, hi_addr)), il.const(2, 8))
return il.or_expr(2, lo, hi)
+
OperandIL = [
- lambda il, value: None, # NONE
- lambda il, value: il.load(1, il.const(2, value)), # ABS
- lambda il, value: il.const(2, value), # ABS_DEST
- lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "x")))), # ABS_X
- lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "x"))), # ABS_X_DEST
- lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "y")))), # ABS_Y
- lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "y"))), # ABS_Y_DEST
- lambda il, value: il.reg(1, "a"), # ACCUM
- lambda il, value: il.const(2, value), # ADDR
- lambda il, value: il.const(1, value), # IMMED
- lambda il, value: indirect_load(il, value), # IND
- lambda il, value: il.load(1, load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, "x")))), # IND_X
- lambda il, value: load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, "x"))), # IND_X_DEST
- lambda il, value: il.load(1, il.add(2, load_zero_page_16(il, il.const(1, value)), il.reg(1, "y"))), # IND_Y
- lambda il, value: il.add(2, load_zero_page_16(il, il.const(1, value)), il.reg(1, "y")), # IND_Y_DEST
- lambda il, value: il.const(2, value), # REL
- lambda il, value: il.load(1, il.const(2, value)), # ZERO
- lambda il, value: il.const(2, value), # ZERO_DEST
- lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "x")))), # ZERO_X
- lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "x"))), # ZERO_X_DEST
- lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "y")))), # ZERO_Y
- lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "y"))) # ZERO_Y_DEST
+ lambda il, value: None, # NONE
+ lambda il, value: il.load(1, il.const(2, value)), # ABS
+ lambda il, value: il.const(2, value), # ABS_DEST
+ lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "x")))), # ABS_X
+ lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "x"))), # ABS_X_DEST
+ lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "y")))), # ABS_Y
+ lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "y"))), # ABS_Y_DEST
+ lambda il, value: il.reg(1, "a"), # ACCUM
+ lambda il, value: il.const(2, value), # ADDR
+ lambda il, value: il.const(1, value), # IMMED
+ lambda il, value: indirect_load(il, value), # IND
+ lambda il, value: il.load(1, load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, "x")))), # IND_X
+ lambda il, value: load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, "x"))), # IND_X_DEST
+ lambda il, value: il.load(1, il.add(2, load_zero_page_16(il, il.const(1, value)), il.reg(1, "y"))), # IND_Y
+ lambda il, value: il.add(2, load_zero_page_16(il, il.const(1, value)), il.reg(1, "y")), # IND_Y_DEST
+ lambda il, value: il.const(2, value), # REL
+ lambda il, value: il.load(1, il.const(2, value)), # ZERO
+ lambda il, value: il.const(2, value), # ZERO_DEST
+ lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "x")))), # ZERO_X
+ lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "x"))), # ZERO_X_DEST
+ lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "y")))), # ZERO_Y
+ lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "y"))) # ZERO_Y_DEST
]
+
def cond_branch(il, cond, dest):
t = None
- if il[dest].operation == LLIL_CONST:
+ if il[dest].operation == LowLevelILOperation.LLIL_CONST:
t = il.get_label_for_address(Architecture['6502'], il[dest].value)
if t is None:
t = LowLevelILLabel()
@@ -246,9 +258,10 @@ def cond_branch(il, cond, dest):
il.mark_label(f)
return None
+
def jump(il, dest):
label = None
- if il[dest].operation == LLIL_CONST:
+ if il[dest].operation == LowLevelILOperation.LLIL_CONST:
label = il.get_label_for_address(Architecture['6502'], il[dest].value)
if label is None:
il.append(il.jump(dest))
@@ -256,6 +269,7 @@ def jump(il, dest):
il.append(il.goto(label))
return None
+
def get_p_value(il):
c = il.flag_bit(1, "c", 0)
z = il.flag_bit(1, "z", 1)
@@ -267,6 +281,7 @@ def get_p_value(il):
return il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1,
il.or_expr(1, c, z), i), d), b), v), s)
+
def set_p_value(il, value):
il.append(il.set_reg(1, LLIL_TEMP(0), value))
il.append(il.set_flag("c", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x01))))
@@ -278,22 +293,24 @@ def set_p_value(il, value):
il.append(il.set_flag("s", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x80))))
return None
+
def rti(il):
set_p_value(il, il.pop(1))
return il.ret(il.pop(2))
+
InstructionIL = {
"adc": lambda il, operand: il.set_reg(1, "a", il.add_carry(1, il.reg(1, "a"), operand, flags = "*")),
"asl": lambda il, operand: il.store(1, operand, il.shift_left(1, il.load(1, operand), il.const(1, 1), flags = "czs")),
"asl@": lambda il, operand: il.set_reg(1, "a", il.shift_left(1, operand, il.const(1, 1), flags = "czs")),
"and": lambda il, operand: il.set_reg(1, "a", il.and_expr(1, il.reg(1, "a"), operand, flags = "zs")),
- "bcc": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_UGE), operand),
- "bcs": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_ULT), operand),
- "beq": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_E), operand),
+ "bcc": lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_UGE), operand),
+ "bcs": lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_ULT), operand),
+ "beq": lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_E), operand),
"bit": lambda il, operand: il.and_expr(1, il.reg(1, "a"), operand, flags = "czs"),
- "bmi": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_NEG), operand),
- "bne": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_NE), operand),
- "bpl": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_POS), operand),
+ "bmi": lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_NEG), operand),
+ "bne": lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_NE), operand),
+ "bpl": lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_POS), operand),
"brk": lambda il, operand: il.system_call(),
"bvc": lambda il, operand: cond_branch(il, il.not_expr(0, il.flag("v")), operand),
"bvs": lambda il, operand: cond_branch(il, il.flag("v"), operand),
@@ -345,10 +362,12 @@ InstructionIL = {
"tya": lambda il, operand: il.set_reg(1, "a", il.reg(1, "y"), flags = "zs")
}
+
class M6502(Architecture):
name = "6502"
address_size = 2
default_int_size = 1
+ max_instr_length = 3
regs = {
"a": RegisterInfo("a", 1),
"x": RegisterInfo("x", 1),
@@ -359,18 +378,18 @@ class M6502(Architecture):
flags = ["c", "z", "i", "d", "b", "v", "s"]
flag_write_types = ["*", "czs", "zvs", "zs"]
flag_roles = {
- "c": SpecialFlagRole, # Not a normal carry flag, subtract result is inverted
- "z": ZeroFlagRole,
- "v": OverflowFlagRole,
- "s": NegativeSignFlagRole
+ "c": FlagRole.SpecialFlagRole, # Not a normal carry flag, subtract result is inverted
+ "z": FlagRole.ZeroFlagRole,
+ "v": FlagRole.OverflowFlagRole,
+ "s": FlagRole.NegativeSignFlagRole
}
flags_required_for_flag_condition = {
- LLFC_UGE: ["c"],
- LLFC_ULT: ["c"],
- LLFC_E: ["z"],
- LLFC_NE: ["z"],
- LLFC_NEG: ["s"],
- LLFC_POS: ["s"]
+ LowLevelILFlagCondition.LLFC_UGE: ["c"],
+ LowLevelILFlagCondition.LLFC_ULT: ["c"],
+ LowLevelILFlagCondition.LLFC_E: ["z"],
+ LowLevelILFlagCondition.LLFC_NE: ["z"],
+ LowLevelILFlagCondition.LLFC_NEG: ["s"],
+ LowLevelILFlagCondition.LLFC_POS: ["s"]
}
flags_written_by_flag_write_type = {
"*": ["c", "z", "v", "s"],
@@ -412,17 +431,17 @@ class M6502(Architecture):
result.length = length
if instr == "jmp":
if operand == ADDR:
- result.add_branch(UnconditionalBranch, struct.unpack("<H", data[1:3])[0])
+ result.add_branch(BranchType.UnconditionalBranch, struct.unpack("<H", data[1:3])[0])
else:
- result.add_branch(UnresolvedBranch)
+ result.add_branch(BranchType.UnresolvedBranch)
elif instr == "jsr":
- result.add_branch(CallDestination, struct.unpack("<H", data[1:3])[0])
+ result.add_branch(BranchType.CallDestination, struct.unpack("<H", data[1:3])[0])
elif instr in ["rti", "rts"]:
- result.add_branch(FunctionReturn)
+ result.add_branch(BranchType.FunctionReturn)
if instr in ["bcc", "bcs", "beq", "bmi", "bne", "bpl", "bvc", "bvs"]:
dest = (addr + 2 + struct.unpack("b", data[1])[0]) & 0xffff
- result.add_branch(TrueBranch, dest)
- result.add_branch(FalseBranch, addr + 2)
+ result.add_branch(BranchType.TrueBranch, dest)
+ result.add_branch(BranchType.FalseBranch, addr + 2)
return result
def perform_get_instruction_text(self, data, addr):
@@ -431,7 +450,7 @@ class M6502(Architecture):
return None
tokens = []
- tokens.append(InstructionTextToken(TextToken, "%-7s " % instr.replace("@", "")))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, "%-7s " % instr.replace("@", "")))
tokens += OperandTokens[operand](value)
return tokens, length
@@ -487,42 +506,14 @@ 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.data = data
- self.notification = NESViewUpdateNotification(self)
- self.data.register_notification(self.notification)
+ BinaryView.__init__(self, parent_view = data, file_metadata = data.file)
+ self.platform = Architecture['6502'].standalone_platform
@classmethod
def is_valid_for_data(self, data):
@@ -538,7 +529,7 @@ class NESView(BinaryView):
def init(self):
try:
- hdr = self.data.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]
@@ -549,51 +540,60 @@ 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, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable)
+
+ # Add ROM mappings
+ self.add_auto_segment(0x8000, 0x4000, self.rom_offset + (self.__class__.bank * 0x4000), 0x4000,
+ SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable)
+ self.add_auto_segment(0xc000, 0x4000, self.rom_offset + self.rom_length - 0x4000, 0x4000,
+ SegmentFlag.SegmentReadable | SegmentFlag.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]
- self.define_auto_symbol(Symbol(FunctionSymbol, nmi, "_nmi"))
- self.define_auto_symbol(Symbol(FunctionSymbol, start, "_start"))
- self.define_auto_symbol(Symbol(FunctionSymbol, irq, "_irq"))
- self.add_function(Architecture['6502'].standalone_platform, nmi)
- self.add_function(Architecture['6502'].standalone_platform, irq)
- self.add_entry_point(Architecture['6502'].standalone_platform, start)
+ self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, nmi, "_nmi"))
+ self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, start, "_start"))
+ self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, irq, "_irq"))
+ self.add_function(nmi)
+ self.add_function(irq)
+ self.add_entry_point(start)
# 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"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2000, "PPUCTRL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2001, "PPUMASK"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2002, "PPUSTATUS"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2003, "OAMADDR"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2004, "OAMDATA"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2005, "PPUSCROLL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2006, "PPUADDR"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2007, "PPUDATA"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4000, "SQ1_VOL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4001, "SQ1_SWEEP"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4002, "SQ1_LO"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4003, "SQ1_HI"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4004, "SQ2_VOL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4005, "SQ2_SWEEP"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4006, "SQ2_LO"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4007, "SQ2_HI"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4008, "TRI_LINEAR"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400a, "TRI_LO"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400b, "TRI_HI"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400c, "NOISE_VOL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400e, "NOISE_LO"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400f, "NOISE_HI"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4010, "DMC_FREQ"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4011, "DMC_RAW"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4012, "DMC_START"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4013, "DMC_LEN"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4014, "OAMDMA"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4015, "SND_CHN"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4016, "JOY1"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4017, "JOY2"))
- sym_files = [self.data.file.filename + ".%x.nl" % self.__class__.bank,
- self.data.file.filename + ".ram.nl",
- self.data.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()
@@ -604,86 +604,22 @@ class NESView(BinaryView):
break
addr = int(sym[0][1:], 16)
name = sym[1]
- self.define_auto_symbol(Symbol(FunctionSymbol, addr, name))
+ self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, addr, name))
if addr >= 0x8000:
- self.add_function(Architecture['6502'].standalone_platform, addr)
+ self.add_function(addr)
return True
except:
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.data.read(self.rom_offset + bank_ofs + (self.__class__.bank * 0x4000), to_read)
- else:
- data = self.data.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.data.write(self.rom_offset + bank_ofs + (self.__class__.bank * 0x4000), value[offset : offset + to_write])
- else:
- written = self.data.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
def perform_get_entry_point(self):
return struct.unpack("<H", str(self.perform_read(0xfffc, 2)))[0]
+
banks = []
for i in xrange(0, 32):
class NESViewBank(NESView):
diff --git a/python/examples/nsf.py b/python/examples/nsf.py
new file mode 100644
index 00000000..b1bac3a8
--- /dev/null
+++ b/python/examples/nsf.py
@@ -0,0 +1,145 @@
+# 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.binaryview import BinaryView
+from binaryninja.architecture import Architecture
+from binaryninja.log import log_error, log_info
+from binaryninja.types import Symbol
+from binaryninja.enums import SymbolType, SegmentFlag
+
+import struct
+import traceback
+
+
+class NSFView(BinaryView):
+ name = "NSF"
+ long_name = "Nintendo Sound Format"
+
+ def __init__(self, data):
+ BinaryView.__init__(self, parent_view=data, file_metadata=data.file)
+ self.platform = Architecture["6502"].standalone_platform
+
+ @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, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable)
+
+ # Add ROM mappings
+ self.add_auto_segment(0x8000, 0x4000, self.rom_offset, 0x4000,
+ SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable)
+
+ self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, self.play_address, "_play"))
+ self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, self.init_address, "_init"))
+ self.add_entry_point(self.init_address)
+ self.add_function(self.play_address)
+
+ # Hardware registers
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2000, "PPUCTRL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2001, "PPUMASK"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2002, "PPUSTATUS"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2003, "OAMADDR"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2004, "OAMDATA"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2005, "PPUSCROLL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2006, "PPUADDR"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2007, "PPUDATA"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4000, "SQ1_VOL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4001, "SQ1_SWEEP"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4002, "SQ1_LO"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4003, "SQ1_HI"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4004, "SQ2_VOL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4005, "SQ2_SWEEP"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4006, "SQ2_LO"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4007, "SQ2_HI"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4008, "TRI_LINEAR"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400a, "TRI_LO"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400b, "TRI_HI"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400c, "NOISE_VOL"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400e, "NOISE_LO"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x400f, "NOISE_HI"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4010, "DMC_FREQ"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4011, "DMC_RAW"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4012, "DMC_START"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4013, "DMC_LEN"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4014, "OAMDMA"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4015, "SND_CHN"))
+ self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4016, "JOY1"))
+ self.define_auto_symbol(Symbol(SymbolType.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()
diff --git a/python/examples/print_syscalls.py b/python/examples/print_syscalls.py
new file mode 100644
index 00000000..2af4d38d
--- /dev/null
+++ b/python/examples/print_syscalls.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# 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.
+
+
+# Thanks to @theqlabs from arm.ninja for the nice writeup and idea for this plugin:
+# http://arm.ninja/2016/03/08/intro-to-binary-ninja-api/
+
+import sys
+from itertools import chain
+
+from binaryninja.binaryview import BinaryViewType
+from binaryninja.enums import LowLevelILOperation
+
+
+def print_syscalls(fileName):
+ """ Print Syscall numbers for a provided file """
+ bv = BinaryViewType.get_view_of_file(fileName)
+ calling_convention = bv.platform.system_call_convention
+ if calling_convention is None:
+ print('Error: No syscall convention available for {:s}'.format(bv.platform))
+ return
+
+ register = calling_convention.int_arg_regs[0]
+
+ for func in bv.functions:
+ syscalls = (il for il in chain.from_iterable(func.low_level_il)
+ if il.operation == LowLevelILOperation.LLIL_SYSCALL)
+ for il in syscalls:
+ value = func.get_reg_value_at(il.address, register).value
+ print("System call address: {:#x} - {:d}".format(il.address, value))
+
+
+if __name__ == "__main__":
+ if len(sys.argv) != 2:
+ print('Usage: {} <file>'.format(sys.argv[0]))
+ else:
+ print_syscalls(sys.argv[1])
diff --git a/python/examples/version-switcher.py b/python/examples/version_switcher.py
index a1936a52..9d5bbf05 100644
--- a/python/examples/version-switcher.py
+++ b/python/examples/version_switcher.py
@@ -1,26 +1,50 @@
#!/usr/bin/env python
+# 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.
+
import sys
-import binaryninja
+
+from binaryninja.update import UpdateChannel, are_auto_updates_enabled, set_auto_updates_enabled, is_update_installation_pending, install_pending_update
+from binaryninja import core_version
import datetime
-chandefault="private-beta"
-channel=0
-versions=0
+chandefault = UpdateChannel.list[0].name
+channel = None
+versions = []
+
def load_channel(newchannel):
global channel
global versions
- if (channel != 0 and newchannel == channel.name):
+ if (channel is not None and newchannel == channel.name):
print "Same channel, not updating."
else:
try:
print "Loading channel %s" % newchannel
- channel = binaryninja.UpdateChannel[newchannel]
+ channel = UpdateChannel[newchannel]
print "Loading versions..."
versions = channel.versions
except Exception:
print "%s is not a valid channel name. Defaulting to " % chandefault
- channel = binaryninja.UpdateChannel[chandefault]
+ channel = UpdateChannel[chandefault]
+
def select(version):
done = False
@@ -44,43 +68,50 @@ def select(version):
print "Requesting update to latest version."
else:
print "Requesting update to prior version."
- if binaryninja.are_auto_updates_enabled():
+ if are_auto_updates_enabled():
print "Disabling automatic updates."
- binaryninja.set_auto_updates_enabled(False)
- if (version.version == binaryninja.core_version):
+ set_auto_updates_enabled(False)
+ if (version.version == core_version):
print "Already running %s" % version.version
else:
print "version.version %s" % version.version
- print "binaryninja.core_version %s" % binaryninja.core_version
- print "Updating..."
+ print "core_version %s" % core_version
+ print "Downloading..."
print version.update()
- #forward updating won't work without reloading
+ print "Installing..."
+ if is_update_installation_pending:
+ #note that the GUI will be launched after update but should still do the upgrade headless
+ install_pending_update()
+ # forward updating won't work without reloading
sys.exit()
else:
print "Invalid selection"
+
def list_channels():
done = False
print "\tSelect channel:\n"
while not done:
- channel_list = binaryninja.UpdateChannel.list
+ channel_list = UpdateChannel.list
for index, item in enumerate(channel_list):
- print "\t%d)\t%s" % (index+1, item.name)
- print "\t%d)\t%s" % (len(channel_list)+1, "Main Menu")
+ print "\t%d)\t%s" % (index + 1, item.name)
+ print "\t%d)\t%s" % (len(channel_list) + 1, "Main Menu")
selection = raw_input('Choice: ')
if selection.isdigit():
selection = int(selection)
else:
selection = 0
- if (selection <= 0 or selection > len(channel_list)+1):
+ if (selection <= 0 or selection > len(channel_list) + 1):
print "%s is an invalid choice." % selection
else:
done = True
if (selection != len(channel_list) + 1):
load_channel(channel_list[selection - 1].name)
+
def toggle_updates():
- binaryninja.set_auto_updates_enabled(not binaryninja.are_auto_updates_enabled())
+ set_auto_updates_enabled(not are_auto_updates_enabled())
+
def main():
global channel
@@ -89,8 +120,8 @@ def main():
while not done:
print "\n\tBinary Ninja Version Switcher"
print "\t\tCurrent Channel:\t%s" % channel.name
- print "\t\tCurrent Version:\t%s" % binaryninja.core_version
- print "\t\tAuto-Updates On:\t%s\n" % binaryninja.are_auto_updates_enabled()
+ print "\t\tCurrent Version:\t%s" % core_version
+ print "\t\tAuto-Updates On:\t%s\n" % are_auto_updates_enabled()
for index, version in enumerate(versions):
date = datetime.datetime.fromtimestamp(version.time).strftime('%c')
print "\t%d)\t%s (%s)" % (index + 1, version.version, date)