From 778ee6f5ec96e428ae758c4fc63eab74295e0ec7 Mon Sep 17 00:00:00 2001
From: devttys0 <heffnercj@gmail.com>
Date: Thu, 19 Dec 2013 16:51:27 -0500
Subject: [PATCH] Integrated plugins with new API

---
 src/binwalk/config.py             |   2 +-
 src/binwalk/magics/binarch        |  62 --------------------------------------------------------------
 src/binwalk/magics/bincast        |  10 ----------
 src/binwalk/magics/binwalk        |  14 +++++++++-----
 src/binwalk/magics/compressd      |   1 -
 src/binwalk/magics/zlib           |   4 ----
 src/binwalk/module.py             |  20 +++++++++++---------
 src/binwalk/plugin.py             | 113 +++++++++++++++++++++++------------------------------------------------------------------------------------------
 src/binwalk/plugins/armopcodes.py |  50 --------------------------------------------------
 src/binwalk/plugins/compressd.py  |  44 ++++++++++++++------------------------------
 src/binwalk/plugins/cpio.py       |  24 ++++++++++--------------
 src/binwalk/plugins/deflate.py    |  81 ---------------------------------------------------------------------------------
 src/binwalk/plugins/lzmamod.py    |  30 ++++++++++++++----------------
 src/binwalk/plugins/strcompat.py  |  22 ----------------------
 src/binwalk/plugins/zlib.py       |  42 ++++++++++++------------------------------
 src/magic/compressed              |  14 +++++++++-----
 src/setup.py                      |   4 ++--
 17 files changed, 105 insertions(+), 432 deletions(-)
 delete mode 100644 src/binwalk/magics/binarch
 delete mode 100644 src/binwalk/magics/bincast
 delete mode 100644 src/binwalk/magics/compressd
 delete mode 100644 src/binwalk/magics/zlib
 delete mode 100644 src/binwalk/plugins/armopcodes.py
 delete mode 100644 src/binwalk/plugins/deflate.py
 delete mode 100644 src/binwalk/plugins/strcompat.py

diff --git a/src/binwalk/config.py b/src/binwalk/config.py
index ebd133e..71e8c6e 100644
--- a/src/binwalk/config.py
+++ b/src/binwalk/config.py
@@ -39,7 +39,7 @@ class Config:
 
 	# Sub directories
 	BINWALK_USER_DIR = ".binwalk"
-	BINWALK_MAGIC_DIR = "magic"
+	BINWALK_MAGIC_DIR = "magics"
 	BINWALK_CONFIG_DIR = "configs"
 	BINWALK_PLUGINS_DIR = "plugins"
 
diff --git a/src/binwalk/magics/binarch b/src/binwalk/magics/binarch
deleted file mode 100644
index 6695ef2..0000000
--- a/src/binwalk/magics/binarch
+++ /dev/null
@@ -1,62 +0,0 @@
-# MIPS prologue
-# addiu $sp, -XX
-# 27 BD FF XX
-0	string	\377\275\47	MIPSEL instructions, function prologue{offset-adjust:-1}
-0       string  \47\275\377	MIPS instructions, function prologue
-
-# MIPS epilogue
-# jr $ra
-0	belong	0x03e00008	MIPS instructions, function epilogue
-0	lelong	0x03e00008	MIPSEL instructions, function epilogue
-
-# PowerPC prologue
-# mflr r0
-0	belong 0x7C0802A6	PowerPC big endian instructions, function prologue
-0	lelong 0x7C0802A6	PowerPC little endian instructions, funciton prologue
-
-# PowerPC epilogue
-# blr
-0	belong 0x4E800020	PowerPC big endian instructions, function epilogue
-0	lelong 0x4E800020	PowerPC little endian instructions, function epilogue
-
-# ARM prologue
-# STMFD SP!, {XX}
-0	beshort	0xE92D		ARMEB instructions, function prologue
-0	leshort	0xE92D		ARM instructions, function prologue{offset-adjust:-2}
-
-# ARM epilogue
-# LDMFD SP!, {XX}
-0	beshort	0xE8BD		ARMEB instructions, function epilogue
-0	leshort	0xE8BD		ARM instructions, function epilogue{offset-adjust:-2}
-
-# Ubicom32 prologue
-# move.4 -4($sp)++, $ra
-0	belong	0x02FF6125	Ubicom32 instructions, function prologue
-
-# Ubicom32 epilogues
-# calli $ra, 0($ra)
-# ret ($sp)4++
-0	belong	0xF0A000A0	Ubicom32 instructions, function epilogue
-0	belong	0x000022E1	Ubicom32 instructions, function epilogue
-
-# AVR8 prologue
-# push r28
-# push r29
-0	belong	0x93CF93DF	AVR8 instructions, function prologue
-0	belong	0x93DF93CF	AVR8 instructions, function prologue
-
-# AVR32 prologue
-# pushm   r7,lr
-# mov r7,sp
-0	string	\xEB\xCD\x40\x80\x1A\x97	AVR32 instructions, function prologue
-
-# SPARC eiplogue
-# ret
-# restore XX
-0	string	\x81\xC7\xE0\x08\x81\xE8	SPARC instructions, function epilogue
-
-# x86 epilogue
-# push ebp
-# move ebp, esp
-0	string	\x55\x89\xE5	Intel x86 instructions, function epilogue
-
diff --git a/src/binwalk/magics/bincast b/src/binwalk/magics/bincast
deleted file mode 100644
index af0a75a..0000000
--- a/src/binwalk/magics/bincast
+++ /dev/null
@@ -1,10 +0,0 @@
-0	belong x	Hex:                 0x%.8X
-#0	string x	String:              %s
-#0	lequad x	Little Endian Quad:  %lld
-#0	bequad x	Big Endian Quad:     %lld
-0	lelong x	Little Endian Long:  %d
-0	belong x	Big Endian Long:     %d
-0	leshort x	Little Endian Short: %d
-0	beshort x	Big Endian Short:    %d
-0	ledate x	Little Endian Date:  %s
-0	bedate x	Big Endian Date:     %s
diff --git a/src/binwalk/magics/binwalk b/src/binwalk/magics/binwalk
index 04fc859..67f0ae2 100644
--- a/src/binwalk/magics/binwalk
+++ b/src/binwalk/magics/binwalk
@@ -476,15 +476,19 @@
 >4      byte            x               \b%d
 
 # New LZMA format signature
-0	string		\xFFLZMA\x00	LZMA compressed data (new),
->6	byte&0x10	0		single-block stream
->6	byte&0x10	0x10		multi-block stream
-
 # See lzma file for LZMA signatures
-
+0	string		\xFFLZMA\x00	LZMA compressed data (new),
+>6	byte&0x10	0				single-block stream
+>6	byte&0x10	0x10			multi-block stream
 
 0	string	\xff\x06\x00\x00\x73\x4e\x61\x50\x70\x59	Snappy compression, stream identifier
 
+0   string	\x1f\x9d\x90	compress'd data, 16 bits
+
+#0	beshort		0x7801		Zlib header, no compression
+0	beshort		0x789c		Zlib header, default compression
+0	beshort		0x78da		Zlib header, best compression
+0	beshort		0x785e		Zlib header, compressed
 # Type: OpenSSL certificates/key files
 # From: Nicolas Collignon <tsointsoin@gmail.com>
 
diff --git a/src/binwalk/magics/compressd b/src/binwalk/magics/compressd
deleted file mode 100644
index 20fa45a..0000000
--- a/src/binwalk/magics/compressd
+++ /dev/null
@@ -1 +0,0 @@
-0       string          \x1f\x9d\x90          compress'd data, 16 bits
diff --git a/src/binwalk/magics/zlib b/src/binwalk/magics/zlib
deleted file mode 100644
index 166ba58..0000000
--- a/src/binwalk/magics/zlib
+++ /dev/null
@@ -1,4 +0,0 @@
-#0	beshort		0x7801		Zlib header, no compression
-0	beshort		0x789c		Zlib header, default compression
-0	beshort		0x78da		Zlib header, best compression
-0	beshort		0x785e		Zlib header, compressed
diff --git a/src/binwalk/module.py b/src/binwalk/module.py
index 07706ec..eb96009 100644
--- a/src/binwalk/module.py
+++ b/src/binwalk/module.py
@@ -5,6 +5,7 @@ import inspect
 import argparse
 import binwalk.common
 import binwalk.config
+import binwalk.plugin
 from binwalk.compat import *
 
 class ModuleOption(object):
@@ -72,6 +73,7 @@ class Result(object):
 		@file        - The file object of the scanned file.
 		@valid       - Set to True if the result if value, False if invalid.
 		@display     - Set to True to display the result to the user, False to hide it.
+		@extract     - Set to True to flag this result for extraction.
 
 		Provide additional kwargs as necessary.
 		Returns None.
@@ -81,6 +83,7 @@ class Result(object):
 		self.file = None
 		self.valid = True
 		self.display = True
+		self.extract = True
 
 		for (k, v) in iterator(kwargs):
 			setattr(self, k, v)
@@ -134,12 +137,11 @@ class Module(object):
 	RESULT = ['offset', 'description']
 
 	def __init__(self, dependency=False, **kwargs):
-		# TODO: Instantiate plugins object
-		# self.plugins = x
 		self.errors = []
 		self.results = []
 		self.status = None
 		self.name = self.__class__.__name__
+		self.plugins = binwalk.plugin.Plugins(self)
 
 		process_kwargs(self, kwargs)
 
@@ -154,6 +156,8 @@ class Module(object):
 			raise e
 		except Exception as e:
 			self.error(exception=e)
+	
+		self.plugins.load_plugins()
 
 	def load(self):
 		'''
@@ -193,15 +197,13 @@ class Module(object):
 		return None
 
 	def _plugins_pre_scan(self):
-		# plugins(self)
-		return None
+		self.plugins.pre_scan_callbacks(self)
 
 	def _plugins_post_scan(self):
-		# plugins(self)
-		return None
+		self.plugins.post_scan_callbacks(self)
 
-	def _plugins_callback(self, r):
-		return None
+	def _plugins_result(self, r):
+		self.plugins.scan_callbacks(r)
 
 	def _build_display_args(self, r):
 		args = []
@@ -230,7 +232,7 @@ class Module(object):
 			r = Result(**kwargs)
 
 		self.validate(r)
-		self._plugins_callback(r)
+		self._plugins_result(r)
 
 		if r.valid:
 			self.results.append(r)
diff --git a/src/binwalk/plugin.py b/src/binwalk/plugin.py
index f834978..f0b6510 100644
--- a/src/binwalk/plugin.py
+++ b/src/binwalk/plugin.py
@@ -34,15 +34,6 @@ class Plugins:
 		  This method is called after running a scan against a file, but before the file has been closed.
 		  It is passed the file object of the scanned file.
 
-	Valid return values for all plugin callbacks are (PLUGIN_* values may be OR'd together):
-
-		PLUGIN_CONTINUE     - Do nothing, continue the scan normally.
-		PLUGIN_NO_EXTRACT   - Do not preform data extraction.
-		PLUGIN_NO_DISPLAY   - Ignore the result(s); they will not be displayed or further processed.
-		PLUGIN_STOP_PLUGINS - Do not call any other plugins.
-		PLUGIN_TERMINATE    - Terminate the scan.
-		None                - The same as PLUGIN_CONTINUE.
-
 	Values returned by pre_scan affect all results during the scan of that particular file.
 	Values returned by callback affect only that specific scan result.
 	Values returned by post_scan are ignored since the scan of that file has already been completed.
@@ -50,50 +41,20 @@ class Plugins:
 	By default, all plugins are loaded during binwalk signature scans. Plugins that wish to be disabled by 
 	default may create a class variable named 'ENABLED' and set it to False. If ENABLED is set to False, the
 	plugin will only be loaded if it is explicitly named in the plugins whitelist.
-
-	Simple example plugin:
-
-		from binwalk.plugins import *
-
-		class Plugin:
-
-			# Set to False to have this plugin disabled by default.
-			ENABLED = True
-
-			def __init__(self):
-				self.binwalk = binwalk
-				print 'Scanning initialized!'
-
-			def __del__(self):
-				print 'Scanning complete!'
-
-			def pre_scan(self, fd):
-				print 'About to scan', fd.name
-				return PLUGIN_CONTINUE
-
-			def callback(self, results):
-				print 'Got a result:', results['description']
-				return PLUGIN_CONTINUE
-
-			def post_scan(self, fd):
-				print 'Done scanning', fd.name 
-				return PLUGIN_CONTINUE
 	'''
 
-	RESULT = 'result'
+	SCAN = 'scan'
 	PRESCAN = 'pre_scan'
 	POSTSCAN = 'post_scan'
 	PLUGIN = 'Plugin'
 	MODULE_EXTENSION = '.py'
 
-	def __init__(self, whitelist=[], blacklist=[]):
-		self.config = binwalk.config.Config()
-		self.result = []
+	def __init__(self, parent=None):
+		self.scan = []
 		self.pre_scan = []
-		self.pre_parser = []
 		self.post_scan = []
-		self.whitelist = whitelist
-		self.blacklist = blacklist
+		self.parent = parent
+		self.config = binwalk.config.Config()
 
 	def __del__(self):
 		pass
@@ -105,23 +66,14 @@ class Plugins:
 		pass
 
 	def _call_plugins(self, callback_list, arg):
-		retval = PLUGIN_CONTINUE
-
 		for callback in callback_list:
-			if (retval & PLUGIN_STOP_PLUGINS):
-				break
-
 			try:
-				val = callback(arg)
-				if val is not None:
-					retval |= val
+				callback(arg)
 			except KeyboardInterrupt as e:
 				raise e
 			except Exception as e:
 				sys.stderr.write("WARNING: %s.%s failed: %s\n" % (callback.__module__, callback.__name__, e))
 
-		return retval
-
 	def list_plugins(self):
 		'''
 		Obtain a list of all user and system plugin modules.
@@ -165,32 +117,22 @@ class Plugins:
 			for file_name in os.listdir(plugins[key]['path']):
 				if file_name.endswith(self.MODULE_EXTENSION):
 					module = file_name[:-len(self.MODULE_EXTENSION)]
-					if module in self.blacklist:
-						continue
-					else:
-						plugin = imp.load_source(module, os.path.join(plugins[key]['path'], file_name))
-						plugin_class = getattr(plugin, self.PLUGIN)
-
-						try:
-							enabled = plugin_class.ENABLED
-						except KeyboardInterrupt as e:
-							raise e
-						except Exception as e:
-							enabled = True
 						
-						plugins[key]['enabled'][module] = enabled
+					plugin = imp.load_source(module, os.path.join(plugins[key]['path'], file_name))
+					plugin_class = getattr(plugin, self.PLUGIN)
 
-						plugins[key]['modules'].append(module)
+					plugins[key]['enabled'][module] = True
+					plugins[key]['modules'].append(module)
 						
-						try:
-							plugins[key]['descriptions'][module] = plugin_class.__doc__.strip().split('\n')[0]
-						except KeyboardInterrupt as e:
-							raise e
-						except Exception as e:
-							plugins[key]['descriptions'][module] = 'No description'
+					try:
+						plugins[key]['descriptions'][module] = plugin_class.__doc__.strip().split('\n')[0]
+					except KeyboardInterrupt as e:
+						raise e
+					except Exception as e:
+						plugins[key]['descriptions'][module] = 'No description'
 		return plugins
 
-	def _load_plugins(self):
+	def load_plugins(self):
 		plugins = self.list_plugins()
 		self._load_plugin_modules(plugins['user'])
 		self._load_plugin_modules(plugins['system'])
@@ -203,19 +145,10 @@ class Plugins:
 				plugin = imp.load_source(module, file_path)
 				plugin_class = getattr(plugin, self.PLUGIN)
 
-				try:
-					# 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:
-						continue
-				except KeyboardInterrupt as e:
-					raise e
-				except Exception as e:
-					pass
-
-				class_instance = plugin_class()
+				class_instance = plugin_class(self.parent)
 
 				try:
-					self.result.append(getattr(class_instance, self.RESULT))
+					self.scan.append(getattr(class_instance, self.SCAN))
 				except KeyboardInterrupt as e:
 					raise e
 				except Exception as e:
@@ -240,12 +173,12 @@ class Plugins:
 			except Exception as e:
 				sys.stderr.write("WARNING: Failed to load plugin module '%s': %s\n" % (module, str(e)))
 
-	def _pre_scan_callbacks(self, obj):
+	def pre_scan_callbacks(self, obj):
 		return self._call_plugins(self.pre_scan, obj)
 
-	def _post_scan_callbacks(self, obj):
+	def post_scan_callbacks(self, obj):
 		return self._call_plugins(self.post_scan, obj)
 
-	def _result_callbacks(self, obj):
-		return self._call_plugins(self.result, obj)
+	def scan_callbacks(self, obj):
+		return self._call_plugins(self.scan, obj)
 
diff --git a/src/binwalk/plugins/armopcodes.py b/src/binwalk/plugins/armopcodes.py
deleted file mode 100644
index 5067bac..0000000
--- a/src/binwalk/plugins/armopcodes.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from binwalk.common import *
-from binwalk.plugins import *
-
-class Plugin:
-	'''
-	Validates ARM instructions during opcode scans.
-	'''
-
-	BITMASK = 0x83FF
-	BITMASK_SIZE = 2
-
-	def __init__(self, binwalk):
-		self.fd = None
-
-		if binwalk.scan_type == binwalk.BINARCH:
-			self.enabled = True
-		else:
-			self.enabled = False
-
-	def pre_scan(self, fd):
-		if self.enabled:
-			self.fd = BlockFile(fd.name, 'r')
-
-	def callback(self, results):
-		if self.fd:
-			data = ''
-			
-			try:
-				if results['description'].startswith('ARM instruction'):
-					self.fd.seek(results['offset'])
-					data = self.fd.read(self.BITMASK_SIZE)
-					data = data[1] + data[0]
-				elif results['description'].startswith('ARMEB instruction'):
-					self.fd.seek(results['offset']+self.BITMASK_SIZE)
-					data = self.fd.read(self.BITMASK_SIZE)
-
-				if data:
-					registers = int(data.encode('hex'), 16)
-					if (registers & self.BITMASK) != registers:
-						return PLUGIN_NO_DISPLAY
-			except:
-				pass
-			
-
-	def post_scan(self, fd):
-		try:
-			self.fd.close()
-		except:
-			pass
-			
diff --git a/src/binwalk/plugins/compressd.py b/src/binwalk/plugins/compressd.py
index 39aed58..335ec36 100644
--- a/src/binwalk/plugins/compressd.py
+++ b/src/binwalk/plugins/compressd.py
@@ -1,47 +1,31 @@
 import ctypes
 import ctypes.util
 from binwalk.common import *
-from binwalk.plugins import *
 
 class Plugin:
 	'''
 	Searches for and validates compress'd data.
 	'''
 
-	ENABLED = True
 	READ_SIZE = 64
 
-	def __init__(self, binwalk):
+	def __init__(self, module):
 		self.fd = None
 		self.comp = None
-		self.binwalk = binwalk
-		compressd_magic_file = binwalk.config.find_magic_file("compressd")
 
-		if binwalk.scan_type == binwalk.BINWALK:
+		if module.name == 'Signature':
 			self.comp = ctypes.cdll.LoadLibrary(ctypes.util.find_library("compress42"))
-			if self.comp:
-				binwalk.magic_files.append(compressd_magic_file)
-		elif compressd_magic_file in binwalk.magic_files:
-			binwalk.magic_files.pop(binwalk.magic_files.index(compressd_magic_file))
-
-	def __del__(self):
-		try:
-			self.fd.close()
-		except:
-			pass
-
-	def pre_scan(self, fd):
-		try:
-			if self.comp:
-				self.fd = BlockFile(fd.name, 'r')
-		except:
-			pass
-
-	def callback(self, results):
-		if self.fd and results['description'].lower().startswith("compress'd data"):
-			self.fd.seek(results['offset'])
-			compressed_data = self.fd.read(self.READ_SIZE)
+
+	def scan(self, result):
+		if self.comp:
+			if result.file and result.description.lower().startswith("compress'd data"):
+				fd = BlockFile(result.file.name, "r")
+				fd.seek(result.offset)
+
+				compressed_data = fd.read(self.READ_SIZE)
                         
-			if not self.comp.is_compressed(compressed_data, len(compressed_data)):
-				return (PLUGIN_NO_DISPLAY | PLUGIN_NO_EXTRACT)
+				if not self.comp.is_compressed(compressed_data, len(compressed_data)):
+					result.valid = False
+
+				fd.close()
 
diff --git a/src/binwalk/plugins/cpio.py b/src/binwalk/plugins/cpio.py
index 3aeed24..ec6c834 100644
--- a/src/binwalk/plugins/cpio.py
+++ b/src/binwalk/plugins/cpio.py
@@ -1,36 +1,32 @@
-from binwalk.plugins import *
+from binwalk.plugin import *
 
 class Plugin:
 	'''
 	Ensures that ASCII CPIO archive entries only get extracted once.	
 	'''
 
-	def __init__(self, binwalk):
-		self.binwalk = binwalk
+	def __init__(self, module):
 		self.found_archive = False
-
-	def pre_scan(self, fd):
+		self.enabled = (module.name == 'Signature')
+		
+	def pre_scan(self, module):
 		# Be sure to re-set this at the beginning of every scan
 		self.found_archive = False
 
-	def callback(self, results):
-		if self.binwalk.extractor.enabled and self.binwalk.scan_type == self.binwalk.BINWALK:
+	def scan(self, result):
+		if self.enabled and result.valid:
 			# ASCII CPIO archives consist of multiple entries, ending with an entry named 'TRAILER!!!'.
 			# Displaying each entry is useful, as it shows what files are contained in the archive,
 			# but we only want to extract the archive when the first entry is found.
-			if results['description'].startswith('ASCII cpio archive'):
+			if result.description.startswith('ASCII cpio archive'):
 				if not self.found_archive:
 					# This is the first entry. Set found_archive and allow the scan to continue normally.
 					self.found_archive = True
-					return PLUGIN_CONTINUE
+					result.extract = True
 				elif 'TRAILER!!!' in results['description']:
 					# This is the last entry, un-set found_archive.
 					self.found_archive = False
 	
 				# The first entry has already been found and this is the last entry, or the last entry 
 				# has not yet been found. Don't extract.
-				return PLUGIN_NO_EXTRACT
-
-		# Allow all other results to continue normally.
-		return PLUGIN_CONTINUE
-
+				result.extract = False
diff --git a/src/binwalk/plugins/deflate.py b/src/binwalk/plugins/deflate.py
deleted file mode 100644
index 44e4bb5..0000000
--- a/src/binwalk/plugins/deflate.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python
-
-import ctypes
-import ctypes.util
-from binwalk.plugins import *
-from binwalk.common import BlockFile
-
-class Plugin:
-	'''
-	Finds and extracts raw deflate compression streams.
-	'''
-
-	ENABLED = False
-	SIZE = 33*1024
-	# To prevent many false positives, only show data that decompressed to a reasonable size and didn't just result in a bunch of NULL bytes
-	MIN_DECOMP_SIZE = 32*1024
-	DESCRIPTION = "Deflate compressed data stream"
-
-	def __init__(self, binwalk):
-		self.binwalk = binwalk
-
-		# The tinfl library is built and installed with binwalk
-		self.tinfl = ctypes.cdll.LoadLibrary(ctypes.util.find_library("tinfl"))
-
-		if self.tinfl:
-			# Add an extraction rule
-			if self.binwalk.extractor.enabled:
-				self.binwalk.extractor.add_rule(regex='^%s' % self.DESCRIPTION.lower(), extension="deflate", cmd=self._extractor)
-
-	def pre_scan(self, fp):
-		if self.tinfl:
-			# Make sure we'll be getting enough data for a good decompression test
-			if fp.MAX_TRAILING_SIZE < self.SIZE:
-				fp.MAX_TRAILING_SIZE = self.SIZE
-
-			self._deflate_scan(fp)
-
-			return PLUGIN_TERMINATE
-
-	def _extractor(self, file_name):
-		if self.tinfl:
-			out_file = os.path.splitext(file_name)[0]
-			self.tinfl.inflate_raw_file(file_name, out_file)
-
-	def _deflate_scan(self, fp):
-		# Set these so that the progress report reflects the current scan status
-		self.binwalk.scan_length = fp.length
-		self.binwalk.total_scanned = 0
-
-		while self.binwalk.total_scanned < self.binwalk.scan_length:
-			current_total = self.binwalk.total_scanned
-
-			(data, dlen) = fp.read_block()
-			if not data or dlen == 0:
-				break
-
-			# dlen == block size, but data includes MAX_TRAILING_SIZE data as well
-			actual_dlen = len(data)
-
-			for i in range(0, dlen):
-				decomp_size = self.tinfl.is_deflated(data[i:], actual_dlen-i, 0)
-				if decomp_size >= self.MIN_DECOMP_SIZE:
-					loc = fp.offset + current_total + i
-					description = self.DESCRIPTION + ', uncompressed size >= %d' % decomp_size
-
-					# Extract the file
-					if self.binwalk.extractor.enabled:
-						self.binwalk.extractor.extract(loc, description, fp.name, (fp.size - loc))
-					
-					# Display results after extraction to be consistent with normal binwalk scans
-					self.binwalk.display.easy_results(loc, description)
-				
-				# Update total_scanned here for immediate progress feedback
-				self.binwalk.total_scanned = current_total + i
-
-				if (current_total + i) > self.binwalk.scan_length:
-					break
-
-			# Set total_scanned here in case no data streams were identified
-			self.binwalk.total_scanned = current_total + dlen
-
diff --git a/src/binwalk/plugins/lzmamod.py b/src/binwalk/plugins/lzmamod.py
index 24a9ecc..048e6ef 100644
--- a/src/binwalk/plugins/lzmamod.py
+++ b/src/binwalk/plugins/lzmamod.py
@@ -9,23 +9,21 @@ class Plugin:
 	Based on Bernardo Rodrigues' work: http://w00tsec.blogspot.com/2013/11/unpacking-firmware-images-from-cable.html
 	'''
 
-	ENABLED = True
-
 	FAKE_LZMA_SIZE = "\x00\x00\x00\x10\x00\x00\x00\x00"
 	SIGNATURE = "lzma compressed data"
 
-	def __init__(self, binwalk):
-		self.binwalk = binwalk
+	def __init__(self, module):
 		self.original_cmd = ''
+		self.enabled = (module.name == 'Signature')
 
-		if self.binwalk.extractor.enabled:
+		#if module.extractor.enabled:
 			# Replace the existing LZMA extraction command with our own
-			rules = self.binwalk.extractor.get_rules()
-			for i in range(0, len(rules)):
-				if rules[i]['regex'].match(self.SIGNATURE):
-					self.original_cmd = rules[i]['cmd']
-					rules[i]['cmd'] = self.lzma_cable_extractor
-					break
+		#	rules = self.binwalk.extractor.get_rules()
+		#	for i in range(0, len(rules)):
+		#		if rules[i]['regex'].match(self.SIGNATURE):
+		#			self.original_cmd = rules[i]['cmd']
+		#			rules[i]['cmd'] = self.lzma_cable_extractor
+		#			break
 
 	def lzma_cable_extractor(self, fname):
 		# Try extracting the LZMA file without modification first
@@ -55,10 +53,10 @@ class Plugin:
 			shutil.move(out_name, fname)
 			self.binwalk.extractor.execute(self.original_cmd, fname)
 
-	def pre_parser(self, result):
+	def scan(self, result):
 		# The modified cable modem LZMA headers all have valid dictionary sizes and a properties byte of 0x5D.
-		if result['description'].lower().startswith(self.SIGNATURE) and "invalid uncompressed size" in result['description']:
-			if "properties: 0x5D" in result['description'] and "invalid dictionary size" not in result['description']:
-				result['invalid'] = False
-				result['description'] = result['description'].split("invalid uncompressed size")[0] + "missing uncompressed size"
+		if result.description.lower().startswith(self.SIGNATURE) and "invalid uncompressed size" in result.description:
+			if "properties: 0x5D" in result.description and "invalid dictionary size" not in result.description:
+				result.valid = True
+				result.description = result.description.split("invalid uncompressed size")[0] + "missing uncompressed size"
 
diff --git a/src/binwalk/plugins/strcompat.py b/src/binwalk/plugins/strcompat.py
deleted file mode 100644
index fb165b6..0000000
--- a/src/binwalk/plugins/strcompat.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from binwalk.compat import *
-
-class Plugin:
-	'''
-	Modifies string analysis output to mimic that of the Unix strings utility.
-	'''
-
-	ENABLED = False
-
-	def __init__(self, binwalk):
-		self.modify_output = False
-
-		if binwalk.scan_type == binwalk.STRINGS:
-			binwalk.display.quiet = True
-			self.modify_output = True
-
-	def callback(self, results):
-		if self.modify_output:
-			try:
-				print(results['description'])
-			except Exception as e:
-				pass
diff --git a/src/binwalk/plugins/zlib.py b/src/binwalk/plugins/zlib.py
index bcddb36..156a97d 100644
--- a/src/binwalk/plugins/zlib.py
+++ b/src/binwalk/plugins/zlib.py
@@ -1,6 +1,5 @@
 import ctypes
 import ctypes.util
-from binwalk.plugins import *
 from binwalk.common import BlockFile
 
 class Plugin:
@@ -11,44 +10,27 @@ class Plugin:
 	MIN_DECOMP_SIZE = 16*1024
 	MAX_DATA_SIZE = 33 * 1024
 
-	def __init__(self, binwalk):
-		self.fd = None
+	def __init__(self, module):
 		self.tinfl = None
-		zlib_magic_file = binwalk.config.find_magic_file('zlib')
 
-		# Only initialize this plugin if this is a normal binwalk signature scan
-		if binwalk.scan_type == binwalk.BINWALK:
+		# Only initialize this plugin if this is a signature scan
+		if module.name == 'Signature':
 			# Load libtinfl.so
 			self.tinfl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('tinfl'))
-			if self.tinfl:
-				# Add the zlib file to the list of magic files
-				binwalk.magic_files.append(zlib_magic_file)
-		# Else, be sure to unload the zlib file from the list of magic signatures
-		elif zlib_magic_file in binwalk.magic_files:
-			binwalk.magic_files.pop(binwalk.magic_files.index(zlib_magic_file))
-
-	def pre_scan(self, fd):
-		if self.tinfl:
-			self.fd = BlockFile(fd.name, 'r')
-
-	def callback(self, result):
 
+	def scan(self, result):
 		# If this result is a zlib signature match, try to decompress the data
-		if self.fd and result['description'].lower().startswith('zlib'):
+		if self.tinfl and result.file and result.description.lower().startswith('zlib'):
 			# Seek to and read the suspected zlib data
-			self.fd.seek(result['offset'])
-			data = self.fd.read(self.MAX_DATA_SIZE)
-			
+			fd = BlockFile(result.file.name, "r")
+			fd.seek(result.offset)
+			data = fd.read(self.MAX_DATA_SIZE)
+			fd.close()
+
 			# Check if this is valid zlib data
 			decomp_size = self.tinfl.is_deflated(data, len(data), 1)
 			if decomp_size > 0:
-				result['description'] += ", uncompressed size >= %d" % decomp_size
+				result.description += ", uncompressed size >= %d" % decomp_size
 			else:
-				return (PLUGIN_NO_DISPLAY | PLUGIN_NO_EXTRACT)
-		
-		return PLUGIN_CONTINUE
-
-	def post_scan(self, fd):
-		if self.fd:
-			self.fd.close()
+				result.valid = False
 
diff --git a/src/magic/compressed b/src/magic/compressed
index aa4e88b..c142789 100644
--- a/src/magic/compressed
+++ b/src/magic/compressed
@@ -160,12 +160,16 @@
 >4      byte            x               \b%d
 
 # New LZMA format signature
-0	string		\xFFLZMA\x00	LZMA compressed data (new),
->6	byte&0x10	0		single-block stream
->6	byte&0x10	0x10		multi-block stream
-
 # See lzma file for LZMA signatures
-
+0	string		\xFFLZMA\x00	LZMA compressed data (new),
+>6	byte&0x10	0				single-block stream
+>6	byte&0x10	0x10			multi-block stream
 
 0	string	\xff\x06\x00\x00\x73\x4e\x61\x50\x70\x59	Snappy compression, stream identifier
 
+0   string	\x1f\x9d\x90	compress'd data, 16 bits
+
+#0	beshort		0x7801		Zlib header, no compression
+0	beshort		0x789c		Zlib header, default compression
+0	beshort		0x78da		Zlib header, best compression
+0	beshort		0x785e		Zlib header, compressed
diff --git a/src/setup.py b/src/setup.py
index 3f910df..49f53e0 100755
--- a/src/setup.py
+++ b/src/setup.py
@@ -97,7 +97,7 @@ os.chdir(working_directory)
 print("generating binwalk magic file")
 magic_files = listdir("magic")
 magic_files.sort()
-fd = open("binwalk/magic/binwalk", "wb")
+fd = open("binwalk/magics/binwalk", "wb")
 for magic in magic_files:
 	fpath = path.join("magic", magic)
 	if path.isfile(fpath):
@@ -105,7 +105,7 @@ for magic in magic_files:
 fd.close()
 
 # The data files to install along with the binwalk module
-install_data_files = ["magic/*", "config/*", "plugins/*", "modules/*"]
+install_data_files = ["magics/*", "configs/*", "plugins/*", "modules/*"]
 
 # Install the binwalk module, script and support files
 setup(	name = "binwalk",
--
libgit2 0.26.0