Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stvemillertime/2a58e95b29dca434ec344c7e9d26b047 to your computer and use it in GitHub Desktop.
Save stvemillertime/2a58e95b29dca434ec344c7e9d26b047 to your computer and use it in GitHub Desktop.
Binary Ninja plugin for copying opcode bytes to the clipboard formatted to YARA best practice
"""Binary Ninja plugin for copying opcode bytes to the clipboard formatted to YARA best practice."""
import json
from binaryninja.enums import InstructionTextTokenType, LinearDisassemblyLineType
from binaryninja.interaction import get_text_line_input
from binaryninja.plugin import PluginCommand
from binaryninja.settings import Settings
import PySide6
s = Settings()
s.register_group('c', 'Copy Bytes')
setting = {
'description': 'YARA format bytes copied as uppercase.',
'title': 'Uppercase Bytes',
'default': False,
'type': 'boolean'
}
s.register_setting('c.upper', json.dumps(setting))
def get_texts(bv, addr, end):
"""Get the opcode and disassembly texts in an address range."""
pos = bv.get_linear_disassembly_position_at(addr)
opcode_bytes = list()
disasm_text = list()
l_types = [LinearDisassemblyLineType.CodeDisassemblyLineType, LinearDisassemblyLineType.CodeDisassemblyLineType]
while True:
lines = bv.get_next_linear_disassembly_lines(pos)
exit = False
for line in lines:
if line.contents.address < addr:
continue
if line.contents.address >= end:
exit = True
break
if line.type not in l_types:
continue
for token in line.contents.tokens:
if token.type is InstructionTextTokenType.OpcodeToken:
if s.get_bool('c.upper'):
out = token.text.upper()
else:
out = token.text
opcode_bytes.append(out)
line_text = ''.join([t.text for t in line.contents.tokens])
disasm_text.append(line_text)
if exit:
break
return opcode_bytes, disasm_text
def format_output(bv, addr, length, yara_string=False, named=False):
"""Copy properly formatted bytes to the clipboard."""
end = addr + length
opcode_bytes, disasm_text = get_texts(bv, addr, end)
# Copy decoded string to clipboard.
clip = PySide6.QtGui.QGuiApplication.clipboard()
opcode_output = ' '.join(opcode_bytes)
if named:
var_name = get_text_line_input('Variable Name', 'Name YARA Variable').decode()
else:
var_name = str()
if yara_string:
template = ' ${} = {{ {} }}\n{}\n'
indent = '\n' + ' '*12 + '// '
disasm_output = indent.join(disasm_text)
output = template.format(var_name, opcode_output, disasm_output)
else:
output = opcode_output
clip.setText(output)
def format_opcode(bv, addr, length):
"""Output a YARA formatted opcode string."""
format_output(bv, addr, length)
def format_yara_string(bv, addr, length):
"""Output a formatted YARA string."""
format_output(bv, addr, length, yara_string=True)
def format_named_yara_string(bv, addr, length):
"""Output a formatted YARA string."""
format_output(bv, addr, length, yara_string=True, named=True)
description = 'Copy YARA format opcodes to clipboard for selected instructions.'
PluginCommand.register_for_range('Copy YARA format opcodes', description, format_opcode)
description = 'Copy fully formatted YARA string to clipboard for selected instructions.'
PluginCommand.register_for_range('Copy YARA string', description, format_yara_string)
description = 'Copy fully formatted named YARA string to clipboard for selected instructions.'
PluginCommand.register_for_range('Copy named YARA string', description, format_named_yara_string)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment