From 850b32e4b95094399bfd298c21bcdf6e1f8dfcec Mon Sep 17 00:00:00 2001 From: devttys0 <heffnercj@gmail.com> Date: Mon, 29 Dec 2014 14:32:14 -0500 Subject: [PATCH] Added ability to specify explicit return codes for external extractors --- src/binwalk/modules/extractor.py | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/binwalk/modules/extractor.py b/src/binwalk/modules/extractor.py index c77bb02..5d03e94 100644 --- a/src/binwalk/modules/extractor.py +++ b/src/binwalk/modules/extractor.py @@ -163,7 +163,7 @@ class Extractor(Module): def append_rule(self, r): self.extract_rules.append(r.copy()) - def add_rule(self, txtrule=None, regex=None, extension=None, cmd=None): + def add_rule(self, txtrule=None, regex=None, extension=None, cmd=None, codes=[0, None]): ''' Adds a set of rules to the extraction rule list. @@ -172,6 +172,7 @@ class Extractor(Module): @extension - If rule string is not specified, this is the file extension to use. @cmd - If rule string is not specified, this is the command to run. Alternatively a callable object may be specified, which will be passed one argument: the path to the file to extract. + @codes - A list of valid return codes for the extractor. Returns None. ''' @@ -180,7 +181,8 @@ class Extractor(Module): r = { 'extension' : '', 'cmd' : '', - 'regex' : None + 'regex' : None, + 'codes' : codes } # Process single explicitly specified rule @@ -209,6 +211,7 @@ class Extractor(Module): r['regex'] = re.compile(values[0]) r['extension'] = values[1] r['cmd'] = values[2] + r['codes'] = values[3] except KeyboardInterrupt as e: raise e except Exception: @@ -397,7 +400,7 @@ class Extractor(Module): # Execute the specified command against the extracted file if self.run_extractors: - extract_ok = self.execute(rule['cmd'], fname) + extract_ok = self.execute(rule['cmd'], fname, rule['codes']) else: extract_ok = True @@ -486,9 +489,20 @@ class Extractor(Module): @rule - Rule string. - Returns an array of ['<case insensitive matching string>', '<file extension>', '<command to run>']. + Returns an array of ['<case insensitive matching string>', '<file extension>', '<command to run>', '<comma separated return codes>']. ''' - return rule.strip().split(self.RULE_DELIM, 2) + values = rule.strip().split(self.RULE_DELIM, 3) + + if len(values) == 4: + codes = values[3].split(',') + for i in range(0, len(codes)): + try: + codes[i] = int(codes[i], 0) + except ValueError as e: + binwalk.core.common.warning("The specified return code '%s' for extractor '%s' is not a valid number!" % (codes[i], values[0])) + values[3] = codes + + return values def _dd(self, file_name, offset, size, extension, output_file_name=None): ''' @@ -550,12 +564,13 @@ class Extractor(Module): binwalk.core.common.debug("Carved data block 0x%X - 0x%X from '%s' to '%s'" % (offset, offset+size, file_name, fname)) return fname - def execute(self, cmd, fname): + def execute(self, cmd, fname, codes=[0, None]): ''' Execute a command against the specified file. @cmd - Command to execute. @fname - File to run command against. + @codes - List of return codes indicating cmd success. Returns True on success, False on failure, or None if the external extraction utility could not be found. ''' @@ -592,13 +607,20 @@ class Extractor(Module): binwalk.core.common.debug("subprocess.call(%s, stdout=%s, stderr=%s)" % (command, str(tmp), str(tmp))) rval = subprocess.call(shlex.split(command), stdout=tmp, stderr=tmp) - binwalk.core.common.debug('External extractor command "%s" completed with return code %d' % (cmd, rval)) - if rval == 0: + if rval in codes: retval = True else: retval = False - break + + binwalk.core.common.debug('External extractor command "%s" completed with return code %d (success: %s)' % (cmd, rval, str(retval))) + + # TODO: Should errors from all commands in a command string be checked? Currently we only support + # specifying one set of error codes, so at the moment, this is not done; it is up to the + # final command to return success or failure (which presumably it will if previous necessary + # commands were not successful, but this is an assumption). + #if retval == False: + # break except KeyboardInterrupt as e: raise e -- libgit2 0.26.0