Commit 27d1a24b by devttys0

Updated usage output, small directory restructuring.

parent b16c8417
......@@ -9,14 +9,14 @@ def display_status(m):
while True:
try:
raw_input()
print("Progress: %.2f%% (%d / %d)\n" % (((float(m.status.completed) / float(m.status.total)) * 100), m.status.completed, m.status.total))
sys.stderr.write("Progress: %.2f%% (%d / %d)\n\n" % (((float(m.status.completed) / float(m.status.total)) * 100), m.status.completed, m.status.total))
except KeyboardInterrupt as e:
raise e
except Exception:
pass
def usage(modules):
print modules.help()
sys.stderr.write(modules.help())
sys.exit(1)
def main():
......
......@@ -35,6 +35,8 @@ def file_size(filename):
fd = os.open(filename, os.O_RDONLY)
try:
return os.lseek(fd, 0, os.SEEK_END)
except KeyboardInterrupt as e:
raise e
except Exception as e:
raise Exception("file_size failed to obtain the size of '%s': %s" % (filename, str(e)))
finally:
......@@ -51,7 +53,9 @@ def str2int(string):
'''
try:
return int(string)
except:
except KeyboardInterrupt as e:
raise e
except Exception:
return int(string, 16)
def strip_quoted_strings(string):
......@@ -85,7 +89,9 @@ def get_quoted_strings(string):
# double quotes, and this function should ignore those. However, it also means that any
# data between two quoted strings (ex: '"quote 1" non-quoted data "quote 2"') will also be included.
return re.findall(r'\"(.*)\"', string)[0]
except:
except KeyboardInterrupt as e:
raise e
except Exception:
return ''
def unique_file_name(base_name, extension=''):
......@@ -159,7 +165,9 @@ class MathExpression(object):
if expression:
try:
self.value = self.evaluate(self.expression)
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
def evaluate(self, expr):
......@@ -230,7 +238,9 @@ class BlockFile(io.FileIO):
try:
self.size = file_size(fname)
except:
except KeyboardInterrupt as e:
raise e
except Exception:
self.size = 0
if offset < 0:
......
......@@ -161,7 +161,9 @@ class CompressionEntropyAnalyzer(object):
def __del__(self):
try:
self.fp.close()
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
def analyze(self):
......
......@@ -35,12 +35,12 @@ class Config:
o PLUGINS - Path to the plugins directory.
'''
# Release version
VERSION = "1.3.0 beta"
VERSION = "2.0.0 alpha"
# Sub directories
BINWALK_USER_DIR = ".binwalk"
BINWALK_MAGIC_DIR = "magic"
BINWALK_CONFIG_DIR = "config"
BINWALK_CONFIG_DIR = "configs"
BINWALK_PLUGINS_DIR = "plugins"
# File names
......@@ -118,7 +118,9 @@ class Config:
if os.path.islink(root):
root = os.path.realpath(root)
return os.path.dirname(os.path.abspath(root))
except:
except KeyboardInterrupt as e:
raise e
except Exception:
return ''
def _get_user_dir(self):
......@@ -128,7 +130,9 @@ class Config:
try:
# This should work in both Windows and Unix environments
return os.getenv('USERPROFILE') or os.getenv('HOME')
except:
except KeyboardInterrupt as e:
raise e
except Exception:
return ''
def _file_path(self, dirname, filename):
......@@ -143,7 +147,9 @@ class Config:
if not os.path.exists(dirname):
try:
os.makedirs(dirname)
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
fpath = os.path.join(dirname, filename)
......@@ -151,7 +157,9 @@ class Config:
if not os.path.exists(fpath):
try:
open(fpath, "w").close()
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
return fpath
......
......@@ -69,10 +69,14 @@ class Display(object):
end = len(data[start:])
self.string_parts.append(data[start:end])
except:
except KeyboardInterrupt as e:
raise e
except Exception:
try:
self.string_parts.append(data[start:])
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
return start
......@@ -123,6 +127,8 @@ class Display(object):
# Get the terminal window width
hw = struct.unpack('hh', fcntl.ioctl(1, termios.TIOCGWINSZ, '1234'))
self.SCREEN_WIDTH = self.HEADER_WIDTH = hw[1]
except Exception as e:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
......@@ -185,7 +185,9 @@ class FileEntropy(object):
'''
try:
self.fd.close()
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
def _read_block(self):
......@@ -288,7 +290,9 @@ class FileEntropy(object):
# This results in a divide by zero if one/all plugins returns PLUGIN_TERMINATE or PLUGIN_NO_DISPLAY,
# or if the file being scanned is a zero-size file.
average = float(float(total) / float(len(offsets)))
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
if self.plugins:
......@@ -372,7 +376,9 @@ class FileEntropy(object):
try:
if algorithm.lower() == 'gzip':
algo = self.gzip
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
return self._do_analysis(algo)
......
......@@ -115,7 +115,9 @@ class Extractor:
r['regex'] = re.compile(values[0])
r['extension'] = values[1]
r['cmd'] = values[2]
except:
except KeyboardInterrupt as e:
raise e
except Exception:
pass
# Verify that the match string was retrieved.
......@@ -183,6 +185,8 @@ class Extractor:
with open(fname, 'r') as f:
for rule in f.readlines():
self.add_rule(rule.split(self.COMMENT_DELIM, 1)[0])
except KeyboardInterrupt as e:
raise e
except Exception as e:
raise Exception("Extractor.load_from_file failed to load file '%s': %s" % (fname, str(e)))
......@@ -201,6 +205,8 @@ class Extractor:
for extract_file in extract_files:
try:
self.load_from_file(extract_file)
except KeyboardInterrupt as e:
raise e
except Exception as e:
if self.verbose:
raise Exception("Extractor.load_defaults failed to load file '%s': %s" % (extract_file, str(e)))
......@@ -289,7 +295,9 @@ class Extractor:
# Remove the original file that we extracted
try:
os.unlink(fname)
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
pass
# If the command worked, assume it removed the file extension from the extracted file
......@@ -297,7 +305,9 @@ class Extractor:
if cleanup_extracted_fname and os.path.exists(extracted_fname) and file_size(extracted_fname) == 0:
try:
os.unlink(extracted_fname)
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
pass
# If the command executed OK, don't try any more rules
......@@ -308,7 +318,9 @@ class Extractor:
elif i != (len(rules)-1):
try:
os.unlink(fname)
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
pass
# If there was no command to execute, just use the first rule
......@@ -442,6 +454,8 @@ class Extractor:
# Open the output file
try:
fdout = BlockFile(fname, 'w')
except KeyboardInterrupt as e:
raise e
except Exception as e:
# Fall back to the default name if the requested name fails
fname = unique_file_name(default_bname, extension)
......@@ -455,6 +469,8 @@ class Extractor:
# Cleanup
fdout.close()
fdin.close()
except KeyboardInterrupt as e:
raise e
except Exception as e:
raise Exception("Extractor.dd failed to extract data from '%s' to '%s': %s" % (file_name, fname, str(e)))
......@@ -479,6 +495,8 @@ class Extractor:
if callable(cmd):
try:
cmd(fname)
except KeyboardInterrupt as e:
raise e
except Exception as e:
sys.stderr.write("WARNING: Extractor.execute failed to run '%s': %s\n" % (str(cmd), str(e)))
else:
......@@ -492,6 +510,8 @@ class Extractor:
# Execute.
if subprocess.call(shlex.split(cmd), stdout=tmp, stderr=tmp) != 0:
retval = False
except KeyboardInterrupt as e:
raise e
except Exception as e:
# Silently ignore no such file or directory errors. Why? Because these will inevitably be raised when
# making the switch to the new firmware mod kit directory structure. We handle this elsewhere, but it's
......
#!/usr/bin/env python
# Routines to perform Monte Carlo Pi approximation and Chi Squared tests.
# Used for fingerprinting unknown areas of high entropy (e.g., is this block of high entropy data compressed or encrypted?).
# Inspired by people who actually know what they're doing: http://www.fourmilab.ch/random/
import math
from binwalk.compat import *
class MonteCarloPi(object):
'''
Performs a Monte Carlo Pi approximation.
'''
def __init__(self):
'''
Class constructor.
Returns None.
'''
self.reset()
def reset(self):
'''
Reset state to the beginning.
'''
self.pi = 0
self.error = 0
self.m = 0
self.n = 0
def update(self, data):
'''
Update the pi approximation with new data.
@data - A string of bytes to update (length must be >= 6).
Returns None.
'''
c = 0
dlen = len(data)
while (c+6) < dlen:
# Treat 3 bytes as an x coordinate, the next 3 bytes as a y coordinate.
# Our box is 1x1, so divide by 2^24 to put the x y values inside the box.
x = ((ord(data[c]) << 16) + (ord(data[c+1]) << 8) + ord(data[c+2])) / 16777216.0
c += 3
y = ((ord(data[c]) << 16) + (ord(data[c+1]) << 8) + ord(data[c+2])) / 16777216.0
c += 3
# Does the x,y point lie inside the circle inscribed within our box, with diameter == 1?
if ((x**2) + (y**2)) <= 1:
self.m += 1
self.n += 1
def montecarlo(self):
'''
Approximates the value of Pi based on the provided data.
Returns a tuple of (approximated value of pi, percent deviation).
'''
if self.n:
self.pi = (float(self.m) / float(self.n) * 4.0)
if self.pi:
self.error = math.fabs(1.0 - (math.pi / self.pi)) * 100.0
return (self.pi, self.error)
else:
return (0.0, 0.0)
class ChiSquare(object):
'''
Performs a Chi Squared test against the provided data.
'''
IDEAL = 256.0
def __init__(self):
'''
Class constructor.
Returns None.
'''
self.bytes = {}
self.freedom = self.IDEAL - 1
# Initialize the self.bytes dictionary with keys for all possible byte values (0 - 255)
for i in range(0, int(self.IDEAL)):
self.bytes[chr(i)] = 0
self.reset()
def reset(self):
self.xc2 = 0.0
self.byte_count = 0
for key in self.bytes.keys():
self.bytes[key] = 0
def update(self, data):
'''
Updates the current byte counts with new data.
@data - String of bytes to update.
Returns None.
'''
# Count the number of occurances of each byte value
for i in data:
self.bytes[i] += 1
self.byte_count += len(data)
def chisq(self):
'''
Calculate the Chi Square critical value.
Returns the critical value.
'''
expected = self.byte_count / self.IDEAL
if expected:
for byte in self.bytes.values():
self.xc2 += ((byte - expected) ** 2 ) / expected
return self.xc2
class MathAnalyzer(object):
'''
Class wrapper aroung ChiSquare and MonteCarloPi.
Performs analysis and attempts to interpret the results.
'''
# Data blocks must be in multiples of 6 for the monte carlo pi approximation
BLOCK_SIZE = 32
CHI_CUTOFF = 512
def __init__(self, fp, start, length):
'''
Class constructor.
@fp - A seekable, readable, file object that will be the data source.
@start - The start offset to begin analysis at.
@length - The number of bytes to analyze.
Returns None.
'''
self.fp = fp
self.start = start
self.length = length
def analyze(self):
'''
Perform analysis and interpretation.
Returns a descriptive string containing the results and attempted interpretation.
'''
i = 0
num_error = 0
analyzer_results = []
chi = ChiSquare()
self.fp.seek(self.start)
while i < self.length:
rsize = self.length - i
if rsize > self.BLOCK_SIZE:
rsize = self.BLOCK_SIZE
chi.reset()
chi.update(self.fp.read(rsize))
if chi.chisq() >= self.CHI_CUTOFF:
num_error += 1
i += rsize
if num_error > 0:
verdict = 'Low/medium entropy data block'
else:
verdict = 'High entropy data block'
result = '%s, %d low entropy blocks' % (verdict, num_error)
return result
if __name__ == "__main__":
import sys
rsize = 0
largest = (0, 0)
num_error = 0
data = open(sys.argv[1], 'rb').read()
try:
block_size = int(sys.argv[2], 0)
except:
block_size = 32
chi = ChiSquare()
while rsize < len(data):
chi.reset()
d = data[rsize:rsize+block_size]
if d < block_size:
break
chi.update(d)
if chi.chisq() >= 512:
sys.stderr.write("0x%X -> %d\n" % (rsize, chi.xc2))
num_error += 1
if chi.xc2 >= largest[1]:
largest = (rsize, chi.xc2)
rsize += block_size
sys.stderr.write("Number of deviations: %d\n" % num_error)
sys.stderr.write("Largest deviation: %d at offset 0x%X\n" % (largest[1], largest[0]))
......@@ -4,6 +4,7 @@ import sys
import inspect
import argparse
import binwalk.common
import binwalk.config
from binwalk.compat import *
class ModuleOption(object):
......@@ -380,7 +381,7 @@ class Modules(object):
return modules
def help(self):
help_string = ""
help_string = "\nBinwalk v%s\nCraig Heffner, http://www.binwalk.org\n" % binwalk.config.Config.VERSION
for obj in self.list(attribute="CLI"):
if obj.CLI:
......
......@@ -6,7 +6,6 @@ import ctypes
import ctypes.util
import binwalk.common
import binwalk.module
import binwalk.smartstrings
from binwalk.compat import *
class HashResult(object):
......
......@@ -115,6 +115,8 @@ class Plugins:
val = callback(arg)
if val is not None:
retval |= val
except KeyboardInterrupt as e:
raise e
except Exception as e:
sys.stderr.write("WARNING: %s.%s failed: %s\n" % (callback.__module__, callback.__name__, e))
......@@ -171,7 +173,9 @@ class Plugins:
try:
enabled = plugin_class.ENABLED
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
enabled = True
plugins[key]['enabled'][module] = enabled
......@@ -180,7 +184,9 @@ class Plugins:
try:
plugins[key]['descriptions'][module] = plugin_class.__doc__.strip().split('\n')[0]
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
plugins[key]['descriptions'][module] = 'No description'
return plugins
......@@ -201,26 +207,36 @@ class Plugins:
# If this plugin is disabled by default and has not been explicitly white listed, ignore it
if plugin_class.ENABLED == False and module not in self.whitelist:
continue
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
pass
class_instance = plugin_class()
try:
self.result.append(getattr(class_instance, self.RESULT))
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
pass
try:
self.pre_scan.append(getattr(class_instance, self.PRESCAN))
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
pass
try:
self.post_scan.append(getattr(class_instance, self.POSTSCAN))
except:
except KeyboardInterrupt as e:
raise e
except Exception as e:
pass
except KeyboardInterrupt as e:
raise e
except Exception as e:
sys.stderr.write("WARNING: Failed to load plugin module '%s': %s\n" % (module, str(e)))
......
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