Commit 27d1a24b by devttys0

Updated usage output, small directory restructuring.

parent b16c8417
...@@ -9,14 +9,14 @@ def display_status(m): ...@@ -9,14 +9,14 @@ def display_status(m):
while True: while True:
try: try:
raw_input() 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: except KeyboardInterrupt as e:
raise e raise e
except Exception: except Exception:
pass pass
def usage(modules): def usage(modules):
print modules.help() sys.stderr.write(modules.help())
sys.exit(1) sys.exit(1)
def main(): def main():
......
...@@ -35,6 +35,8 @@ def file_size(filename): ...@@ -35,6 +35,8 @@ def file_size(filename):
fd = os.open(filename, os.O_RDONLY) fd = os.open(filename, os.O_RDONLY)
try: try:
return os.lseek(fd, 0, os.SEEK_END) return os.lseek(fd, 0, os.SEEK_END)
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
raise Exception("file_size failed to obtain the size of '%s': %s" % (filename, str(e))) raise Exception("file_size failed to obtain the size of '%s': %s" % (filename, str(e)))
finally: finally:
...@@ -51,7 +53,9 @@ def str2int(string): ...@@ -51,7 +53,9 @@ def str2int(string):
''' '''
try: try:
return int(string) return int(string)
except: except KeyboardInterrupt as e:
raise e
except Exception:
return int(string, 16) return int(string, 16)
def strip_quoted_strings(string): def strip_quoted_strings(string):
...@@ -85,7 +89,9 @@ def get_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 # 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. # data between two quoted strings (ex: '"quote 1" non-quoted data "quote 2"') will also be included.
return re.findall(r'\"(.*)\"', string)[0] return re.findall(r'\"(.*)\"', string)[0]
except: except KeyboardInterrupt as e:
raise e
except Exception:
return '' return ''
def unique_file_name(base_name, extension=''): def unique_file_name(base_name, extension=''):
...@@ -159,7 +165,9 @@ class MathExpression(object): ...@@ -159,7 +165,9 @@ class MathExpression(object):
if expression: if expression:
try: try:
self.value = self.evaluate(self.expression) self.value = self.evaluate(self.expression)
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
def evaluate(self, expr): def evaluate(self, expr):
...@@ -230,7 +238,9 @@ class BlockFile(io.FileIO): ...@@ -230,7 +238,9 @@ class BlockFile(io.FileIO):
try: try:
self.size = file_size(fname) self.size = file_size(fname)
except: except KeyboardInterrupt as e:
raise e
except Exception:
self.size = 0 self.size = 0
if offset < 0: if offset < 0:
......
...@@ -161,7 +161,9 @@ class CompressionEntropyAnalyzer(object): ...@@ -161,7 +161,9 @@ class CompressionEntropyAnalyzer(object):
def __del__(self): def __del__(self):
try: try:
self.fp.close() self.fp.close()
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
def analyze(self): def analyze(self):
......
...@@ -35,12 +35,12 @@ class Config: ...@@ -35,12 +35,12 @@ class Config:
o PLUGINS - Path to the plugins directory. o PLUGINS - Path to the plugins directory.
''' '''
# Release version # Release version
VERSION = "1.3.0 beta" VERSION = "2.0.0 alpha"
# Sub directories # Sub directories
BINWALK_USER_DIR = ".binwalk" BINWALK_USER_DIR = ".binwalk"
BINWALK_MAGIC_DIR = "magic" BINWALK_MAGIC_DIR = "magic"
BINWALK_CONFIG_DIR = "config" BINWALK_CONFIG_DIR = "configs"
BINWALK_PLUGINS_DIR = "plugins" BINWALK_PLUGINS_DIR = "plugins"
# File names # File names
...@@ -118,7 +118,9 @@ class Config: ...@@ -118,7 +118,9 @@ class Config:
if os.path.islink(root): if os.path.islink(root):
root = os.path.realpath(root) root = os.path.realpath(root)
return os.path.dirname(os.path.abspath(root)) return os.path.dirname(os.path.abspath(root))
except: except KeyboardInterrupt as e:
raise e
except Exception:
return '' return ''
def _get_user_dir(self): def _get_user_dir(self):
...@@ -128,7 +130,9 @@ class Config: ...@@ -128,7 +130,9 @@ class Config:
try: try:
# This should work in both Windows and Unix environments # This should work in both Windows and Unix environments
return os.getenv('USERPROFILE') or os.getenv('HOME') return os.getenv('USERPROFILE') or os.getenv('HOME')
except: except KeyboardInterrupt as e:
raise e
except Exception:
return '' return ''
def _file_path(self, dirname, filename): def _file_path(self, dirname, filename):
...@@ -143,7 +147,9 @@ class Config: ...@@ -143,7 +147,9 @@ class Config:
if not os.path.exists(dirname): if not os.path.exists(dirname):
try: try:
os.makedirs(dirname) os.makedirs(dirname)
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
fpath = os.path.join(dirname, filename) fpath = os.path.join(dirname, filename)
...@@ -151,7 +157,9 @@ class Config: ...@@ -151,7 +157,9 @@ class Config:
if not os.path.exists(fpath): if not os.path.exists(fpath):
try: try:
open(fpath, "w").close() open(fpath, "w").close()
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
return fpath return fpath
......
...@@ -69,10 +69,14 @@ class Display(object): ...@@ -69,10 +69,14 @@ class Display(object):
end = len(data[start:]) end = len(data[start:])
self.string_parts.append(data[start:end]) self.string_parts.append(data[start:end])
except: except KeyboardInterrupt as e:
raise e
except Exception:
try: try:
self.string_parts.append(data[start:]) self.string_parts.append(data[start:])
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
return start return start
...@@ -123,6 +127,8 @@ class Display(object): ...@@ -123,6 +127,8 @@ class Display(object):
# Get the terminal window width # Get the terminal window width
hw = struct.unpack('hh', fcntl.ioctl(1, termios.TIOCGWINSZ, '1234')) hw = struct.unpack('hh', fcntl.ioctl(1, termios.TIOCGWINSZ, '1234'))
self.SCREEN_WIDTH = self.HEADER_WIDTH = hw[1] self.SCREEN_WIDTH = self.HEADER_WIDTH = hw[1]
except Exception as e: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
...@@ -185,7 +185,9 @@ class FileEntropy(object): ...@@ -185,7 +185,9 @@ class FileEntropy(object):
''' '''
try: try:
self.fd.close() self.fd.close()
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
def _read_block(self): def _read_block(self):
...@@ -288,7 +290,9 @@ class FileEntropy(object): ...@@ -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, # 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. # or if the file being scanned is a zero-size file.
average = float(float(total) / float(len(offsets))) average = float(float(total) / float(len(offsets)))
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
if self.plugins: if self.plugins:
...@@ -372,7 +376,9 @@ class FileEntropy(object): ...@@ -372,7 +376,9 @@ class FileEntropy(object):
try: try:
if algorithm.lower() == 'gzip': if algorithm.lower() == 'gzip':
algo = self.gzip algo = self.gzip
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
return self._do_analysis(algo) return self._do_analysis(algo)
......
...@@ -115,7 +115,9 @@ class Extractor: ...@@ -115,7 +115,9 @@ class Extractor:
r['regex'] = re.compile(values[0]) r['regex'] = re.compile(values[0])
r['extension'] = values[1] r['extension'] = values[1]
r['cmd'] = values[2] r['cmd'] = values[2]
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
# Verify that the match string was retrieved. # Verify that the match string was retrieved.
...@@ -183,6 +185,8 @@ class Extractor: ...@@ -183,6 +185,8 @@ class Extractor:
with open(fname, 'r') as f: with open(fname, 'r') as f:
for rule in f.readlines(): for rule in f.readlines():
self.add_rule(rule.split(self.COMMENT_DELIM, 1)[0]) self.add_rule(rule.split(self.COMMENT_DELIM, 1)[0])
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
raise Exception("Extractor.load_from_file failed to load file '%s': %s" % (fname, str(e))) raise Exception("Extractor.load_from_file failed to load file '%s': %s" % (fname, str(e)))
...@@ -201,6 +205,8 @@ class Extractor: ...@@ -201,6 +205,8 @@ class Extractor:
for extract_file in extract_files: for extract_file in extract_files:
try: try:
self.load_from_file(extract_file) self.load_from_file(extract_file)
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
if self.verbose: if self.verbose:
raise Exception("Extractor.load_defaults failed to load file '%s': %s" % (extract_file, str(e))) raise Exception("Extractor.load_defaults failed to load file '%s': %s" % (extract_file, str(e)))
...@@ -289,7 +295,9 @@ class Extractor: ...@@ -289,7 +295,9 @@ class Extractor:
# Remove the original file that we extracted # Remove the original file that we extracted
try: try:
os.unlink(fname) os.unlink(fname)
except: except KeyboardInterrupt as e:
raise e
except Exception as e:
pass pass
# If the command worked, assume it removed the file extension from the extracted file # If the command worked, assume it removed the file extension from the extracted file
...@@ -297,7 +305,9 @@ class Extractor: ...@@ -297,7 +305,9 @@ class Extractor:
if cleanup_extracted_fname and os.path.exists(extracted_fname) and file_size(extracted_fname) == 0: if cleanup_extracted_fname and os.path.exists(extracted_fname) and file_size(extracted_fname) == 0:
try: try:
os.unlink(extracted_fname) os.unlink(extracted_fname)
except: except KeyboardInterrupt as e:
raise e
except Exception as e:
pass pass
# If the command executed OK, don't try any more rules # If the command executed OK, don't try any more rules
...@@ -308,7 +318,9 @@ class Extractor: ...@@ -308,7 +318,9 @@ class Extractor:
elif i != (len(rules)-1): elif i != (len(rules)-1):
try: try:
os.unlink(fname) os.unlink(fname)
except: except KeyboardInterrupt as e:
raise e
except Exception as e:
pass pass
# If there was no command to execute, just use the first rule # If there was no command to execute, just use the first rule
...@@ -442,6 +454,8 @@ class Extractor: ...@@ -442,6 +454,8 @@ class Extractor:
# Open the output file # Open the output file
try: try:
fdout = BlockFile(fname, 'w') fdout = BlockFile(fname, 'w')
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
# Fall back to the default name if the requested name fails # Fall back to the default name if the requested name fails
fname = unique_file_name(default_bname, extension) fname = unique_file_name(default_bname, extension)
...@@ -455,6 +469,8 @@ class Extractor: ...@@ -455,6 +469,8 @@ class Extractor:
# Cleanup # Cleanup
fdout.close() fdout.close()
fdin.close() fdin.close()
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
raise Exception("Extractor.dd failed to extract data from '%s' to '%s': %s" % (file_name, fname, str(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: ...@@ -479,6 +495,8 @@ class Extractor:
if callable(cmd): if callable(cmd):
try: try:
cmd(fname) cmd(fname)
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
sys.stderr.write("WARNING: Extractor.execute failed to run '%s': %s\n" % (str(cmd), str(e))) sys.stderr.write("WARNING: Extractor.execute failed to run '%s': %s\n" % (str(cmd), str(e)))
else: else:
...@@ -492,6 +510,8 @@ class Extractor: ...@@ -492,6 +510,8 @@ class Extractor:
# Execute. # Execute.
if subprocess.call(shlex.split(cmd), stdout=tmp, stderr=tmp) != 0: if subprocess.call(shlex.split(cmd), stdout=tmp, stderr=tmp) != 0:
retval = False retval = False
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
# Silently ignore no such file or directory errors. Why? Because these will inevitably be raised when # 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 # 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 ...@@ -4,6 +4,7 @@ import sys
import inspect import inspect
import argparse import argparse
import binwalk.common import binwalk.common
import binwalk.config
from binwalk.compat import * from binwalk.compat import *
class ModuleOption(object): class ModuleOption(object):
...@@ -380,7 +381,7 @@ class Modules(object): ...@@ -380,7 +381,7 @@ class Modules(object):
return modules return modules
def help(self): 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"): for obj in self.list(attribute="CLI"):
if obj.CLI: if obj.CLI:
......
...@@ -6,7 +6,6 @@ import ctypes ...@@ -6,7 +6,6 @@ import ctypes
import ctypes.util import ctypes.util
import binwalk.common import binwalk.common
import binwalk.module import binwalk.module
import binwalk.smartstrings
from binwalk.compat import * from binwalk.compat import *
class HashResult(object): class HashResult(object):
......
...@@ -115,6 +115,8 @@ class Plugins: ...@@ -115,6 +115,8 @@ class Plugins:
val = callback(arg) val = callback(arg)
if val is not None: if val is not None:
retval |= val retval |= val
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
sys.stderr.write("WARNING: %s.%s failed: %s\n" % (callback.__module__, callback.__name__, e)) sys.stderr.write("WARNING: %s.%s failed: %s\n" % (callback.__module__, callback.__name__, e))
...@@ -171,7 +173,9 @@ class Plugins: ...@@ -171,7 +173,9 @@ class Plugins:
try: try:
enabled = plugin_class.ENABLED enabled = plugin_class.ENABLED
except: except KeyboardInterrupt as e:
raise e
except Exception as e:
enabled = True enabled = True
plugins[key]['enabled'][module] = enabled plugins[key]['enabled'][module] = enabled
...@@ -180,7 +184,9 @@ class Plugins: ...@@ -180,7 +184,9 @@ class Plugins:
try: try:
plugins[key]['descriptions'][module] = plugin_class.__doc__.strip().split('\n')[0] 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' plugins[key]['descriptions'][module] = 'No description'
return plugins return plugins
...@@ -201,26 +207,36 @@ class Plugins: ...@@ -201,26 +207,36 @@ class Plugins:
# If this plugin is disabled by default and has not been explicitly white listed, ignore it # 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: if plugin_class.ENABLED == False and module not in self.whitelist:
continue continue
except: except KeyboardInterrupt as e:
raise e
except Exception as e:
pass pass
class_instance = plugin_class() class_instance = plugin_class()
try: try:
self.result.append(getattr(class_instance, self.RESULT)) self.result.append(getattr(class_instance, self.RESULT))
except: except KeyboardInterrupt as e:
raise e
except Exception as e:
pass pass
try: try:
self.pre_scan.append(getattr(class_instance, self.PRESCAN)) self.pre_scan.append(getattr(class_instance, self.PRESCAN))
except: except KeyboardInterrupt as e:
raise e
except Exception as e:
pass pass
try: try:
self.post_scan.append(getattr(class_instance, self.POSTSCAN)) self.post_scan.append(getattr(class_instance, self.POSTSCAN))
except: except KeyboardInterrupt as e:
raise e
except Exception as e:
pass pass
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
sys.stderr.write("WARNING: Failed to load plugin module '%s': %s\n" % (module, str(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