Commit 4e6c3063 by Craig Heffner

Fixed plugin extractor ordering.

parent 8d0afa75
...@@ -275,7 +275,18 @@ class Extractor(Module): ...@@ -275,7 +275,18 @@ class Extractor(Module):
def append_rule(self, r): def append_rule(self, r):
self.extract_rules.append(r.copy()) self.extract_rules.append(r.copy())
def add_rule(self, txtrule=None, regex=None, extension=None, cmd=None, codes=[0, None], recurse=True): def prepend_rule(self, r):
self.extract_rules = [r] + self.extract_rules
def add_rule(self, txtrule=None, regex=None, extension=None, cmd=None, codes=[0, None], recurse=True, prepend=False):
rules = self.create_rule(txtrule, regex, extension, cmd, codes, recurse)
for r in rules:
if prepend:
self.prepend_rule(r)
else:
self.append_rule(r)
def create_rule(self, txtrule=None, regex=None, extension=None, cmd=None, codes=[0, None], recurse=True):
''' '''
Adds a set of rules to the extraction rule list. Adds a set of rules to the extraction rule list.
...@@ -290,6 +301,7 @@ class Extractor(Module): ...@@ -290,6 +301,7 @@ class Extractor(Module):
Returns None. Returns None.
''' '''
rules = [] rules = []
created_rules = []
match = False match = False
r = { r = {
'extension': '', 'extension': '',
...@@ -306,8 +318,7 @@ class Extractor(Module): ...@@ -306,8 +318,7 @@ class Extractor(Module):
if cmd: if cmd:
r['cmd'] = cmd r['cmd'] = cmd
self.append_rule(r) return [r]
return
# Process rule string, or list of rule strings # Process rule string, or list of rule strings
if not isinstance(txtrule, type([])): if not isinstance(txtrule, type([])):
...@@ -334,7 +345,9 @@ class Extractor(Module): ...@@ -334,7 +345,9 @@ class Extractor(Module):
# Verify that the match string was retrieved. # Verify that the match string was retrieved.
if match: if match:
self.append_rule(r) created_rules.append(r)
return created_rules
def remove_rules(self, description): def remove_rules(self, description):
''' '''
...@@ -553,8 +566,7 @@ class Extractor(Module): ...@@ -553,8 +566,7 @@ class Extractor(Module):
if not rules: if not rules:
return (None, None, False) return (None, None, False)
else: else:
binwalk.core.common.debug( binwalk.core.common.debug("Found %d matching extraction rules" % len(rules))
"Found %d matching extraction rules" % len(rules))
# Generate the output directory name where extracted files will be # Generate the output directory name where extracted files will be
# stored # stored
...@@ -579,8 +591,7 @@ class Extractor(Module): ...@@ -579,8 +591,7 @@ class Extractor(Module):
recurse = True recurse = True
# Copy out the data to disk, if we haven't already # Copy out the data to disk, if we haven't already
fname = self._dd( fname = self._dd(file_path, offset, size, rule['extension'], output_file_name=name)
file_path, offset, size, rule['extension'], output_file_name=name)
# If there was a command specified for this rule, try to execute it. # If there was a command specified for this rule, try to execute it.
# If execution fails, the next rule will be attempted. # If execution fails, the next rule will be attempted.
...@@ -595,8 +606,7 @@ class Extractor(Module): ...@@ -595,8 +606,7 @@ class Extractor(Module):
# Execute the specified command against the extracted file # Execute the specified command against the extracted file
if self.run_extractors: if self.run_extractors:
extract_ok = self.execute( extract_ok = self.execute(rule['cmd'], fname, rule['codes'])
rule['cmd'], fname, rule['codes'])
else: else:
extract_ok = True extract_ok = True
...@@ -665,12 +675,22 @@ class Extractor(Module): ...@@ -665,12 +675,22 @@ class Extractor(Module):
Returns None if no match is found. Returns None if no match is found.
''' '''
rules = [] rules = []
ordered_rules = []
description = description.lower() description = description.lower()
for rule in self.extract_rules: for rule in self.extract_rules:
if rule['regex'].search(description): if rule['regex'].search(description):
rules.append(rule) rules.append(rule)
return rules
# Plugin rules should take precedence over external extraction commands.
for rule in rules:
if callable(rule['cmd']):
ordered_rules.append(rule)
for rule in rules:
if not callable(rule['cmd']):
ordered_rules.append(rule)
return ordered_rules
def _parse_rule(self, rule): def _parse_rule(self, rule):
''' '''
......
...@@ -23,16 +23,18 @@ class LZMAExtractPlugin(binwalk.core.plugin.Plugin): ...@@ -23,16 +23,18 @@ class LZMAExtractPlugin(binwalk.core.plugin.Plugin):
self.decompressor = lzma.decompress self.decompressor = lzma.decompress
# If the extractor is enabled for the module we're currently loaded # If the extractor is enabled for the module we're currently loaded
# into, then register self.extractor as a zlib extraction rule. # into, then register self.extractor as an lzma extraction rule.
if self.module.extractor.enabled: if self.module.extractor.enabled:
self.module.extractor.add_rule(txtrule=None, self.module.extractor.add_rule(txtrule=None,
regex="^lzma compressed data", regex="^lzma compressed data",
extension="7z", extension="7z",
cmd=self.extractor) cmd=self.extractor,
prepend=True)
self.module.extractor.add_rule(txtrule=None, self.module.extractor.add_rule(txtrule=None,
regex="^xz compressed data", regex="^xz compressed data",
extension="xz", extension="xz",
cmd=self.extractor) cmd=self.extractor,
prepend=True)
except ImportError as e: except ImportError as e:
pass pass
......
import os import os
import shutil
import binwalk.core.plugin import binwalk.core.plugin
from binwalk.core.compat import * from binwalk.core.compat import *
from binwalk.core.common import BlockFile from binwalk.core.common import BlockFile
...@@ -19,48 +18,42 @@ class LZMAModPlugin(binwalk.core.plugin.Plugin): ...@@ -19,48 +18,42 @@ class LZMAModPlugin(binwalk.core.plugin.Plugin):
def init(self): def init(self):
self.original_cmd = '' self.original_cmd = ''
# Replace the first existing LZMA extraction command with our own self.module.extractor.add_rule(txtrule=None,
for rule in self.module.extractor.match(self.SIGNATURE): regex="^%s" % self.SIGNATURE,
self.original_cmd = rule['cmd'] extension="7z",
rule['cmd'] = self.lzma_cable_extractor cmd=self.lzma_cable_extractor, prepend=True)
break
def lzma_cable_extractor(self, fname): def lzma_cable_extractor(self, fname):
# Try extracting the LZMA file without modification first out_name = os.path.splitext(fname)[0] + '-patched' + os.path.splitext(fname)[1]
result = self.module.extractor.execute(self.original_cmd, fname) fp_out = BlockFile(out_name, 'w')
# Use self.module.config.open_file here to ensure that other config
# settings (such as byte-swapping) are honored
fp_in = self.module.config.open_file(fname, offset=0, length=0)
fp_in.set_block_size(peek=0)
i = 0
# If the external extractor was successul (True) or didn't exist while i < fp_in.length:
# (None), don't do anything. (data, dlen) = fp_in.read_block()
if result not in [True, None]:
out_name = os.path.splitext(fname)[
0] + '-patched' + os.path.splitext(fname)[1]
fp_out = BlockFile(out_name, 'w')
# Use self.module.config.open_file here to ensure that other config
# settings (such as byte-swapping) are honored
fp_in = self.module.config.open_file(fname, offset=0, length=0)
fp_in.set_block_size(peek=0)
i = 0
while i < fp_in.length: if i == 0:
(data, dlen) = fp_in.read_block() out_data = data[0:5] + self.FAKE_LZMA_SIZE + data[5:]
else:
out_data = data
if i == 0: fp_out.write(out_data)
out_data = data[0:5] + self.FAKE_LZMA_SIZE + data[5:]
else:
out_data = data
fp_out.write(out_data) i += dlen
i += dlen fp_in.close()
fp_out.close()
fp_in.close() for rule in self.module.extractor.get_rules(self.SIGNATURE):
fp_out.close() if rule['cmd'] != self.lzma_cable_extractor:
result = self.module.extractor.execute(rule['cmd'], out_name)
# Overwrite the original file so that it can be cleaned up if -r if result == True:
# was specified break
shutil.move(out_name, fname)
result = self.module.extractor.execute(self.original_cmd, fname)
os.remove(out_name)
return result return result
def scan(self, result): def scan(self, result):
......
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