Skip to content

Instantly share code, notes, and snippets.

@utkonos
Created January 17, 2024 00:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save utkonos/0aa6e1d491b703489359ca40f1c1cb4d to your computer and use it in GitHub Desktop.
Save utkonos/0aa6e1d491b703489359ca40f1c1cb4d 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