Commit ff54c6ff by devttys0

Added opcodes module.

parent a51332af
...@@ -7,7 +7,7 @@ class Display(object): ...@@ -7,7 +7,7 @@ class Display(object):
HEADER_WIDTH = 150 HEADER_WIDTH = 150
DEFAULT_FORMAT = "%s\n" DEFAULT_FORMAT = "%s\n"
def __init__(self, quiet=False, verbose=0, log=None, csv=False, fit_to_screen=False): def __init__(self, quiet=False, verbose=False, log=None, csv=False, fit_to_screen=False):
self.quiet = quiet self.quiet = quiet
self.verbose = verbose self.verbose = verbose
self.fit_to_screen = fit_to_screen self.fit_to_screen = fit_to_screen
......
...@@ -78,6 +78,7 @@ class Result(object): ...@@ -78,6 +78,7 @@ class Result(object):
@valid - Set to True if the result if value, False if invalid. @valid - Set to True if the result if value, False if invalid.
@display - Set to True to display the result to the user, False to hide it. @display - Set to True to display the result to the user, False to hide it.
@extract - Set to True to flag this result for extraction. @extract - Set to True to flag this result for extraction.
@plot - Set to Flase to exclude this result from entropy plots.
Provide additional kwargs as necessary. Provide additional kwargs as necessary.
Returns None. Returns None.
...@@ -88,6 +89,7 @@ class Result(object): ...@@ -88,6 +89,7 @@ class Result(object):
self.valid = True self.valid = True
self.display = True self.display = True
self.extract = True self.extract = True
self.plot = True
for (k, v) in iterator(kwargs): for (k, v) in iterator(kwargs):
setattr(self, k, v) setattr(self, k, v)
...@@ -298,9 +300,9 @@ class Module(object): ...@@ -298,9 +300,9 @@ class Module(object):
self.results.append(r) self.results.append(r)
# Update the progress status automatically if it is not being done manually by the module # Update the progress status automatically if it is not being done manually by the module
if r.file and self.AUTO_UPDATE_STATUS: if r.offset and self.AUTO_UPDATE_STATUS:
self.status.total = r.file.length self.status.total = r.file.length
self.status.completed = r.file.tell() - r.file.offset self.status.completed = r.offset
if r.display: if r.display:
display_args = self._build_display_args(r) display_args = self._build_display_args(r)
......
...@@ -5,3 +5,4 @@ from binwalk.modules.hashmatch import HashMatch ...@@ -5,3 +5,4 @@ from binwalk.modules.hashmatch import HashMatch
from binwalk.modules.configuration import Configuration from binwalk.modules.configuration import Configuration
from binwalk.modules.extractor import Extractor from binwalk.modules.extractor import Extractor
from binwalk.modules.entropy import Entropy from binwalk.modules.entropy import Entropy
from binwalk.modules.opcodes import OpcodeValidator
...@@ -53,7 +53,7 @@ class Configuration(Module): ...@@ -53,7 +53,7 @@ class Configuration(Module):
description='Supress output to stdout'), description='Supress output to stdout'),
Option(long='verbose', Option(long='verbose',
short='v', short='v',
kwargs={'verbose' : 1}, kwargs={'verbose' : True},
description='Enable verbose output'), description='Enable verbose output'),
Option(short='h', Option(short='h',
long='help', long='help',
...@@ -74,7 +74,7 @@ class Configuration(Module): ...@@ -74,7 +74,7 @@ class Configuration(Module):
Kwarg(name='csv', default=False), Kwarg(name='csv', default=False),
Kwarg(name='format_to_terminal', default=False), Kwarg(name='format_to_terminal', default=False),
Kwarg(name='quiet', default=False), Kwarg(name='quiet', default=False),
Kwarg(name='verbose', default=0), Kwarg(name='verbose', default=False),
Kwarg(name='files', default=[]), Kwarg(name='files', default=[]),
Kwarg(name='show_help', default=False), Kwarg(name='show_help', default=False),
] ]
...@@ -119,8 +119,8 @@ class Configuration(Module): ...@@ -119,8 +119,8 @@ class Configuration(Module):
''' '''
# If more than one target file was specified, enable verbose mode; else, there is # If more than one target file was specified, enable verbose mode; else, there is
# nothing in some outputs to indicate which scan corresponds to which file. # nothing in some outputs to indicate which scan corresponds to which file.
if len(self.target_files) > 1 and self.verbose == 0: if len(self.target_files) > 1 and not self.verbose:
self.verbose = 1 self.verbose = True
def open_file(self, fname, length=None, offset=None, swap=None): def open_file(self, fname, length=None, offset=None, swap=None):
''' '''
......
import sys
import inspect
import binwalk.core.common
from binwalk.core.compat import *
from binwalk.core.module import Module, Option, Kwarg
class Operand(object):
def __init__(self, **kwargs):
self.valid = False
self.value = None
self.mnem = None
for (k, v) in iterator(kwargs):
setattr(self, k, v)
class Instruction(object):
BIG = 'big'
LITTLE = 'little'
def __init__(self, **kwargs):
self.valid = False
self.opcode = None
self.mnem = None
self.endianess = None
self.operands = []
self.size = 0
for (k, v) in iterator(kwargs):
setattr(self, k, v)
class Disassembler(object):
INSTRUCTION_SIZE = 4
OPCODE_INDEX = 0
OPCODE_MASK = 0
ENDIANESS = Instruction.BIG
def __init__(self):
self.confidence = 0.0
def pre_processor(self, data):
d = ''
if self.ENDIANESS == Instruction.LITTLE:
d = data[::-1]
else:
d = data
return d
def validate(self, instruction):
return None
def disassemble_opcode(self, ins, data):
ins.opcode = ord(data[self.OPCODE_INDEX]) & self.OPCODE_MASK
if ins.opcode in self.OPCODES:
ins.valid = True
else:
ins.valid = False
def disassemble(self, data):
data = self.pre_processor(data)
ins = Instruction(size=self.INSTRUCTION_SIZE, endianess=self.ENDIANESS)
self.disassemble_opcode(ins, data)
self.validate(ins)
return ins
class MIPS(Disassembler):
OPCODE_MASK = (0x3F << 2)
OPCODES = [
0x04 << 2, # beq
0x05 << 2, # bne
0x09 << 2, # addiu
0x08 << 2, # addi
0x0D << 2, # ori
0x23 << 2, # lw
0x2B << 2, # sw
0x0F << 2, # lui
]
class MIPSEL(MIPS):
ENDIANESS = Instruction.LITTLE
class ARMEB(Disassembler):
OPCODE_MASK = 0xF0
OPCODES = [0xE0]
class ARM(ARMEB):
ENDIANESS = Instruction.LITTLE
class OpcodeValidator(Module):
MIN_INS_COUNT = 6
MIN_CONFIDENCE = 0.0
TITLE = 'Opcode'
CLI = [
Option(short='A',
long='opcodes',
kwargs={'enabled' : True},
description='Scan files for executable opcodes'),
Option(short='a',
long='unaligned',
kwargs={'honor_instruction_alignment' : False},
description='Scan for opcodes at unaligned offsets'),
]
KWARGS = [
Kwarg(name='enabled', default=False),
Kwarg(name='honor_instruction_alignment', default=True),
]
def init(self):
self.disassemblers = {}
for (name, cls) in inspect.getmembers(sys.modules[__name__], inspect.isclass):
try:
obj = cls()
if isinstance(obj, Disassembler) and name != 'Disassembler':
self.disassemblers[obj] = 0
except TypeError:
pass
if self.config.verbose:
self.HEADER[-1] = 'EXECUTABLE CODE'
else:
self.HEADER = ['CONFIDENCE', 'FILE ARCHITECTURE']
self.HEADER_FORMAT = '%s %s'
self.RESULT = ['confidence', 'description']
self.RESULT_FORMAT = '%-7.2f %s'
def run(self):
for fp in self.config.target_files:
self.header()
for disassembler in self.search(fp):
if not self.config.verbose and disassembler.confidence > self.MIN_CONFIDENCE:
desc = disassembler.__class__.__name__ + " executable code, endianess: " + disassembler.ENDIANESS
self.result(description=desc, confidence=disassembler.confidence, file=fp, plot=False)
self.footer()
def is_valid_sequence(self, disassembler, data):
j = 0
retval = True
# Ignore blocks of NULL bytes
if data == "\x00" * len(data):
return False
while j < len(data):
ins = disassembler.disassemble(data[j:j+disassembler.INSTRUCTION_SIZE])
if not ins.valid:
retval = False
break
else:
j += disassembler.INSTRUCTION_SIZE
return retval
def search(self, fp):
while True:
i = 0
(data, dlen) = fp.read_block()
if not data:
break
while i < dlen:
count = 1
for disassembler in get_keys(self.disassemblers):
if self.honor_instruction_alignment and (i % disassembler.INSTRUCTION_SIZE):
continue
ins = disassembler.disassemble(data[i:i+disassembler.INSTRUCTION_SIZE])
if ins.valid:
sequence_size = self.MIN_INS_COUNT * disassembler.INSTRUCTION_SIZE
sequence = data[i:i+sequence_size]
if len(sequence) == sequence_size and self.is_valid_sequence(disassembler, sequence):
self.result(description=disassembler.__class__.__name__ + " instructions, endianess: " + disassembler.ENDIANESS,
offset=(fp.total_read - dlen + i),
file=fp,
display=self.config.verbose)
self.disassemblers[disassembler] += 1
count = disassembler.INSTRUCTION_SIZE * self.MIN_INS_COUNT
break
i += count
total_hits = 0
for (k, v) in iterator(self.disassemblers):
total_hits += v
for (k, v) in iterator(self.disassemblers):
k.confidence = ((v / float(total_hits)) * 100)
return sorted(self.disassemblers, key=self.disassemblers.get, reverse=True)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment