Commit 8ef8a797 by devttys0

Consolidated code into the binwalk.module.Module parent class.

parent f23e83b7
...@@ -3,6 +3,7 @@ import sys ...@@ -3,6 +3,7 @@ import sys
import inspect import inspect
import argparse import argparse
import binwalk.common import binwalk.common
import binwalk.loader
from binwalk.compat import * from binwalk.compat import *
class ModuleOption(object): class ModuleOption(object):
...@@ -108,7 +109,6 @@ class Module(object): ...@@ -108,7 +109,6 @@ class Module(object):
''' '''
All module classes must be subclassed from this. All module classes must be subclassed from this.
''' '''
# The module name, as displayed in help output # The module name, as displayed in help output
NAME = "" NAME = ""
...@@ -118,6 +118,9 @@ class Module(object): ...@@ -118,6 +118,9 @@ class Module(object):
# A list of binwalk.module.ModuleKwargs accepted by __init__ # A list of binwalk.module.ModuleKwargs accepted by __init__
KWARGS = [] KWARGS = []
# A dictionary of module dependencies; all modules depend on binwalk.modules.configuration.Configuration
DEPENDS = {}
# Format string for printing the header during a scan # Format string for printing the header during a scan
HEADER_FORMAT = "%s\n" HEADER_FORMAT = "%s\n"
...@@ -134,12 +137,19 @@ class Module(object): ...@@ -134,12 +137,19 @@ class Module(object):
# Note that these will be formatted per the RESULT_FORMAT format string. # Note that these will be formatted per the RESULT_FORMAT format string.
RESULT = ['offset', 'description'] RESULT = ['offset', 'description']
def __init__(self, **kwargs): def __init__(self, dependency=False, **kwargs):
# TODO: Instantiate plugins object # TODO: Instantiate plugins object
# self.plugins = x # self.plugins = x
self.errors = [] self.errors = []
self.results = [] self.results = []
process_kwargs(self, kwargs) process_kwargs(self, kwargs)
# If the module was loaded as a dependency, don't display or log any results
if dependency:
self.config.display.quiet = True
self.config.display.log = None
try: try:
self.load() self.load()
except KeyboardInterrupt as e: except KeyboardInterrupt as e:
...@@ -252,7 +262,7 @@ class Module(object): ...@@ -252,7 +262,7 @@ class Module(object):
def main(self): def main(self):
''' '''
Responsible for calling self.init, initializing self.config.display, printing the header and calling self.run. Responsible for calling self.init, initializing self.config.display, and calling self.run.
Returns the value returned from self.run. Returns the value returned from self.run.
''' '''
...@@ -264,7 +274,6 @@ class Module(object): ...@@ -264,7 +274,6 @@ class Module(object):
self.error(exception=e) self.error(exception=e)
return False return False
self.header()
self._plugins_pre_scan() self._plugins_pre_scan()
try: try:
...@@ -276,254 +285,29 @@ class Module(object): ...@@ -276,254 +285,29 @@ class Module(object):
return False return False
self._plugins_post_scan() self._plugins_post_scan()
self.footer()
return retval return retval
class Modules(object):
'''
Main class used for running and managing modules.
'''
def __init__(self, argv=sys.argv[1:], dummy=False):
'''
Class constructor.
@argv - List of command line options. Must not include the program name (sys.argv[0]).
@dummy - Set to True if you only need the class instance for interrogating modules (run, load, execute will not work).
Returns None.
'''
self.ok = True
self.config = None
self.arguments = argv
self.dependency_results = {}
if not dummy:
from binwalk.modules.configuration import Configuration
self.config = self.load(Configuration)
for e in self.config.errors:
if e.exception:
self.ok = False
break
def list(self, attribute="run"):
'''
Finds all modules with the specified attribute.
@attribute - The desired module attribute.
Returns a list of modules that contain the specified attribute.
'''
import binwalk.modules
modules = []
for (name, module) in inspect.getmembers(binwalk.modules):
if inspect.isclass(module) and hasattr(module, attribute):
modules.append(module)
return modules
def help(self):
help_string = ""
for obj in self.list(attribute="CLI"):
if obj.CLI:
help_string += "\n%s Options:\n" % obj.NAME
for module_option in obj.CLI:
if module_option.long:
long_opt = '--' + module_option.long
if module_option.nargs > 0:
optargs = "=%s" % module_option.dtype
else:
optargs = ""
if module_option.short:
short_opt = "-" + module_option.short + ","
else:
short_opt = " "
fmt = " %%s %%s%%-%ds%%s\n" % (32-len(long_opt))
help_string += fmt % (short_opt, long_opt, optargs, module_option.description)
return help_string
def execute(self):
run_modules = []
for module in self.list():
if self.run(module):
run_modules.append(module)
return run_modules
def run(self, module):
obj = self.load(module)
if isinstance(obj, Module) and obj.enabled:
try:
obj.main()
except AttributeError as e:
sys.stderr.write("WARNING: " + str(e) + "\n")
obj = None
else:
obj = None
return obj
def load(self, module):
if self.ok:
kwargs = self.argv(module, argv=self.arguments)
kwargs.update(self.dependencies(module))
return module(**kwargs)
else:
return None
def dependencies(self, module):
kwargs = {}
if self.ok and hasattr(module, "DEPENDS"):
# Disable output when modules are loaded as dependencies
orig_log = self.config.display.log
orig_quiet = self.config.display.quiet
self.config.display.log = False
self.config.display.quiet = True
for (kwarg, mod) in iterator(module.DEPENDS):
if not has_key(self.dependency_results, mod):
self.dependency_results[mod] = self.run(mod)
kwargs[kwarg] = self.dependency_results[mod]
self.config.display.log = orig_log
self.config.display.quiet = orig_quiet
return kwargs
def argv(self, module, argv=sys.argv[1:]):
'''
Processes argv for any options specific to the specified module.
@module - The module to process argv for.
@argv - A list of command line arguments (excluding argv[0]).
Returns a dictionary of kwargs for the specified module.
'''
kwargs = {}
last_priority = {}
longs = []
shorts = ""
parser = argparse.ArgumentParser(add_help=False)
if hasattr(module, "CLI"):
for module_option in module.CLI:
if not module_option.long:
continue
if module_option.nargs == 0:
action = 'store_true'
else:
action = None
if module_option.short:
parser.add_argument('-' + module_option.short, '--' + module_option.long, action=action, dest=module_option.long)
else:
parser.add_argument('--' + module_option.long, action=action, dest=module_option.long)
args, unknown = parser.parse_known_args(argv)
args = args.__dict__
for module_option in module.CLI:
if module_option.type in [io.FileIO, argparse.FileType, binwalk.common.BlockFile]:
for k in get_keys(module_option.kwargs):
kwargs[k] = []
for unk in unknown:
if not unk.startswith('-'):
kwargs[k].append(unk)
elif has_key(args, module_option.long) and args[module_option.long] not in [None, False]:
i = 0
for (name, value) in iterator(module_option.kwargs):
if not has_key(last_priority, name) or last_priority[name] <= module_option.priority:
if module_option.nargs > i:
value = args[module_option.long]
i += 1
last_priority[name] = module_option.priority
# Do this manually as argparse doesn't seem to be able to handle hexadecimal values
if module_option.type == int:
kwargs[name] = int(value, 0)
elif module_option.type == float:
kwargs[name] = float(value)
elif module_option.type == dict:
if not has_key(kwargs, name):
kwargs[name] = {}
kwargs[name][len(kwargs[name])] = value
elif module_option.type == list:
if not has_key(kwargs, name):
kwargs[name] = []
kwargs[name].append(value)
else:
kwargs[name] = value
else:
raise Exception("binwalk.module.Modules.argv: %s has no attribute 'CLI'" % str(module))
if self.config is not None and not has_key(kwargs, 'config'):
kwargs['config'] = self.config
if not has_key(kwargs, 'enabled'):
kwargs['enabled'] = False
return kwargs
def kwargs(self, module, kwargs):
'''
Processes a module's kwargs. All modules should use this for kwarg processing.
@module - An instance of the module (e.g., self)
@kwargs - The kwargs passed to the module
Returns None.
'''
if hasattr(module, "KWARGS"):
for module_argument in module.KWARGS:
if has_key(kwargs, module_argument.name):
arg_value = kwargs[module_argument.name]
else:
arg_value = module_argument.default
setattr(module, module_argument.name, arg_value)
for (k, v) in iterator(kwargs):
if not hasattr(module, k):
setattr(module, k, v)
else:
raise Exception("binwalk.module.Modules.process_kwargs: %s has no attribute 'KWARGS'" % str(module))
def process_kwargs(obj, kwargs): def process_kwargs(obj, kwargs):
''' '''
Convenience wrapper around binwalk.module.Modules.kwargs. Convenience wrapper around binwalk.loader.Modules.kwargs.
@obj - The class object (an instance of a sub-class of binwalk.module.Module). @obj - The class object (an instance of a sub-class of binwalk.module.Module).
@kwargs - The kwargs provided to the object's __init__ method. @kwargs - The kwargs provided to the object's __init__ method.
Returns None. Returns None.
''' '''
return Modules(dummy=True).kwargs(obj, kwargs) return binwalk.loader.Modules().kwargs(obj, kwargs)
def show_help(fd=sys.stdout): def show_help(fd=sys.stdout):
''' '''
Convenience wrapper around binwalk.module.Modules.help. Convenience wrapper around binwalk.loader.Modules.help.
@fd - An object with a write method (e.g., sys.stdout, sys.stderr, etc). @fd - An object with a write method (e.g., sys.stdout, sys.stderr, etc).
Returns None. Returns None.
''' '''
fd.write(Modules(dummy=True).help()) fd.write(binwalk.loader.Modules().help())
...@@ -2,6 +2,7 @@ import os ...@@ -2,6 +2,7 @@ import os
import binwalk.module import binwalk.module
from binwalk.compat import * from binwalk.compat import *
from binwalk.common import BlockFile from binwalk.common import BlockFile
from binwalk.modules.configuration import Configuration
class Plotter(binwalk.module.Module): class Plotter(binwalk.module.Module):
''' '''
...@@ -14,6 +15,8 @@ class Plotter(binwalk.module.Module): ...@@ -14,6 +15,8 @@ class Plotter(binwalk.module.Module):
NAME = "Binary Visualization" NAME = "Binary Visualization"
DEPENDS = {'config' : Configuration}
CLI = [ CLI = [
binwalk.module.ModuleOption(short='3', binwalk.module.ModuleOption(short='3',
long='3D', long='3D',
......
...@@ -8,6 +8,7 @@ import binwalk.common ...@@ -8,6 +8,7 @@ import binwalk.common
import binwalk.module import binwalk.module
import binwalk.smartstrings import binwalk.smartstrings
from binwalk.compat import * from binwalk.compat import *
from binwalk.modules.configuration import Configuration
class HashResult(object): class HashResult(object):
''' '''
...@@ -27,6 +28,8 @@ class HashMatch(binwalk.module.Module): ...@@ -27,6 +28,8 @@ class HashMatch(binwalk.module.Module):
DEFAULT_CUTOFF = 0 DEFAULT_CUTOFF = 0
CONSERVATIVE_CUTOFF = 90 CONSERVATIVE_CUTOFF = 90
DEPENDS = {'config' : Configuration }
NAME = "Fuzzy Hash" NAME = "Fuzzy Hash"
CLI = [ CLI = [
binwalk.module.ModuleOption(short='F', binwalk.module.ModuleOption(short='F',
......
...@@ -5,6 +5,7 @@ import platform ...@@ -5,6 +5,7 @@ import platform
import binwalk.module import binwalk.module
import binwalk.common as common import binwalk.common as common
from binwalk.compat import * from binwalk.compat import *
from binwalk.modules.configuration import Configuration
# TODO: This code is an effing mess. # TODO: This code is an effing mess.
class HexDiff(binwalk.module.Module): class HexDiff(binwalk.module.Module):
...@@ -22,6 +23,8 @@ class HexDiff(binwalk.module.Module): ...@@ -22,6 +23,8 @@ class HexDiff(binwalk.module.Module):
'blue' : '34', 'blue' : '34',
} }
DEPENDS = {'config' : Configuration}
NAME = "Binary Diffing" NAME = "Binary Diffing"
CLI = [ CLI = [
binwalk.module.ModuleOption(short='W', binwalk.module.ModuleOption(short='W',
......
...@@ -5,9 +5,12 @@ import binwalk.parser ...@@ -5,9 +5,12 @@ import binwalk.parser
import binwalk.filter import binwalk.filter
import binwalk.smartsignature import binwalk.smartsignature
from binwalk.compat import * from binwalk.compat import *
from binwalk.modules.configuration import Configuration
class Signature(binwalk.module.Module): class Signature(binwalk.module.Module):
DEPENDS = {'config' : Configuration}
CLI = [ CLI = [
binwalk.module.ModuleOption(short='B', binwalk.module.ModuleOption(short='B',
long='signature', long='signature',
......
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