Commit 4e6c3063 by Craig Heffner

Fixed plugin extractor ordering.

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