Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save torque59/18c02f4a3b94cb03e097b8aa143eda24 to your computer and use it in GitHub Desktop.

Select an option

Save torque59/18c02f4a3b94cb03e097b8aa143eda24 to your computer and use it in GitHub Desktop.
my current collection of snippets
Welcome to Jordan's grab-bag of common Binary Ninja Snippets.
These snippest are meant to run with the Snippets Plugin
(http://github.com/Vector35/snippets) though they can all also be pasted
directly into the python console or turned into stand-alone plugins as needed.
To install the entire collection at once, just install the Snippets plugin via
the plugin manager (CMD/CTL-SHIFT-M), confirm the Snippet Editor works
(Tool/Snippets/Snippet Editor), and unzip this bundle (Download ZIP above) into
your Snippets folder.
You can access the snippets folder by using Tools/Open Plugin Folder and then
navigating up one folder, then into "Snippets".
Also, appologies for the weird file name, trying to fight gist's auto-sorting.
# automatically create string types at all detected strings
#
for s in bv.strings:
bv.define_user_data_var(s.start, Type.array(Type.char(), s.length))
log_debug("Auto string snippet creating string at %x" % s.start)
# copies the currently selected value as an offset from the base to the clipboard
#
import os
modulename=os.path.basename(bv.file.original_filename)
offset=bv.get_segment_at(here).start
clip = PySide2.QtGui.QGuiApplication.clipboard()
clip.setText('%x' % here-offset)
# creates executable sections if none exist
#
# Useful snippet for binaries without sections but executable (and writable)
# segments. Also demonstrates triggering an analysis module after load.
counter=0
for seg in bv.segments:
if seg.executable and seg.writable:
bv.add_user_section("section_%d"%counter, seg.start, seg.end-seg.start, SectionSemantics.ReadOnlyCodeSectionSemantics)
bv.add_analysis_option("linearsweep")
counter += 1
bv.update_analysis()
# generate settings official documentation
#
import json
from PySide2.QtGui import QGuiApplication
settings = json.loads(binaryninja.Settings().serialize_schema())
table = """|Category|Setting|Description|Type|Default|Key|
|---|---|---|---|---|---|
"""
for category in settings:
for setting in settings[category]['settings']:
title = settings[category]['settings'][setting]['title']
description = settings[category]['settings'][setting]['description']
type = str(settings[category]['settings'][setting]['type'])
key = str(settings[category]['settings'][setting]['key'])
if type:
type = "`%s`" % type
default = str(settings[category]['settings'][setting]['default'])
if default:
default = "`%s`" % default
table += f"|{category}|{title}|{description}|{type}|{default}|<a name='{key}'>{key}</a>|\n"
show_markdown_report("Settings Documentation", "Below table added to the clipboard:\n\n"+table)
log_info("Saving result to the clipboard.")
clip = QGuiApplication.clipboard()
clip.setText(table)
# Find a variable definition from current selection
#
if uicontext.token.localVarValid:
log_info("Found a localvar")
varname = uicontext.token.token.text
log_info(str(dir(uicontext)))
log_info("-----\n")
instrIndex = 0
else:
log_warn("No variable selected")
# Basic sample flowgrpah
#
graph = FlowGraph()
node_a = FlowGraphNode(graph)
node_a.lines = ["Node A"]
node_b = FlowGraphNode(graph)
node_b.lines = ["Node B"]
node_c = FlowGraphNode(graph)
node_c.lines = ["Node C"]
graph.append(node_a)
graph.append(node_b)
graph.append(node_c)
node_a.add_outgoing_edge(BranchType.UnconditionalBranch, node_b)
node_a.add_outgoing_edge(BranchType.UnconditionalBranch, node_c)
show_graph_report("In order", graph)
graph2 = FlowGraph()
node2_a = FlowGraphNode(graph)
node2_a.lines = ["Node A"]
node2_b = FlowGraphNode(graph)
node2_b.lines = ["Node B"]
node2_c = FlowGraphNode(graph)
node2_c.lines = ["Node C"]
graph2.append(node2_b)
graph2.append(node2_c)
graph2.append(node2_a)
node2_a.add_outgoing_edge(BranchType.UnconditionalBranch, node2_b)
node2_a.add_outgoing_edge(BranchType.UnconditionalBranch, node2_c)
show_graph_report("Out of order", graph)
# create common tags for function attributes like leaf, loop, stub, etc
#
# See below for the tags variable for the various tag types created/added
large = 40
def init_tags():
for tagType in tags:
if tagType['name'] not in bv.tag_types.keys():
bv.create_tag_type(tagType['name'], tagType['emoji'])
def isleaf(fn):
return len(fn.callees) == 0
def islarge(fn):
return len(fn.basic_blocks) >= large
def isstub(fn):
"""Returns true if a function is likely only a stub"""
if len(fn.basic_blocks) > 1 or len(fn.llil.basic_blocks) > 1:
return False
if fn.llil.basic_blocks[0].has_undetermined_outgoing_edges or len(fn.callees) == 1:
return True
return False
def hasloop(fn):
"""Returns true if a function has a 'strange loop' (ignore this, inside joke)"""
for bb in fn.basic_blocks:
if bb in bb.dominance_frontier:
return True
return False
tags = [ \
{'emoji': '🍃', 'name': 'Leaf Function', 'description': 'Leaf function (does not call anything else)', 'fn': isleaf},
{'emoji': '🔄', 'name': 'Loop Function', 'description': 'Function contains a loop', 'fn': hasloop},
{'emoji': '🥾', 'name': 'Stub Function', 'description': 'Function is likely a stub (only contains one basic block and one call or indirect jump)', 'fn': isstub},
{'emoji': '🐘', 'name': 'Large Function', 'description': 'Function is "large" (IE, it has more than the blocks defined above)', 'fn': islarge},
]
init_tags()
for fn in bv.functions:
for tagType in tags:
if tagType['fn'](fn):
fn.create_user_function_tag(bv.tag_types[tagType['name']], '', unique=True)
# jump to a random function
#
import random
randomIndex = random.randint(0, len(bv.functions)-1)
destination = bv.functions[randomIndex].start
log_info("Jumping to: 0x%x" % destination)
here = destination
# save HLIL decompilation for the selected function to a file
#
source = '\n'.join(map(str, current_function.hlil.root.lines))
while True:
output = get_save_filename_input("Source filename:", "txt", "%s.txt" % current_function.name)
if output == None:
msg = "No file specified."
interaction.show_message_box(msg, msg)
break
try:
f = open(output, "w")
f.write(source)
f.close()
except:
msg = "Save failed. Try again?"
if not interaction.show_message_box(msg, msg, buttons=MessageBoxButtonSet.YesNoButtonSet):
break
# Simple PySide UI elements/testing
#
import binaryninjaui
from PySide2 import QtWidgets, QtGui, QtWidgets, QtCore
def basic():
popout = QtWidgets.QDialog()
popout.setWindowTitle("test popout1")
popout.exec_()
def qpixmap():
pixmap = QtGui.QPixmap("play-and-pause-button.png")
mask = pixmap.createMaskFromColor(QtGui.QColor('black'), QtGui.Qt.MaskOutColor)
pixmap.fill((QtGui.QColor('red')))
pixmap.setMask(mask)
window = QtWidgets.QDialog()
window.setWindowTitle("View Image")
label = QtWidgets.QLabel(window)
label.setPixmap(pixmap)
label.setGeometry(QtCore.QRect(10, 40, pixmap.width(), pixmap.height()))
window.resize(pixmap.width()+20, pixmap.height()+100)
window.exec_()
def qpixmap2():
icon = QtGui.QIcon("play-and-pause-button.svg")
button = QtWidgets.QPushButton(icon)
msg_box = QtWidgets.QMessageBox()
msg_box.setWindowTitle("Testing Icons")
msg_box.exec_()
def colorize(img, color):
pixmap = QtGui.QPixmap(img)
mask = pixmap.createMaskFromColor(QtGui.QColor('black'), QtGui.Qt.MaskOutColor)
pixmap.fill(color)
pixmap.setMask(mask)
return pixmap
def qicon():
ico = QtGui.QIcon("play-and-pause-button.svg")
ico2 = QtGui.QIcon(colorize(ico.pixmap(ico.actualSize(QtCore.QSize(1024, 1024))), QtGui.QColor('red')))
msg_box = QtWidgets.QMessageBox()
msg_box.setWindowTitle("Show Icon")
button = QtWidgets.QPushButton(msg_box)
button.setIcon(ico2)
button.setText("PlayPause")
msg_box.exec_()
#qpixmap2()
#qpixmap()
#basic()
qicon()
# annotate inline strings that are assembled via one byte moves/pushes
#
annotation=""
for instruction in current_basic_block.get_disassembly_text():
if instruction.address >= current_selection[0] and instruction.address < current_selection[1]:
address = instruction.address
value = instruction.tokens[-1].value
operand = instruction.tokens[-1].operand
type = IntegerDisplayType.CharacterConstantDisplayType
current_function.set_int_display_type(address, value, operand, type)
annotation += chr(instruction.tokens[-1].value)
log_info("Adding comment for string: %s" % annotation)
current_function.set_comment_at(current_selection[0], annotation)
# shell out to swift-demangle to handle swift symbol names
#
import subprocess
result = subprocess.run(['/usr/bin/xcrun', '--find', 'swift-demangle'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
if result.returncode == 0:
demangle_str = result.stdout.decode('utf-8')
for f in bv.functions:
result = subprocess.run([demangle_str, '-simplified', '-compact', symbol], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
if result.returncode == 0:
f.name = demangle(f.name)
else:
log_error('Unable to find swift-demangle.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment