Commit b16c8417 by devttys0

Replaced binwalk script with one using the new API.

parent e929bb00
...@@ -134,33 +134,37 @@ class MagicFilter: ...@@ -134,33 +134,37 @@ class MagicFilter:
return self.FILTER_INCLUDE return self.FILTER_INCLUDE
def invalid(self, data): def valid_magic_result(self, data):
''' '''
Checks if the given string contains invalid data. Checks if the given string contains invalid data.
Called internally by Binwalk.scan(). Called internally by Binwalk.scan().
@data - String to validate. @data - String to validate.
Returns True if data is invalid, False if valid. Returns True if data is valid, False if invalid.
''' '''
# A result of 'data' is never ever valid. # A result of 'data' is never ever valid.
if data == self.DATA_RESULT: if data == self.DATA_RESULT:
return True return False
# If showing invalid results, just return False. # Make sure this result wasn't filtered
if self.show_invalid_results: if self.filter(data) == self.FILTER_EXCLUDE:
return False return False
# If showing invalid results, just return True without further checking.
if self.show_invalid_results:
return True
# Don't include quoted strings or keyword arguments in this search, as # Don't include quoted strings or keyword arguments in this search, as
# strings from the target file may legitimately contain the INVALID_RESULT text. # strings from the target file may legitimately contain the INVALID_RESULT text.
if self.INVALID_RESULT in common.strip_quoted_strings(self.smart._strip_tags(data)): if self.INVALID_RESULT in common.strip_quoted_strings(self.smart._strip_tags(data)):
return True return False
# There should be no non-printable characters in any of the data # There should be no non-printable characters in any of the data
if self.NON_PRINTABLE_RESULT in data: if self.NON_PRINTABLE_RESULT in data:
return True return False
return False return True
def grep(self, data=None, filters=[]): def grep(self, data=None, filters=[]):
''' '''
......
...@@ -104,9 +104,6 @@ class Module(object): ...@@ -104,9 +104,6 @@ class Module(object):
''' '''
All module classes must be subclassed from this. All module classes must be subclassed from this.
''' '''
# The module name, automatically populated.
NAME = ""
# The module title, as displayed in help output # The module title, as displayed in help output
TITLE = "" TITLE = ""
...@@ -140,7 +137,8 @@ class Module(object): ...@@ -140,7 +137,8 @@ class Module(object):
# self.plugins = x # self.plugins = x
self.errors = [] self.errors = []
self.results = [] self.results = []
self.NAME = self.__class__.__name__ self.status = None
self.name = self.__class__.__name__
process_kwargs(self, kwargs) process_kwargs(self, kwargs)
...@@ -218,21 +216,29 @@ class Module(object): ...@@ -218,21 +216,29 @@ class Module(object):
return args return args
def result(self, **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.
Accepts the same kwargs as the binwalk.module.Result class. Accepts the same kwargs as the binwalk.module.Result class.
@r - An existing instance of binwalk.module.Result.
Returns None. Returns None.
''' '''
r = Result(**kwargs) if r is None:
r = Result(**kwargs)
self.validate(r) self.validate(r)
self._plugins_callback(r) self._plugins_callback(r)
if r.valid: if r.valid:
self.results.append(r) self.results.append(r)
# Update the progress status automatically if it is not being done manually by the module
if r.file and not self.status.total:
self.status.total = r.file.length
self.status.completed = r.file.tell() - r.file.offset
if r.display: if r.display:
display_args = self._build_display_args(r) display_args = self._build_display_args(r)
if display_args: if display_args:
...@@ -266,12 +272,14 @@ class Module(object): ...@@ -266,12 +272,14 @@ class Module(object):
def footer(self): def footer(self):
self.config.display.footer() self.config.display.footer()
def main(self): def main(self, status):
''' '''
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
try: try:
self.init() self.init()
except KeyboardInterrupt as e: except KeyboardInterrupt as e:
...@@ -302,6 +310,16 @@ class Module(object): ...@@ -302,6 +310,16 @@ class Module(object):
return retval return retval
class Status(object):
def __init__(self, **kwargs):
self.kwargs = kwargs
self.clear()
def clear(self):
for (k,v) in iterator(self.kwargs):
setattr(self, k, v)
class Modules(object): class Modules(object):
''' '''
Main class used for running and managing modules. Main class used for running and managing modules.
...@@ -316,21 +334,24 @@ class Modules(object): ...@@ -316,21 +334,24 @@ class Modules(object):
Returns None. Returns None.
''' '''
argv = list(argv) self.arguments = []
self.loaded_modules = {}
self.status = Status(completed=0, total=0)
self._set_arguments(list(argv), kargv)
def _set_arguments(self, argv=[], kargv={}):
for (k,v) in iterator(kargv): for (k,v) in iterator(kargv):
k = self._parse_api_opt(k) k = self._parse_api_opt(k)
if v not in [True, False, None]: if v not in [True, False, None]:
argv.append("%s %s" % (k, v)) argv.append("%s %s" % (k, v))
else: else:
argv.append(k) argv.append(k)
if not argv: if not argv and not self.arguments:
argv = sys.argv[1:] self.arguments = sys.argv[1:]
elif argv:
self.arguments = argv self.arguments = argv
self.loaded_modules = {}
def _parse_api_opt(self, opt): def _parse_api_opt(self, opt):
# If the argument already starts with a hyphen, don't add hyphens in front of it # If the argument already starts with a hyphen, don't add hyphens in front of it
...@@ -384,18 +405,22 @@ class Modules(object): ...@@ -384,18 +405,22 @@ class Modules(object):
return help_string + "\n" return help_string + "\n"
def execute(self): def execute(self, *args, **kwargs):
run_modules = [] run_modules = []
self._set_arguments(list(args), kwargs)
for module in self.list(): for module in self.list():
if self.run(module): obj = self.run(module)
run_modules.append(module) if obj.enabled:
run_modules.append(obj)
return run_modules return run_modules
def run(self, module): def run(self, module):
obj = self.load(module) obj = self.load(module)
if isinstance(obj, binwalk.module.Module) and obj.enabled: if isinstance(obj, binwalk.module.Module) and obj.enabled:
obj.main() obj.main(status=self.status)
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
# loaded directly and is subsequently also listed as a dependency we don't waste # loaded directly and is subsequently also listed as a dependency we don't waste
......
...@@ -2,6 +2,7 @@ import os ...@@ -2,6 +2,7 @@ import os
import sys import sys
import binwalk.common import binwalk.common
import binwalk.module import binwalk.module
import binwalk.config
import binwalk.display import binwalk.display
from binwalk.config import * from binwalk.config import *
from binwalk.compat import * from binwalk.compat import *
...@@ -87,6 +88,7 @@ class Configuration(binwalk.module.Module): ...@@ -87,6 +88,7 @@ class Configuration(binwalk.module.Module):
def load(self): def load(self):
self.target_files = [] self.target_files = []
self.settings = binwalk.config.Config()
self.display = binwalk.display.Display(log=self.log_file, self.display = binwalk.display.Display(log=self.log_file,
csv=self.csv, csv=self.csv,
quiet=self.quiet, quiet=self.quiet,
......
import magic import magic
import binwalk.config
import binwalk.module import binwalk.module
import binwalk.parser import binwalk.parser
import binwalk.filter import binwalk.filter
...@@ -37,9 +36,6 @@ class Signature(binwalk.module.Module): ...@@ -37,9 +36,6 @@ class Signature(binwalk.module.Module):
MAGIC_FLAGS = magic.MAGIC_NO_CHECK_TEXT | magic.MAGIC_NO_CHECK_ENCODING | magic.MAGIC_NO_CHECK_APPTYPE | magic.MAGIC_NO_CHECK_TOKENS MAGIC_FLAGS = magic.MAGIC_NO_CHECK_TEXT | magic.MAGIC_NO_CHECK_ENCODING | magic.MAGIC_NO_CHECK_APPTYPE | magic.MAGIC_NO_CHECK_TOKENS
def init(self): def init(self):
# Instantiate the config class so we can access file/directory paths
self.conf = binwalk.config.Config()
# Create SmartSignature and MagicParser class instances. These are mostly for internal use. # Create SmartSignature and MagicParser class instances. These are mostly for internal use.
self.filter = binwalk.filter.MagicFilter() self.filter = binwalk.filter.MagicFilter()
self.smart = binwalk.smartsignature.SmartSignature(self.filter, ignore_smart_signatures=False) self.smart = binwalk.smartsignature.SmartSignature(self.filter, ignore_smart_signatures=False)
...@@ -49,8 +45,8 @@ class Signature(binwalk.module.Module): ...@@ -49,8 +45,8 @@ class Signature(binwalk.module.Module):
if not self.magic_files: if not self.magic_files:
# Append the user's magic file first so that those signatures take precedence # Append the user's magic file first so that those signatures take precedence
self.magic_files = [ self.magic_files = [
self.conf.paths['user'][self.conf.BINWALK_MAGIC_FILE], self.config.settings.paths['user'][self.config.settings.BINWALK_MAGIC_FILE],
self.conf.paths['system'][self.conf.BINWALK_MAGIC_FILE], self.config.settings.paths['system'][self.config.settings.BINWALK_MAGIC_FILE],
] ]
# Parse the magic file(s) and initialize libmagic # Parse the magic file(s) and initialize libmagic
...@@ -61,15 +57,28 @@ class Signature(binwalk.module.Module): ...@@ -61,15 +57,28 @@ class Signature(binwalk.module.Module):
# Once the temporary magic file is loaded into libmagic, we don't need it anymore; delete the temp file # Once the temporary magic file is loaded into libmagic, we don't need it anymore; delete the temp file
self.parser.rm_magic_file() self.parser.rm_magic_file()
def validate(self, r):
'''
Called automatically by self.result.
'''
if not r.description:
r.valid = False
if r.size and (r.size + r.offset) > r.file.size:
r.valid = False
if r.jump and (r.jump + r.offset) > r.file.size:
r.valid = False
def scan_file(self, fp): def scan_file(self, fp):
while True: while True:
current_block_offset = 0
(data, dlen) = fp.read_block() (data, dlen) = fp.read_block()
if not data: if not data:
break break
current_block_offset = 0
block_start = fp.tell() - dlen block_start = fp.tell() - dlen
self.status.completed = block_start - fp.offset
for candidate_offset in self.parser.find_signature_candidates(data, dlen): for candidate_offset in self.parser.find_signature_candidates(data, dlen):
if candidate_offset < current_block_offset: if candidate_offset < current_block_offset:
...@@ -81,19 +90,27 @@ class Signature(binwalk.module.Module): ...@@ -81,19 +90,27 @@ class Signature(binwalk.module.Module):
# Pass the data to libmagic, and split out multiple results into a list # Pass the data to libmagic, and split out multiple results into a list
magic_result = self.magic.buffer(candidate_data) magic_result = self.magic.buffer(candidate_data)
# TODO: Should filter process other validations? Reported size, for example? if self.filter.valid_magic_result(magic_result):
if not self.filter.invalid(magic_result):
# The smart filter parser returns a dictionary of keyword values and the signature description. # The smart filter parser returns a dictionary of keyword values and the signature description.
smart = self.smart.parse(magic_result) r = self.smart.parse(magic_result)
self.result(description=smart['description'], offset=block_start+candidate_offset) r.offset = block_start + candidate_offset + r.adjust
r.file = fp
if smart['jump'] > 0:
fp.seek(block_start + candidate_offset + smart['jump']) self.result(r=r)
current_block_offset = smart['jump']
if r.valid and r.jump > 0:
fp.seek(r.offset + r.jump)
current_block_offset = r.jump
def run(self): def run(self):
for fp in self.config.target_files: for fp in self.config.target_files:
self.header() self.header()
self.status.clear()
self.status.total = fp.size
self.status.completed = 0
self.scan_file(fp) self.scan_file(fp)
self.footer() self.footer()
...@@ -55,7 +55,9 @@ class MagicParser: ...@@ -55,7 +55,9 @@ class MagicParser:
def __del__(self): def __del__(self):
try: try:
self.cleanup() self.cleanup()
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
def rm_magic_file(self): def rm_magic_file(self):
...@@ -66,7 +68,9 @@ class MagicParser: ...@@ -66,7 +68,9 @@ class MagicParser:
''' '''
try: try:
self.fd.close() self.fd.close()
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
def cleanup(self): def cleanup(self):
...@@ -79,7 +83,9 @@ class MagicParser: ...@@ -79,7 +83,9 @@ class MagicParser:
try: try:
self.raw_fd.close() self.raw_fd.close()
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
def file_from_string(self, signature_string, offset=0, display_name=DEFAULT_DISPLAY_NAME): def file_from_string(self, signature_string, offset=0, display_name=DEFAULT_DISPLAY_NAME):
...@@ -170,6 +176,8 @@ class MagicParser: ...@@ -170,6 +176,8 @@ class MagicParser:
self.fd.write(str2bytes(line)) self.fd.write(str2bytes(line))
self.build_signature_set() self.build_signature_set()
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
raise Exception("Error parsing magic file '%s' on line %d: %s" % (file_name, line_count, str(e))) raise Exception("Error parsing magic file '%s' on line %d: %s" % (file_name, line_count, str(e)))
...@@ -207,6 +215,8 @@ class MagicParser: ...@@ -207,6 +215,8 @@ class MagicParser:
# The condition line may contain escaped sequences, so be sure to decode it properly. # The condition line may contain escaped sequences, so be sure to decode it properly.
entry['condition'] = string_decode(line_parts[2]) entry['condition'] = string_decode(line_parts[2])
entry['description'] = ' '.join(line_parts[3:]) entry['description'] = ' '.join(line_parts[3:])
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
raise Exception("%s :: %s", (str(e), line)) raise Exception("%s :: %s", (str(e), line))
...@@ -214,6 +224,8 @@ class MagicParser: ...@@ -214,6 +224,8 @@ class MagicParser:
# throw an exception, but let's catch it just in case... # throw an exception, but let's catch it just in case...
try: try:
entry['offset'] = str2int(entry['offset']) entry['offset'] = str2int(entry['offset'])
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
raise Exception("%s :: %s", (str(e), line)) raise Exception("%s :: %s", (str(e), line))
...@@ -234,6 +246,8 @@ class MagicParser: ...@@ -234,6 +246,8 @@ class MagicParser:
# but needing that is rare. # but needing that is rare.
try: try:
intval = str2int(entry['condition'].strip('L')) intval = str2int(entry['condition'].strip('L'))
except KeyboardInterrupt as e:
raise e
except Exception as e: except Exception as e:
raise Exception("Failed to evaluate condition for '%s' type: '%s', condition: '%s', error: %s" % (entry['description'], entry['type'], entry['condition'], str(e))) raise Exception("Failed to evaluate condition for '%s' type: '%s', condition: '%s', error: %s" % (entry['description'], entry['type'], entry['condition'], str(e)))
...@@ -322,6 +336,8 @@ class MagicParser: ...@@ -322,6 +336,8 @@ class MagicParser:
''' '''
try: try:
return data.split(self.RESULT_SEPERATOR) return data.split(self.RESULT_SEPERATOR)
except: except KeyboardInterrupt as e:
raise e
except Exception:
return [] return []
import os import os
import sys import sys
import imp import imp
import binwalk.config
from binwalk.compat import * from binwalk.compat import *
# Valid return values for plugins
PLUGIN_CONTINUE = 0x00
PLUGIN_NO_EXTRACT = 0x01
PLUGIN_NO_DISPLAY = 0x02
PLUGIN_STOP_PLUGINS = 0x04
PLUGIN_TERMINATE = 0x08
class Plugins: class Plugins:
''' '''
Class to load and call plugin callback functions, handled automatically by Binwalk.scan / Binwalk.single_scan. Class to load and call plugin callback functions, handled automatically by Binwalk.scan / Binwalk.single_scan.
...@@ -66,7 +60,7 @@ class Plugins: ...@@ -66,7 +60,7 @@ class Plugins:
# Set to False to have this plugin disabled by default. # Set to False to have this plugin disabled by default.
ENABLED = True ENABLED = True
def __init__(self, binwalk): def __init__(self):
self.binwalk = binwalk self.binwalk = binwalk
print 'Scanning initialized!' print 'Scanning initialized!'
...@@ -86,16 +80,15 @@ class Plugins: ...@@ -86,16 +80,15 @@ class Plugins:
return PLUGIN_CONTINUE return PLUGIN_CONTINUE
''' '''
CALLBACK = 'callback' RESULT = 'result'
PRESCAN = 'pre_scan' PRESCAN = 'pre_scan'
POSTSCAN = 'post_scan' POSTSCAN = 'post_scan'
PREPARSER = 'pre_parser'
PLUGIN = 'Plugin' PLUGIN = 'Plugin'
MODULE_EXTENSION = '.py' MODULE_EXTENSION = '.py'
def __init__(self, binwalk, whitelist=[], blacklist=[]): def __init__(self, whitelist=[], blacklist=[]):
self.binwalk = binwalk self.config = binwalk.config.Config()
self.callback = [] self.result = []
self.pre_scan = [] self.pre_scan = []
self.pre_parser = [] self.pre_parser = []
self.post_scan = [] self.post_scan = []
...@@ -103,16 +96,13 @@ class Plugins: ...@@ -103,16 +96,13 @@ class Plugins:
self.blacklist = blacklist self.blacklist = blacklist
def __del__(self): def __del__(self):
self._cleanup() pass
def __exit__(self, t, v, traceback): def __enter__(self):
self._cleanup() return self
def _cleanup(self): def __exit__(self, t, v, traceback):
try: pass
del self.binwalk
except:
pass
def _call_plugins(self, callback_list, arg): def _call_plugins(self, callback_list, arg):
retval = PLUGIN_CONTINUE retval = PLUGIN_CONTINUE
...@@ -168,7 +158,7 @@ class Plugins: ...@@ -168,7 +158,7 @@ class Plugins:
} }
for key in plugins.keys(): for key in plugins.keys():
plugins[key]['path'] = self.binwalk.config.paths[key][self.binwalk.config.PLUGINS] plugins[key]['path'] = self.config.paths[key][self.config.PLUGINS]
for file_name in os.listdir(plugins[key]['path']): for file_name in os.listdir(plugins[key]['path']):
if file_name.endswith(self.MODULE_EXTENSION): if file_name.endswith(self.MODULE_EXTENSION):
...@@ -214,10 +204,10 @@ class Plugins: ...@@ -214,10 +204,10 @@ class Plugins:
except: except:
pass pass
class_instance = plugin_class(self.binwalk) class_instance = plugin_class()
try: try:
self.callback.append(getattr(class_instance, self.CALLBACK)) self.result.append(getattr(class_instance, self.RESULT))
except: except:
pass pass
...@@ -227,11 +217,6 @@ class Plugins: ...@@ -227,11 +217,6 @@ class Plugins:
pass pass
try: try:
self.pre_parser.append(getattr(class_instance, self.PREPARSER))
except:
pass
try:
self.post_scan.append(getattr(class_instance, self.POSTSCAN)) self.post_scan.append(getattr(class_instance, self.POSTSCAN))
except: except:
pass pass
...@@ -239,15 +224,12 @@ class Plugins: ...@@ -239,15 +224,12 @@ class Plugins:
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)))
def _pre_scan_callbacks(self, fd): def _pre_scan_callbacks(self, obj):
return self._call_plugins(self.pre_scan, fd) return self._call_plugins(self.pre_scan, obj)
def _post_scan_callbacks(self, fd):
return self._call_plugins(self.post_scan, fd)
def _scan_callbacks(self, results): def _post_scan_callbacks(self, obj):
return self._call_plugins(self.callback, results) return self._call_plugins(self.post_scan, obj)
def _scan_pre_parser_callbacks(self, results): def _result_callbacks(self, obj):
return self._call_plugins(self.pre_parser, results) return self._call_plugins(self.result, obj)
import re import re
import binwalk.module
from binwalk.compat import * from binwalk.compat import *
from binwalk.common import str2int, get_quoted_strings, MathExpression from binwalk.common import str2int, get_quoted_strings, MathExpression
...@@ -18,20 +19,20 @@ class SmartSignature: ...@@ -18,20 +19,20 @@ class SmartSignature:
KEYWORD_DELIM_START = "{" KEYWORD_DELIM_START = "{"
KEYWORD_DELIM_END = "}" KEYWORD_DELIM_END = "}"
KEYWORDS = { KEYWORDS = {
'jump' : '%sjump-to-offset:' % KEYWORD_DELIM_START, 'jump' : '%sjump-to-offset:' % KEYWORD_DELIM_START,
'filename' : '%sfile-name:' % KEYWORD_DELIM_START, 'filename' : '%sfile-name:' % KEYWORD_DELIM_START,
'filesize' : '%sfile-size:' % KEYWORD_DELIM_START, 'filesize' : '%sfile-size:' % KEYWORD_DELIM_START,
'raw-string' : '%sraw-string:' % KEYWORD_DELIM_START, # This one is special and must come last in a signature block 'raw-string' : '%sraw-string:' % KEYWORD_DELIM_START, # This one is special and must come last in a signature block
'string-len' : '%sstring-len:' % KEYWORD_DELIM_START, # This one is special and must come last in a signature block 'string-len' : '%sstring-len:' % KEYWORD_DELIM_START, # This one is special and must come last in a signature block
'raw-size' : '%sraw-string-length:' % KEYWORD_DELIM_START, 'raw-size' : '%sraw-string-length:' % KEYWORD_DELIM_START,
'adjust' : '%soffset-adjust:' % KEYWORD_DELIM_START, 'adjust' : '%soffset-adjust:' % KEYWORD_DELIM_START,
'delay' : '%sextract-delay:' % KEYWORD_DELIM_START, 'delay' : '%sextract-delay:' % KEYWORD_DELIM_START,
'year' : '%sfile-year:' % KEYWORD_DELIM_START, 'year' : '%sfile-year:' % KEYWORD_DELIM_START,
'epoch' : '%sfile-epoch:' % KEYWORD_DELIM_START, 'epoch' : '%sfile-epoch:' % KEYWORD_DELIM_START,
'math' : '%smath:' % KEYWORD_DELIM_START, 'math' : '%smath:' % KEYWORD_DELIM_START,
'raw-replace' : '%sraw-replace%s' % (KEYWORD_DELIM_START, KEYWORD_DELIM_END), 'raw-replace' : '%sraw-replace%s' % (KEYWORD_DELIM_START, KEYWORD_DELIM_END),
'one-of-many' : '%sone-of-many%s' % (KEYWORD_DELIM_START, KEYWORD_DELIM_END), 'one-of-many' : '%sone-of-many%s' % (KEYWORD_DELIM_START, KEYWORD_DELIM_END),
'string-len-replace' : '%sstring-len%s' % (KEYWORD_DELIM_START, KEYWORD_DELIM_END), 'string-len-replace' : '%sstring-len%s' % (KEYWORD_DELIM_START, KEYWORD_DELIM_END),
} }
...@@ -45,7 +46,7 @@ class SmartSignature: ...@@ -45,7 +46,7 @@ class SmartSignature:
Returns None. Returns None.
''' '''
self.filter = filter self.filter = filter
self.invalid = False self.valid = True
self.last_one_of_many = None self.last_one_of_many = None
self.ignore_smart_signatures = ignore_smart_signatures self.ignore_smart_signatures = ignore_smart_signatures
...@@ -58,28 +59,30 @@ class SmartSignature: ...@@ -58,28 +59,30 @@ class SmartSignature:
Returns a dictionary of parsed values. Returns a dictionary of parsed values.
''' '''
results = { results = {
'offset' : '', # Offset where the match was found, filled in by Binwalk.single_scan. 'offset' : '', # Offset where the match was found, filled in by Binwalk.single_scan.
'description' : '', # The libmagic data string, stripped of all keywords 'description' : '', # The libmagic data string, stripped of all keywords
'name' : '', # The original name of the file, if known 'name' : '', # The original name of the file, if known
'delay' : '', # Extract delay description 'delay' : '', # Extract delay description
'extract' : '', # Name of the extracted file, filled in by Binwalk.single_scan. 'extract' : '', # Name of the extracted file, filled in by Binwalk.single_scan.
'jump' : 0, # The relative offset to resume the scan from 'jump' : 0, # The relative offset to resume the scan from
'size' : 0, # The size of the file, if known 'size' : 0, # The size of the file, if known
'adjust' : 0, # The relative offset to add to the reported offset 'adjust' : 0, # The relative offset to add to the reported offset
'year' : 0, # The file's creation/modification year, if reported in the signature 'year' : 0, # The file's creation/modification year, if reported in the signature
'epoch' : 0, # The file's creation/modification epoch time, if reported in the signature 'epoch' : 0, # The file's creation/modification epoch time, if reported in the signature
'invalid' : False, # Set to True if parsed numerical values appear invalid 'valid' : True, # Set to False if parsed numerical values appear invalid
} }
self.invalid = False self.valid = True
# If smart signatures are disabled, or the result data is not valid (i.e., potentially malicious), # If smart signatures are disabled, or the result data is not valid (i.e., potentially malicious),
# don't parse anything, just return the raw data as the description. # don't parse anything, just return the raw data as the description.
if self.ignore_smart_signatures or not self._is_valid(data): if self.ignore_smart_signatures or not self._is_valid(data):
results['description'] = data results['description'] = data
else: else:
# Calculate and replace math keyword values # Calculate and replace special keywords/values
data = self._replace_maths(data) data = self._replace_maths(data)
data = self._parse_raw_strings(data)
data = self._parse_string_len(data)
# Parse the offset-adjust value. This is used to adjust the reported offset at which # Parse the offset-adjust value. This is used to adjust the reported offset at which
# a signature was located due to the fact that MagicParser.match expects all signatures # a signature was located due to the fact that MagicParser.match expects all signatures
...@@ -91,17 +94,23 @@ class SmartSignature: ...@@ -91,17 +94,23 @@ class SmartSignature:
# extracted (see Binwalk.scan). # extracted (see Binwalk.scan).
try: try:
results['size'] = str2int(self._get_math_arg(data, 'filesize')) results['size'] = str2int(self._get_math_arg(data, 'filesize'))
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
try: try:
results['year'] = str2int(self._get_keyword_arg(data, 'year')) results['year'] = str2int(self._get_keyword_arg(data, 'year'))
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
try: try:
results['epoch'] = str2int(self._get_keyword_arg(data, 'epoch')) results['epoch'] = str2int(self._get_keyword_arg(data, 'epoch'))
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
results['delay'] = self._get_keyword_arg(data, 'delay') results['delay'] = self._get_keyword_arg(data, 'delay')
...@@ -116,9 +125,9 @@ class SmartSignature: ...@@ -116,9 +125,9 @@ class SmartSignature:
results['name'] = self._get_keyword_arg(data, 'filename').strip('"') results['name'] = self._get_keyword_arg(data, 'filename').strip('"')
results['description'] = self._strip_tags(data) results['description'] = self._strip_tags(data)
results['invalid'] = self.invalid results['valid'] = self.valid
return results return binwalk.module.Result(**results)
def _is_valid(self, data): def _is_valid(self, data):
''' '''
...@@ -152,7 +161,7 @@ class SmartSignature: ...@@ -152,7 +161,7 @@ class SmartSignature:
Returns True if the string result is one of many. Returns True if the string result is one of many.
Returns False if the string result is not one of many. Returns False if the string result is not one of many.
''' '''
if not self.filter.invalid(data): if self.filter.valid_magic_result(data):
if self.last_one_of_many is not None and data.startswith(self.last_one_of_many): if self.last_one_of_many is not None and data.startswith(self.last_one_of_many):
return True return True
...@@ -197,7 +206,7 @@ class SmartSignature: ...@@ -197,7 +206,7 @@ class SmartSignature:
value = MathExpression(arg).value value = MathExpression(arg).value
if value is None: if value is None:
value = 0 value = 0
self.invalid = True self.valid = False
return value return value
...@@ -215,7 +224,9 @@ class SmartSignature: ...@@ -215,7 +224,9 @@ class SmartSignature:
if offset_str: if offset_str:
try: try:
offset = str2int(offset_str) offset = str2int(offset_str)
except: except KeyboardInterrupt as e:
raise e
except Exception:
pass pass
return offset return offset
...@@ -281,7 +292,9 @@ class SmartSignature: ...@@ -281,7 +292,9 @@ class SmartSignature:
# Convert the string to an integer as a sanity check # Convert the string to an integer as a sanity check
try: try:
string_length = '%d' % len(raw_string) string_length = '%d' % len(raw_string)
except: except KeyboardInterrupt as e:
raise e
except Exception:
string_length = '0' string_length = '0'
# Strip out *everything* after the string-len keyword, including the keyword itself. # Strip out *everything* after the string-len keyword, including the keyword itself.
......
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