Commit 2492b1c4 by devttys0

Added legends to entropy plots; added module prioritization.

parent b771ae0d
...@@ -148,6 +148,9 @@ class Module(object): ...@@ -148,6 +148,9 @@ class Module(object):
# containing a valid file attribute. # containing a valid file attribute.
AUTO_UPDATE_STATUS = True AUTO_UPDATE_STATUS = True
# Modules with higher priorities are executed first
PRIORITY = 5
def __init__(self, dependency=False, **kwargs): def __init__(self, dependency=False, **kwargs):
self.errors = [] self.errors = []
self.results = [] self.results = []
...@@ -339,13 +342,14 @@ class Module(object): ...@@ -339,13 +342,14 @@ class Module(object):
def footer(self): def footer(self):
self.config.display.footer() self.config.display.footer()
def main(self, status): def main(self, parent):
''' '''
Responsible for calling self.init, initializing self.config.display, 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.
''' '''
self.status = status self.status = parent.status
self.modules = parent.loaded_modules
# Reset all dependency modules # Reset all dependency modules
for (dependency, module) in iterator(self.DEPENDS): for (dependency, module) in iterator(self.DEPENDS):
...@@ -447,16 +451,16 @@ class Modules(object): ...@@ -447,16 +451,16 @@ class Modules(object):
@attribute - The desired module attribute. @attribute - The desired module attribute.
Returns a list of modules that contain the specified attribute. Returns a list of modules that contain the specified attribute, in the order they should be executed.
''' '''
import binwalk.modules import binwalk.modules
modules = [] modules = {}
for (name, module) in inspect.getmembers(binwalk.modules): for (name, module) in inspect.getmembers(binwalk.modules):
if inspect.isclass(module) and hasattr(module, attribute): if inspect.isclass(module) and hasattr(module, attribute):
modules.append(module) modules[module] = module.PRIORITY
return modules return sorted(modules, key=modules.get, reverse=True)
def help(self): def help(self):
help_string = "\nBinwalk v%s\nCraig Heffner, http://www.binwalk.org\n" % binwalk.core.settings.Settings.VERSION help_string = "\nBinwalk v%s\nCraig Heffner, http://www.binwalk.org\n" % binwalk.core.settings.Settings.VERSION
...@@ -508,7 +512,7 @@ class Modules(object): ...@@ -508,7 +512,7 @@ class Modules(object):
obj = self.load(module) obj = self.load(module)
if isinstance(obj, binwalk.core.module.Module) and obj.enabled: if isinstance(obj, binwalk.core.module.Module) and obj.enabled:
obj.main(status=self.status) obj.main(parent=self)
self.status.clear() self.status.clear()
# Add object to loaded_modules here, that way if a module has already been # Add object to loaded_modules here, that way if a module has already been
......
import os import os
import math import math
import binwalk.core.common import binwalk.core.common
from binwalk.core.compat import *
from binwalk.core.module import Module, Option, Kwarg from binwalk.core.module import Module, Option, Kwarg
class Entropy(Module): class Entropy(Module):
...@@ -14,6 +15,8 @@ class Entropy(Module): ...@@ -14,6 +15,8 @@ class Entropy(Module):
FILE_WIDTH = 1024 FILE_WIDTH = 1024
FILE_FORMAT = 'png' FILE_FORMAT = 'png'
COLORS = ['r', 'g', 'c', 'b', 'm']
TITLE = "Entropy" TITLE = "Entropy"
CLI = [ CLI = [
...@@ -29,32 +32,61 @@ class Entropy(Module): ...@@ -29,32 +32,61 @@ class Entropy(Module):
long='no-plot', long='no-plot',
kwargs={'do_plot' : False}, kwargs={'do_plot' : False},
description='Do not generate an entropy plot graph'), description='Do not generate an entropy plot graph'),
Option(short='Q',
long='no-legend',
kwargs={'show_legend' : False},
description='Omit the legend from the entropy plot graph (implied if multiple files are specified)'),
] ]
KWARGS = [ KWARGS = [
Kwarg(name='enabled', default=False), Kwarg(name='enabled', default=False),
Kwarg(name='save_plot', default=False), Kwarg(name='save_plot', default=False),
Kwarg(name='do_plot', default=True), Kwarg(name='do_plot', default=True),
Kwarg(name='show_legend', default=True),
Kwarg(name='block_size', default=1024), Kwarg(name='block_size', default=1024),
] ]
# Run this module last so that it can process all other module's results and overlay them on the entropy graph
PRIORITY = 0
def init(self): def init(self):
self.HEADER[-1] = "ENTROPY" self.HEADER[-1] = "ENTROPY"
self.entropy_results = {}
self.algorithm = self.shannon self.algorithm = self.shannon
self.display_results = True
self.max_description_length = 0
self.markers = []
# Automatically save plots if there is more than one file specified
if len(self.config.target_files) > 1: if len(self.config.target_files) > 1:
self.save_plot = True self.save_plot = True
self.show_legend = False
# Get a list of all other module's results to mark on the entropy graph
for (module, obj) in iterator(self.modules):
for result in obj.results:
if result.description:
description = result.description.split(',')[0]
if len(description) > self.max_description_length:
self.max_description_length = len(description)
self.markers.append((result.offset, description))
# If other modules have been run and they produced results, don't spam the terminal with entropy results
if self.markers:
self.display_results = False
if self.config.block: if self.config.block:
self.block_size = self.config.block self.block_size = self.config.block
def run(self): def run(self):
for fp in self.config.target_files: for fp in self.config.target_files:
self.header()
if self.display_results:
self.header()
self.calculate_file_entropy(fp) self.calculate_file_entropy(fp)
self.footer()
if self.display_results:
self.footer()
def calculate_file_entropy(self, fp): def calculate_file_entropy(self, fp):
# Clear results from any previously analyzed files # Clear results from any previously analyzed files
...@@ -70,7 +102,7 @@ class Entropy(Module): ...@@ -70,7 +102,7 @@ class Entropy(Module):
i = 0 i = 0
while i < dlen: while i < dlen:
entropy = self.algorithm(data[i:i+self.block_size]) entropy = self.algorithm(data[i:i+self.block_size])
r = self.result(offset=(file_offset + i), file=fp, entropy=entropy, description=("%f" % entropy)) r = self.result(offset=(file_offset + i), file=fp, entropy=entropy, description=("%f" % entropy), display=self.display_results)
i += self.block_size i += self.block_size
if self.do_plot: if self.do_plot:
...@@ -108,8 +140,10 @@ class Entropy(Module): ...@@ -108,8 +140,10 @@ class Entropy(Module):
import pyqtgraph as pg import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui from pyqtgraph.Qt import QtCore, QtGui
i = 0
x = [] x = []
y = [] y = []
plotted_colors = {}
for r in self.results: for r in self.results:
x.append(r.offset) x.append(r.offset)
...@@ -117,7 +151,29 @@ class Entropy(Module): ...@@ -117,7 +151,29 @@ class Entropy(Module):
plt = pg.plot(title=fname, clear=True) plt = pg.plot(title=fname, clear=True)
plt.plot(x, y, pen='y') #pen='b' plt.plot(x, y, pen='y')
if self.show_legend and self.markers:
plt.addLegend(size=(self.max_description_length*10, 0))
for (offset, description) in self.markers:
# If this description has already been plotted at a different offset, we need to
# use the same color for the marker, but set the description to None to prevent
# duplicate entries in the graph legend.
#
# Else, get the next color and use it to mark descriptions of this type.
if has_key(plotted_colors, description):
color = plotted_colors[description]
description = None
else:
color = self.COLORS[i]
plotted_colors[description] = color
i += 1
if i >= len(self.COLORS):
i = 0
plt.plot(x=[offset,offset], y=[0,1.1], name=description, pen=pg.mkPen(color, width=2.5))
if self.save_plot: if self.save_plot:
exporter = pg.exporters.ImageExporter.ImageExporter(plt.plotItem) exporter = pg.exporters.ImageExporter.ImageExporter(plt.plotItem)
......
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