Commit 578eeff2 by devttys0

Added preliminary entropy analysis module.

parent 7004a70b
...@@ -125,20 +125,24 @@ class Module(object): ...@@ -125,20 +125,24 @@ class Module(object):
DEPENDS = {'config' : 'Configuration', 'extractor' : 'Extractor'} DEPENDS = {'config' : 'Configuration', 'extractor' : 'Extractor'}
# 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"
HEADER_FORMAT = "%-12s %-12s %s\n"
# Format string for printing each result during a scan # Format string for printing each result during a scan
RESULT_FORMAT = "%.8d %s\n" #RESULT_FORMAT = "%.8d %s\n"
RESULT_FORMAT = "%-12d 0x%-12X %s\n"
# The header to print during a scan. # The header to print during a scan.
# Set to None to not print a header. # Set to None to not print a header.
# Note that this will be formatted per the HEADER_FORMAT format string. # Note that this will be formatted per the HEADER_FORMAT format string.
HEADER = ["OFFSET DESCRIPTION"] #HEADER = ["OFFSET DESCRIPTION"]
HEADER = ["DECIMAL", "HEX", "DESCRIPTION"]
# The attribute names to print during a scan, as provided to the self.results method. # The attribute names to print during a scan, as provided to the self.results method.
# Set to None to not print any results. # Set to None to not print any results.
# 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']
RESULT = ["offset", "offset", "description"]
def __init__(self, dependency=False, **kwargs): def __init__(self, dependency=False, **kwargs):
self.errors = [] self.errors = []
...@@ -239,6 +243,15 @@ class Module(object): ...@@ -239,6 +243,15 @@ class Module(object):
return args return args
def clear(self, results=True, errors=True):
'''
Clears results and errors lists.
'''
if results:
self.results = []
if errors:
self.errors = []
def result(self, r=None, **kwargs): def result(self, r=None, **kwargs):
''' '''
Validates a result, stores it in self.results and prints it. Validates a result, stores it in self.results and prints it.
...@@ -246,7 +259,7 @@ class Module(object): ...@@ -246,7 +259,7 @@ class Module(object):
@r - An existing instance of binwalk.core.module.Result. @r - An existing instance of binwalk.core.module.Result.
Returns None. Returns an instance of binwalk.core.module.Result.
''' '''
if r is None: if r is None:
r = Result(**kwargs) r = Result(**kwargs)
...@@ -278,6 +291,8 @@ class Module(object): ...@@ -278,6 +291,8 @@ class Module(object):
if display_args: if display_args:
self.config.display.result(*display_args) self.config.display.result(*display_args)
return r
def error(self, **kwargs): def error(self, **kwargs):
''' '''
Stores the specified error in self.errors. Stores the specified error in self.errors.
......
...@@ -4,3 +4,4 @@ from binwalk.modules.hexdiff import HexDiff ...@@ -4,3 +4,4 @@ from binwalk.modules.hexdiff import HexDiff
from binwalk.modules.hashmatch import HashMatch 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
import math
from binwalk.core.module import Module, Option, Kwarg
class Entropy(Module):
XLABEL = 'Offset'
YLABEL = 'Entropy'
XUNITS = 'B'
YUNITS = 'E'
TITLE = "Entropy"
CLI = [
Option(short='E',
long='entropy',
kwargs={'enabled' : True},
description='Calculate file entropy'),
]
KWARGS = [
Kwarg(name='enabled', default=False),
Kwarg(name='block_size', default=1024),
]
def init(self):
self.entropy_results = {}
self.algorithm = self.shannon
if self.config.block:
self.block_size = self.config.block
def run(self):
for fp in self.config.target_files:
self.header()
self.calculate_file_entropy(fp)
self.footer()
def calculate_file_entropy(self, fp):
# Clear results from any previously analyzed files
self.clear(results=True)
while True:
file_offset = fp.tell()
(data, dlen) = fp.read_block()
if not data:
break
i = 0
while i < dlen:
entropy = self.algorithm(data[i:i+self.block_size])
r = self.result(offset=(file_offset + i), file=fp, entropy=entropy, description=("%f" % entropy))
i += self.block_size
self.plot_entropy(fp.name)
def shannon(self, data):
'''
Performs a Shannon entropy analysis on a given block of data.
'''
entropy = 0
if data:
for x in range(0, 256):
p_x = float(data.count(chr(x))) / len(data)
if p_x > 0:
entropy += - p_x*math.log(p_x, 2)
return (entropy / 8)
def gzip(self, data, truncate=True):
'''
Performs an entropy analysis based on zlib compression ratio.
This is faster than the shannon entropy analysis, but not as accurate.
'''
# Entropy is a simple ratio of: <zlib compressed size> / <original size>
e = float(float(len(zlib.compress(data, 9))) / float(len(data)))
if truncate and e > 1.0:
e = 1.0
return e
def plot_entropy(self, title):
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
x = []
y = []
for r in self.results:
x.append(r.offset)
y.append(r.entropy)
plt = pg.plot(title=title, clear=True)
plt.plot(x, y, pen='y') #pen='b'
plt.setLabel('left', self.YLABEL, units=self.YUNITS)
plt.setLabel('bottom', self.XLABEL, units=self.XUNITS)
QtGui.QApplication.instance().exec_()
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