Created
January 17, 2024 00:56
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""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