From 8849fb2b2b8dc824bd3f17ce1026a04856477a94 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Sun, 4 Mar 2018 18:08:04 -0500 Subject: working division, prints, and metaclasses, but imports broken, still needs work --- python/examples/nes.py | 646 ------------------------------------------------- 1 file changed, 646 deletions(-) delete mode 100644 python/examples/nes.py (limited to 'python/examples/nes.py') diff --git a/python/examples/nes.py b/python/examples/nes.py deleted file mode 100644 index 00451abd..00000000 --- a/python/examples/nes.py +++ /dev/null @@ -1,646 +0,0 @@ -# Copyright (c) 2015-2017 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 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 -] - -NONE = 0 -ABS = 1 -ABS_DEST = 2 -ABS_X = 3 -ABS_X_DEST = 4 -ABS_Y = 5 -ABS_Y_DEST = 6 -ACCUM = 7 -ADDR = 8 -IMMED = 9 -IND = 10 -IND_X = 11 -IND_X_DEST = 12 -IND_Y = 13 -IND_Y_DEST = 14 -REL = 15 -ZERO = 16 -ZERO_DEST = 17 -ZERO_X = 18 -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 -] - -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 -] - -OperandTokens = [ - 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_pointer(2, value) - hi_addr = il.const_pointer(2, (value & 0xff00) | ((value + 1) & 0xff)) - lo = il.zero_extend(2, il.load(1, lo_addr)) - 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) - return il.load(2, il.const_pointer(2, value)) - - -def load_zero_page_16(il, value): - if il[value].operation == LowLevelILOperation.LLIL_CONST: - if il[value].constant == 0xff: - lo = il.zero_extend(2, il.load(1, il.const_pointer(2, 0xff))) - hi = il.shift_left(2, il.zero_extend(2, il.load(1, il.const_pointer(2, 0)), il.const(2, 8))) - return il.or_expr(2, lo, hi) - return il.load(2, il.const_pointer(2, il[value].constant)) - il.append(il.set_reg(1, LLIL_TEMP(0), value)) - value = il.reg(1, LLIL_TEMP(0)) - lo_addr = value - hi_addr = il.add(1, value, il.const(1, 1)) - lo = il.zero_extend(2, il.load(1, lo_addr)) - 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_pointer(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_pointer(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_pointer(2, value), # REL - lambda il, value: il.load(1, il.const_pointer(2, value)), # ZERO - lambda il, value: il.const_pointer(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 == LowLevelILOperation.LLIL_CONST: - t = il.get_label_for_address(Architecture['6502'], il[dest].constant) - if t is None: - t = LowLevelILLabel() - indirect = True - else: - indirect = False - f = LowLevelILLabel() - il.append(il.if_expr(cond, t, f)) - if indirect: - il.mark_label(t) - il.append(il.jump(dest)) - il.mark_label(f) - return None - - -def jump(il, dest): - label = None - if il[dest].operation == LowLevelILOperation.LLIL_CONST: - label = il.get_label_for_address(Architecture['6502'], il[dest].constant) - if label is None: - il.append(il.jump(dest)) - else: - 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) - i = il.flag_bit(1, "i", 2) - d = il.flag_bit(1, "d", 3) - b = il.flag_bit(1, "b", 4) - v = il.flag_bit(1, "v", 6) - s = il.flag_bit(1, "s", 7) - 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)))) - il.append(il.set_flag("z", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x02)))) - il.append(il.set_flag("i", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x04)))) - il.append(il.set_flag("d", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x08)))) - il.append(il.set_flag("b", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x10)))) - il.append(il.set_flag("v", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x40)))) - 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, il.flag("c"), 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(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(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), - "clc": lambda il, operand: il.set_flag("c", il.const(0, 0)), - "cld": lambda il, operand: il.set_flag("d", il.const(0, 0)), - "cli": lambda il, operand: il.set_flag("i", il.const(0, 0)), - "clv": lambda il, operand: il.set_flag("v", il.const(0, 0)), - "cmp": lambda il, operand: il.sub(1, il.reg(1, "a"), operand, flags = "czs"), - "cpx": lambda il, operand: il.sub(1, il.reg(1, "x"), operand, flags = "czs"), - "cpy": lambda il, operand: il.sub(1, il.reg(1, "y"), operand, flags = "czs"), - "dec": lambda il, operand: il.store(1, operand, il.sub(1, il.load(1, operand), il.const(1, 1), flags = "zs")), - "dex": lambda il, operand: il.set_reg(1, "x", il.sub(1, il.reg(1, "x"), il.const(1, 1), flags = "zs")), - "dey": lambda il, operand: il.set_reg(1, "y", il.sub(1, il.reg(1, "y"), il.const(1, 1), flags = "zs")), - "eor": lambda il, operand: il.set_reg(1, "a", il.xor_expr(1, il.reg(1, "a"), operand, flags = "zs")), - "inc": lambda il, operand: il.store(1, operand, il.add(1, il.load(1, operand), il.const(1, 1), flags = "zs")), - "inx": lambda il, operand: il.set_reg(1, "x", il.add(1, il.reg(1, "x"), il.const(1, 1), flags = "zs")), - "iny": lambda il, operand: il.set_reg(1, "y", il.add(1, il.reg(1, "y"), il.const(1, 1), flags = "zs")), - "jmp": lambda il, operand: jump(il, operand), - "jsr": lambda il, operand: il.call(operand), - "lda": lambda il, operand: il.set_reg(1, "a", operand, flags = "zs"), - "ldx": lambda il, operand: il.set_reg(1, "x", operand, flags = "zs"), - "ldy": lambda il, operand: il.set_reg(1, "y", operand, flags = "zs"), - "lsr": lambda il, operand: il.store(1, operand, il.logical_shift_right(1, il.load(1, operand), il.const(1, 1), flags = "czs")), - "lsr@": lambda il, operand: il.set_reg(1, "a", il.logical_shift_right(1, il.reg(1, "a"), il.const(1, 1), flags = "czs")), - "nop": lambda il, operand: il.nop(), - "ora": lambda il, operand: il.set_reg(1, "a", il.or_expr(1, il.reg(1, "a"), operand, flags = "zs")), - "pha": lambda il, operand: il.push(1, il.reg(1, "a")), - "php": lambda il, operand: il.push(1, get_p_value(il)), - "pla": lambda il, operand: il.set_reg(1, "a", il.pop(1), flags = "zs"), - "plp": lambda il, operand: set_p_value(il, il.pop(1)), - "rol": lambda il, operand: il.store(1, operand, il.rotate_left_carry(1, il.load(1, operand), il.const(1, 1), il.flag("c"), flags = "czs")), - "rol@": lambda il, operand: il.set_reg(1, "a", il.rotate_left_carry(1, il.reg(1, "a"), il.const(1, 1), il.flag("c"), flags = "czs")), - "ror": lambda il, operand: il.store(1, operand, il.rotate_right_carry(1, il.load(1, operand), il.const(1, 1), il.flag("c"), flags = "czs")), - "ror@": lambda il, operand: il.set_reg(1, "a", il.rotate_right_carry(1, il.reg(1, "a"), il.const(1, 1), il.flag("c"), flags = "czs")), - "rti": lambda il, operand: rti(il), - "rts": lambda il, operand: il.ret(il.add(2, il.pop(2), il.const(2, 1))), - "sbc": lambda il, operand: il.set_reg(1, "a", il.sub_borrow(1, il.reg(1, "a"), operand, il.flag("c"), flags = "*")), - "sec": lambda il, operand: il.set_flag("c", il.const(0, 1)), - "sed": lambda il, operand: il.set_flag("d", il.const(0, 1)), - "sei": lambda il, operand: il.set_flag("i", il.const(0, 1)), - "sta": lambda il, operand: il.store(1, operand, il.reg(1, "a")), - "stx": lambda il, operand: il.store(1, operand, il.reg(1, "x")), - "sty": lambda il, operand: il.store(1, operand, il.reg(1, "y")), - "tax": lambda il, operand: il.set_reg(1, "x", il.reg(1, "a"), flags = "zs"), - "tay": lambda il, operand: il.set_reg(1, "y", il.reg(1, "a"), flags = "zs"), - "tsx": lambda il, operand: il.set_reg(1, "x", il.reg(1, "s"), flags = "zs"), - "txa": lambda il, operand: il.set_reg(1, "a", il.reg(1, "x"), flags = "zs"), - "txs": lambda il, operand: il.set_reg(1, "s", il.reg(1, "x")), - "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 - instr_alignment = 1 - max_instr_length = 3 - regs = { - "a": RegisterInfo("a", 1), - "x": RegisterInfo("x", 1), - "y": RegisterInfo("y", 1), - "s": RegisterInfo("s", 1) - } - stack_pointer = "s" - flags = ["c", "z", "i", "d", "b", "v", "s"] - flag_write_types = ["*", "czs", "zvs", "zs"] - flag_roles = { - "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 = { - 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"], - "czs": ["c", "z", "s"], - "zvs": ["z", "v", "s"], - "zs": ["z", "s"] - } - - def decode_instruction(self, data, addr): - if len(data) < 1: - return None, None, None, None - opcode = ord(data[0]) - instr = InstructionNames[opcode] - if instr is None: - return None, None, None, None - - operand = InstructionOperandTypes[opcode] - length = 1 + OperandLengths[operand] - if len(data) < length: - return None, None, None, None - - if OperandLengths[operand] == 0: - value = None - elif operand == REL: - value = (addr + 2 + struct.unpack("b", data[1])[0]) & 0xffff - elif OperandLengths[operand] == 1: - value = ord(data[1]) - else: - value = struct.unpack("> 4) - self.ram_banks = struct.unpack("B", hdr[8])[0] - self.rom_offset = 16 - if self.rom_flags & 4: - 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("= 0x8000: - self.add_function(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 struct.unpack(" Date: Thu, 5 Jul 2018 18:28:59 -0400 Subject: Rebased so commit history is correct now --- .gitignore | 6 - python/__init__.py | 1 + python/downloadprovider.py | 1 - python/examples/README.md | 56 +++ python/examples/angr_plugin.py | 153 +++++++ python/examples/arch_hook.py | 16 + python/examples/bin_info.py | 76 ++++ python/examples/breakpoint.py | 50 +++ python/examples/export_svg.py | 224 ++++++++++ python/examples/instruction_iterator.py | 53 +++ python/examples/jump_table.py | 86 ++++ python/examples/nds.py | 120 ++++++ python/examples/nes.py | 650 ++++++++++++++++++++++++++++++ python/examples/notification_callbacks.py | 74 ++++ python/examples/nsf.py | 145 +++++++ python/examples/print_syscalls.py | 55 +++ python/examples/version_switcher.py | 150 +++++++ python/function.py | 14 +- python/plugin.py | 32 +- suite/generator.py | 1 + suite/oracle.pkl | Bin 9098577 -> 440689 bytes suite/testcommon.py | 6 +- suite/unit.py | 7 +- 23 files changed, 1937 insertions(+), 39 deletions(-) create mode 100644 python/examples/README.md create mode 100644 python/examples/angr_plugin.py create mode 100644 python/examples/arch_hook.py create mode 100644 python/examples/bin_info.py create mode 100644 python/examples/breakpoint.py create mode 100755 python/examples/export_svg.py create mode 100644 python/examples/instruction_iterator.py create mode 100644 python/examples/jump_table.py create mode 100644 python/examples/nds.py create mode 100644 python/examples/nes.py create mode 100644 python/examples/notification_callbacks.py create mode 100644 python/examples/nsf.py create mode 100644 python/examples/print_syscalls.py create mode 100644 python/examples/version_switcher.py (limited to 'python/examples/nes.py') diff --git a/.gitignore b/.gitignore index eff64eb4..302ad960 100644 --- a/.gitignore +++ b/.gitignore @@ -33,14 +33,8 @@ api-docs/source/index.rst .coverage # Make generator -libcrypto.so.1.0.2 -libcurl.so.4 -libssl.so.1.0.2 plugins/ python/examples/binaryninja/ -python/libcrypto.so.1.0.2 -python/libcurl.so.4 -python/libssl.so.1.0.2 python/plugins/ python/types/ suite/binaryninja/ diff --git a/python/__init__.py b/python/__init__.py index e1288b0a..36ed4f0d 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -108,6 +108,7 @@ from binaryninja.lineardisassembly import * from binaryninja.undoaction import * from binaryninja.highlight import * from binaryninja.scriptingprovider import * +from binaryninja.downloadprovider import * from binaryninja.pluginmanager import * from binaryninja.setting import * from binaryninja.metadata import * diff --git a/python/downloadprovider.py b/python/downloadprovider.py index c714cb98..09abd516 100644 --- a/python/downloadprovider.py +++ b/python/downloadprovider.py @@ -20,7 +20,6 @@ import abc -import code import ctypes import sys import traceback diff --git a/python/examples/README.md b/python/examples/README.md new file mode 100644 index 00000000..43af34be --- /dev/null +++ b/python/examples/README.md @@ -0,0 +1,56 @@ +# Binary Ninja Python API Examples + +The following examples demonstrate some of the Binary Ninja API. They include both stand-alone examples that directly call into the core without a GUI, as well as examples meant to be loaded as plugins available from the UI. + +## Stand-alone + +These plugins only operate when run directly outside of the UI + +* 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 +``` + +## GUI Plugins + +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 - 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. + +### OSX + +``` +~/Library/Application Support/Binary Ninja/plugins +``` + +### Windows + +``` +%APPDATA%\Binary Ninja\plugins +``` + +### Linux + +``` +~/.binaryninja/plugins +``` diff --git a/python/examples/angr_plugin.py b/python/examples/angr_plugin.py new file mode 100644 index 00000000..26f8040c --- /dev/null +++ b/python/examples/angr_plugin.py @@ -0,0 +1,153 @@ +# Copyright (c) 2015-2017 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, MessageBoxIcon + +# 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, MessageBoxIcon.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/arch_hook.py b/python/examples/arch_hook.py new file mode 100644 index 00000000..452bd2b6 --- /dev/null +++ b/python/examples/arch_hook.py @@ -0,0 +1,16 @@ +from binaryninja.architecture import Architecture, ArchitectureHook + +class X86ReturnHook(ArchitectureHook): + def get_instruction_text(self, data, addr): + # Call the original implementation's method by calling the superclass + result, length = super(X86ReturnHook, self).get_instruction_text(data, addr) + + # Patch the name of the 'retn' instruction to 'ret' + if len(result) > 0 and result[0].text == 'retn': + result[0].text = 'ret' + + return result, length + +# Install the hook by constructing it with the desired architecture to hook, then registering it +X86ReturnHook(Architecture['x86']).register() + diff --git a/python/examples/bin_info.py b/python/examples/bin_info.py new file mode 100644 index 00000000..05a72ed0 --- /dev/null +++ b/python/examples/bin_info.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# Copyright (c) 2015-2017 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 + +# 2-3 compatibility +from binaryninja import range + + +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.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 range(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 range(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 new file mode 100644 index 00000000..cbcb86d4 --- /dev/null +++ b/python/examples/breakpoint.py @@ -0,0 +1,50 @@ +# Copyright (c) 2015-2017 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: + register + register_for_address + register_for_function + """ + 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 new file mode 100755 index 00000000..5bb27824 --- /dev/null +++ b/python/examples/export_svg.py @@ -0,0 +1,224 @@ +# from binaryninja import * +import os +import webbrowser +import time +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 = { + "'": "'", + ">": ">", + "<": "<", + '"': """, + ' ': " " +} + + +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, origname) + 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 = binaryninja.function.view.get_instruction_length(address) + bytes = binaryninja.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, origname): + graph = binaryninja.function.create_graph() + graph.layout_and_wait() + heightconst = 15 + ratio = 0.48 + widthconst = heightconst * ratio + + output = ''' + + + + +''' + output += ''' + + + + + + + + + + + + + + + '''.format(width=graph.width * widthconst + 20, height=graph.height * heightconst + 20) + output += ''' + Function Graph 0 + ''' + 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 += ' \n'.format(i=i) + output += ' Basic Block {i}\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 += ' \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 += ' \n'.format(x=x, y=y + (i + 1) * heightconst) + for i, line in enumerate(block.lines): + output += ' '.format(x=x + 6, y=y + 6 + (i + 0.7) * heightconst, address=hex(line.address)[:-1]) + hover = instruction_data_flow(function, line.address) + output += '{hover}'.format(hover=hover) + for token in line.tokens: + # TODO: add hover for hex, function, and reg tokens + output += '{text}'.format(text=escape(token.text), tokentype=InstructionTextTokenType(token.type).name) + output += '\n' + output += ' \n' + output += ' \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 += ' \n'.format(type=BranchType(edge.type).name, points=points) + else: + edges += ' \n'.format(type=BranchType(edge.type).name, points=points) + output += ' ' + edges + '\n' + output += ' \n' + output += '' + + output += '

This CFG generated by Binary Ninja from {filename} on {timestring}.

'.format(filename = origname, timestring = time.strftime("%c")) + output += '' + 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 new file mode 100644 index 00000000..f55e1c1b --- /dev/null +++ b/python/examples/instruction_iterator.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# Copyright (c) 2015-2017 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 new file mode 100644 index 00000000..4ed8dda2 --- /dev/null +++ b/python/examples/jump_table.py @@ -0,0 +1,86 @@ +# Copyright (c) 2015-2017 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.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 + arch = func.arch + addrsize = arch.address_size + + # Grab the instruction tokens so that we can look for the table's starting address + tokens, length = arch.get_instruction_text(bv.read(addr, 16), addr) + + # Look for the next jump instruction, which may be the current instruction. Some jump tables will + # compute the address first then jump to the computed address as a separate instruction. + jump_addr = addr + while jump_addr < block.end: + info = arch.get_instruction_info(bv.read(jump_addr, 16), jump_addr) + if len(info.branches) != 0: + break + jump_addr += info.length + if jump_addr >= block.end: + print("Unable to find jump after instruction 0x%x" % addr) + continue + print("Jump at 0x%x" % jump_addr) + + # Collect the branch targets for any tables referenced by the clicked instruction + branches = [] + for token in tokens: + 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 + while True: + # Read the next pointer from the table + data = bv.read(tbl + (i * addrsize), addrsize) + if len(data) == addrsize: + if addrsize == 4: + ptr = struct.unpack("= bv.start) and (ptr < bv.end): + print("Found destination 0x%x" % ptr) + branches.append((arch, ptr)) + else: + # Once a value that is not a pointer is encountered, the jump table is ended + break + else: + # Reading invalid memory + break + + i += 1 + + # Set the indirect branch targets on the jump instruction to be the list of targets discovered + 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 +PluginCommand.register_for_address("Process jump table", "Look for jump table destinations", find_jump_table) diff --git a/python/examples/nds.py b/python/examples/nds.py new file mode 100644 index 00000000..a99303cf --- /dev/null +++ b/python/examples/nds.py @@ -0,0 +1,120 @@ +# Copyright (c) 2015-2017 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 + +# 2-3 compatibility +from binaryninja import range + + +def crc16(data): + crc = 0xffff + for ch in data: + crc ^= ord(ch) + for bit in range(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("> 4) + self.ram_banks = struct.unpack("B", hdr[8])[0] + self.rom_offset = 16 + if self.rom_flags & 4: + 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("= 0x8000: + self.add_function(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 struct.unpack("'.format(sys.argv[0])) + else: + print_syscalls(sys.argv[1]) diff --git a/python/examples/version_switcher.py b/python/examples/version_switcher.py new file mode 100644 index 00000000..c990a6c0 --- /dev/null +++ b/python/examples/version_switcher.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +# Copyright (c) 2015-2017 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 + +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 = UpdateChannel.list[0].name +channel = None +versions = [] + + +def load_channel(newchannel): + global channel + global versions + if (channel is not None and newchannel == channel.name): + print("Same channel, not updating.") + else: + try: + print("Loading channel %s" % newchannel) + channel = UpdateChannel[newchannel] + print("Loading versions...") + versions = channel.versions + except Exception: + print("%s is not a valid channel name. Defaulting to " % chandefault) + channel = UpdateChannel[chandefault] + + +def select(version): + done = False + date = datetime.datetime.fromtimestamp(version.time).strftime('%c') + while not done: + print("Version:\t%s" % version.version) + print("Updated:\t%s" % date) + print("Notes:\n\n-----\n%s" % version.notes) + print("-----") + print("\t1)\tSwitch to version") + print("\t2)\tMain Menu") + selection = raw_input('Choice: ') + if selection.isdigit(): + selection = int(selection) + else: + selection = 0 + if (selection == 2): + done = True + elif (selection == 1): + if (version.version == channel.latest_version.version): + print("Requesting update to latest version.") + else: + print("Requesting update to prior version.") + if are_auto_updates_enabled(): + print("Disabling automatic updates.") + set_auto_updates_enabled(False) + if (version.version == core_version): + print("Already running %s" % version.version) + else: + print("version.version %s" % version.version) + print("core_version %s" % core_version) + print("Downloading...") + print(version.update()) + 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 = 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")) + selection = raw_input('Choice: ') + if selection.isdigit(): + selection = int(selection) + else: + selection = 0 + 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(): + set_auto_updates_enabled(not are_auto_updates_enabled()) + + +def main(): + global channel + done = False + load_channel(chandefault) + while not done: + print("\n\tBinary Ninja Version Switcher") + print("\t\tCurrent Channel:\t%s" % channel.name) + 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)) + print("\t%d)\t%s" % (len(versions) + 1, "Switch Channel")) + print("\t%d)\t%s" % (len(versions) + 2, "Toggle Auto Updates")) + print("\t%d)\t%s" % (len(versions) + 3, "Exit")) + selection = raw_input('Choice: ') + if selection.isdigit(): + selection = int(selection) + else: + selection = 0 + if (selection <= 0 or selection > len(versions) + 3): + print("%d is an invalid choice.\n\n" % selection) + else: + if (selection == len(versions) + 3): + done = True + elif (selection == len(versions) + 2): + toggle_updates() + elif (selection == len(versions) + 1): + list_channels() + else: + select(versions[selection - 1]) + + +if __name__ == "__main__": + main() diff --git a/python/function.py b/python/function.py index 8407eece..0589a5e2 100644 --- a/python/function.py +++ b/python/function.py @@ -26,7 +26,7 @@ import ctypes # Binary Ninja components import binaryninja from binaryninja import _binaryninjacore as core -from binaryninja import associateddatastore #required in the main scope due to being an argument for _FunctionAssociatedDataStore +from binaryninja import associateddatastore # Required in the main scope due to being an argument for _FunctionAssociatedDataStore from binaryninja import highlight from binaryninja import log from binaryninja import types @@ -1631,7 +1631,7 @@ class FunctionGraphEdge(object): class FunctionGraphBlock(object): - def __init__(self, handle): + def __init__(self, handle, graph): self.handle = handle self.graph = graph @@ -1657,14 +1657,14 @@ class FunctionGraphBlock(object): core.BNFreeBasicBlock(block) return None - view = binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle)) + view = binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle)) func = Function(view, func_handle) if core.BNIsLowLevelILBasicBlock(block): - block = lowlevelil.LowLevelILBasicBlock(view, block, + block = binaryninja.lowlevelil.LowLevelILBasicBlock(view, block, lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func)) elif core.BNIsMediumLevelILBasicBlock(block): - block = mediumlevelil.MediumLevelILBasicBlock(view, block, + block = binaryninja.mediumlevelil.MediumLevelILBasicBlock(view, block, mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func)) else: block = binaryninja.basicblock.BasicBlock(view, block) @@ -1942,12 +1942,12 @@ class FunctionGraph(object): il_func = core.BNGetFunctionGraphLowLevelILFunction(self.handle) if not il_func: return None - return lowlevelil.LowLevelILFunction(self.function.arch, il_func, self.function) + return binaryninja.lowlevelil.LowLevelILFunction(self.function.arch, il_func, self.function) if self.is_medium_level_il: il_func = core.BNGetFunctionGraphMediumLevelILFunction(self.handle) if not il_func: return None - return mediumlevelil.MediumLevelILFunction(self.function.arch, il_func, self.function) + return binaryninja.mediumlevelil.MediumLevelILFunction(self.function.arch, il_func, self.function) return None def __setattr__(self, name, value): diff --git a/python/plugin.py b/python/plugin.py index b8217f0b..2fc30052 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -121,7 +121,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): try: file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) - func_obj = binaryninja.function.Function(view_obj, core.BNNewFunctionReference(func)) + func_obj = function.Function(view_obj, core.BNNewFunctionReference(func)) action(view_obj, func_obj) except: log.log_error(traceback.format_exc()) @@ -132,7 +132,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) - func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) action(view_obj, func_obj) except: log.log_error(traceback.format_exc()) @@ -143,7 +143,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) - func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) action(view_obj, func_obj[instr]) except: log.log_error(traceback.format_exc()) @@ -154,7 +154,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) - func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) action(view_obj, func_obj) except: log.log_error(traceback.format_exc()) @@ -165,7 +165,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) - func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) action(view_obj, func_obj[instr]) except: log.log_error(traceback.format_exc()) @@ -213,7 +213,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): return True file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) - func_obj = binaryninja.function.Function(view_obj, core.BNNewFunctionReference(func)) + func_obj = function.Function(view_obj, core.BNNewFunctionReference(func)) return is_valid(view_obj, func_obj) except: log.log_error(traceback.format_exc()) @@ -227,7 +227,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) - func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) return is_valid(view_obj, func_obj) except: log.log_error(traceback.format_exc()) @@ -241,7 +241,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) - func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) return is_valid(view_obj, func_obj[instr]) except: log.log_error(traceback.format_exc()) @@ -255,7 +255,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) - func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) return is_valid(view_obj, func_obj) except: log.log_error(traceback.format_exc()) @@ -269,7 +269,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) - func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) return is_valid(view_obj, func_obj[instr]) except: log.log_error(traceback.format_exc()) @@ -364,7 +364,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): .. warning:: Calling ``register_for_low_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin. """ - startup._init_plugins() + binaryninja.startup._init_plugins() action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_action(view, func, action)) is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_is_valid(view, func, is_valid)) cls._registered_commands.append((action_obj, is_valid_obj)) @@ -383,7 +383,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): .. warning:: Calling ``register_for_low_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin. """ - startup._init_plugins() + binaryninja.startup._init_plugins() action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_action(view, func, instr, action)) is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_is_valid(view, func, instr, is_valid)) cls._registered_commands.append((action_obj, is_valid_obj)) @@ -402,7 +402,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): .. warning:: Calling ``register_for_medium_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin. """ - startup._init_plugins() + binaryninja.startup._init_plugins() action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_action(view, func, action)) is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_is_valid(view, func, is_valid)) cls._registered_commands.append((action_obj, is_valid_obj)) @@ -421,7 +421,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): .. warning:: Calling ``register_for_medium_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin. """ - startup._init_plugins() + binaryninja.startup._init_plugins() action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_action(view, func, instr, action)) is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_is_valid(view, func, instr, is_valid)) cls._registered_commands.append((action_obj, is_valid_obj)) @@ -469,7 +469,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): elif self.command.type == PluginCommandType.LowLevelILInstructionPluginCommand: if context.instruction is None: return False - if not isinstance(context.instruction, lowlevelil.LowLevelILInstruction): + if not isinstance(context.instruction, binaryninja.lowlevelil.LowLevelILInstruction): return False if not self.command.lowLevelILInstructionIsValid: return True @@ -484,7 +484,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): elif self.command.type == PluginCommandType.MediumLevelILInstructionPluginCommand: if context.instruction is None: return False - if not isinstance(context.instruction, mediumlevelil.MediumLevelILInstruction): + if not isinstance(context.instruction, binaryninja.mediumlevelil.MediumLevelILInstruction): return False if not self.command.mediumLevelILInstructionIsValid: return True diff --git a/suite/generator.py b/suite/generator.py index ad0d24fc..f4ee69ee 100755 --- a/suite/generator.py +++ b/suite/generator.py @@ -22,6 +22,7 @@ from collections import Counter global verbose verbose = False + class TestBinaryNinjaAPI(unittest.TestCase): # Returns a tuple of: # bool : Two lists are equal diff --git a/suite/oracle.pkl b/suite/oracle.pkl index d7ce1115..f0be17d4 100644 Binary files a/suite/oracle.pkl and b/suite/oracle.pkl differ diff --git a/suite/testcommon.py b/suite/testcommon.py index ef85c053..07ceb592 100644 --- a/suite/testcommon.py +++ b/suite/testcommon.py @@ -541,6 +541,7 @@ class TestBuilder(Builder): """Types produced different result""" file_name = os.path.join(self.test_store, "helloworld") bv = binja.BinaryViewType.get_view_of_file(file_name) + preprocessed = binja.preprocess_source(""" #ifdef nonexistant int foo = 1; @@ -550,7 +551,7 @@ class TestBuilder(Builder): long long bar1 = 2; #endif """) - source = '\n'.join([i.decode('utf-8') for i in preprocessed[0].split(b'\n') if not b'#line' in i and len(i) > 0]) + source = '\n'.join([i.decode('charmap') for i in preprocessed[0].split(b'\n') if not b'#line' in i and len(i) > 0]) typelist = bv.platform.parse_types_from_source(source) inttype = binja.Type.int(4) @@ -566,14 +567,13 @@ class TestBuilder(Builder): retinfo.append("Type equality: " + str((inttype == inttype) and not (inttype != inttype))) return retinfo - def test_Plugin_bin_info(self): """print_syscalls plugin produced different result""" file_name = os.path.join(self.test_store, "helloworld") self.unpackage_file(file_name) result = subprocess.Popen(["python", os.path.join(self.examples_dir, "bin_info.py"), file_name], stdout=subprocess.PIPE).communicate()[0] # normalize line endings and path sep - return [result.replace(b"\\", b"/").replace(b"\r\n", b"\n").decode("charmap")] + return [line for line in result.replace(b"\\", b"/").replace(b"\r\n", b"\n").decode("charmap").split("\n")] def test_linear_disassembly(self): """linear_disassembly produced different result""" diff --git a/suite/unit.py b/suite/unit.py index 9cbed511..e01b0f19 100644 --- a/suite/unit.py +++ b/suite/unit.py @@ -13,6 +13,7 @@ from collections import Counter global verbose verbose = False + class TestBinaryNinjaAPI(unittest.TestCase): # Returns a tuple of: # bool : Two lists are equal @@ -235,12 +236,6 @@ class TestBinaryNinjaAPI(unittest.TestCase): def test_binary___loop_constant_propagate(self): self.run_binary_test('suite/binaries/test_corpus/loop_constant_propagate.zip') - def test_binary___ls(self): - self.run_binary_test('suite/binaries/test_corpus/ls.zip') - - def test_binary___md5(self): - self.run_binary_test('suite/binaries/test_corpus/md5.zip') - def test_binary___partial_register_dataflow(self): self.run_binary_test('suite/binaries/test_corpus/partial_register_dataflow.zip') -- cgit v1.3.1