From 6640814566521f8ef8039fb8aefb064af042b2ac Mon Sep 17 00:00:00 2001
From: devttys0 <heffnercj@gmail.com>
Date: Sun, 22 Dec 2013 20:47:46 -0500
Subject: [PATCH] Added ctypes wrapper and custom libmagic module.

---
 src/binwalk/core/C.py            | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/binwalk/core/magic.py        | 35 +++++++++++++++++++++++++++++++++++
 src/binwalk/modules/signature.py | 15 ++++-----------
 3 files changed, 117 insertions(+), 11 deletions(-)
 create mode 100644 src/binwalk/core/C.py
 create mode 100644 src/binwalk/core/magic.py

diff --git a/src/binwalk/core/C.py b/src/binwalk/core/C.py
new file mode 100644
index 0000000..6c67a1b
--- /dev/null
+++ b/src/binwalk/core/C.py
@@ -0,0 +1,78 @@
+import os
+import sys
+import glob
+import ctypes
+import ctypes.util
+from binwalk.core.compat import *
+
+class Function(object):
+
+	PY2CTYPES = {
+			bytes	: ctypes.c_char_p,
+			str		: ctypes.c_char_p,
+			int		: ctypes.c_int,
+			float	: ctypes.c_float,
+			None	: ctypes.c_int,
+	}
+
+	RETVAL_CONVERTERS = {
+			int 	: int,
+			float	: float,
+			str 	: bytes2str,
+			bytes	: str2bytes,
+	}
+		
+	def __init__(self, library, name, retype):
+		self.function = getattr(library, name)
+		self.retype = retype
+
+		if has_key(self.PY2CTYPES, self.retype):
+			self.function.restype = self.PY2CTYPES[self.retype]
+			self.retval_converter = self.RETVAL_CONVERTERS[self.retype]
+		else:
+			raise Exception("Unknown return type: '%s'" % retype)
+
+	def run(self, *args):
+		args = list(args)
+
+		for i in range(0, len(args)):
+			if isinstance(args[i], str):
+				args[i] = str2bytes(args[i])
+
+		return self.retval_converter(self.function(*args))
+		
+class Library(object):
+
+	def __init__(self, library, functions):
+		self.library = ctypes.cdll.LoadLibrary(self.find_library(library))
+		if not self.library:
+			raise Exception("Failed to load library '%s'" % library)
+				
+		for (function, restype) in iterator(functions):
+			f = Function(self.library, function, restype)
+			setattr(self, function, f.run)
+
+	def find_library(self, library):
+		lib_path = None
+		system_paths = {
+			'linux'  : ['/usr/local/lib/lib%s.so' % library],
+			'darwin' : ['/opt/local/lib/lib%s.dylib' % library,
+						'/usr/local/lib/lib%s.dylib' % library,
+					   ] + glob.glob('/usr/local/Cellar/lib%s/*/lib/lib%s.dylib' % (library, library)),
+
+			'win32'  : ['%s.dll' % library]
+		}
+
+		lib_path = ctypes.util.find_library(library)
+
+		if not lib_path:
+			for path in system_paths[sys.platform]:
+				if os.path.exists(path):
+					lib_path = path
+					break
+
+		if not lib_path:
+			raise Exception("Failed to locate library '%s'" % library)
+
+		return lib_path
+
diff --git a/src/binwalk/core/magic.py b/src/binwalk/core/magic.py
new file mode 100644
index 0000000..4bf6738
--- /dev/null
+++ b/src/binwalk/core/magic.py
@@ -0,0 +1,35 @@
+import ctypes
+import ctypes.util
+import binwalk.core.C
+from binwalk.core.compat import *
+
+class Magic(object):
+
+	LIBMAGIC_FUNCTIONS = {
+			"magic_open"	: int,
+			"magic_load"	: int,
+			"magic_buffer"	: str,
+	}
+
+	MAGIC_NO_CHECK_TEXT 	= 0x020000
+	MAGIC_NO_CHECK_APPTYPE 	= 0x008000
+	MAGIC_NO_CHECK_TOKENS 	= 0x100000
+	MAGIC_NO_CHECK_ENCODING = 0x200000
+
+	MAGIC_FLAGS = MAGIC_NO_CHECK_TEXT | MAGIC_NO_CHECK_ENCODING | MAGIC_NO_CHECK_APPTYPE | MAGIC_NO_CHECK_TOKENS
+
+	def __init__(self, magic_file=None):
+		if magic_file:
+			self.magic_file = str2bytes(magic_file)
+
+		self.libmagic = binwalk.core.C.Library('magic', self.LIBMAGIC_FUNCTIONS)
+
+		self.magic_cookie = self.libmagic.magic_open(self.MAGIC_FLAGS)
+		self.libmagic.magic_load(self.magic_cookie, self.magic_file)
+
+	def buffer(self, data):
+		return self.libmagic.magic_buffer(self.magic_cookie, str2bytes(data), len(data))
+
+if __name__ == "__main__":
+	magic = Magic()
+	print (magic.buffer("This is my voice on TV."))
diff --git a/src/binwalk/modules/signature.py b/src/binwalk/modules/signature.py
index f9e9529..cacfc98 100644
--- a/src/binwalk/modules/signature.py
+++ b/src/binwalk/modules/signature.py
@@ -1,7 +1,6 @@
-import magic
-import binwalk.core.parser
+import binwalk.core.magic
 import binwalk.core.smart
-from binwalk.core.compat import *
+import binwalk.core.parser
 from binwalk.core.module import Module, Option, Kwarg
 
 class Signature(Module):
@@ -43,8 +42,6 @@ class Signature(Module):
 			Kwarg(name='magic_files', default=[]),
 	]
 
-	MAGIC_FLAGS = magic.MAGIC_NO_CHECK_TEXT | magic.MAGIC_NO_CHECK_ENCODING | magic.MAGIC_NO_CHECK_APPTYPE | magic.MAGIC_NO_CHECK_TOKENS
-
 	VERBOSE_FORMAT = "%s    %d"
 
 	def init(self):
@@ -72,8 +69,7 @@ class Signature(Module):
 
 		# Parse the magic file(s) and initialize libmagic
 		self.mfile = self.parser.parse(self.magic_files)
-		self.magic = magic.open(self.MAGIC_FLAGS)
-		self.magic.load(str2bytes(self.mfile))
+		self.magic = binwalk.core.magic.Magic(self.mfile)
 		
 		# Once the temporary magic files are loaded into libmagic, we don't need them anymore; delete the temp files
 		self.parser.rm_magic_files()
@@ -114,11 +110,8 @@ class Signature(Module):
 				if candidate_offset < current_block_offset:
 					continue
 
-				# In python3 we need a bytes object to pass to magic.buffer
-				candidate_data = str2bytes(data[candidate_offset:candidate_offset+fp.block_peek_size])
-			
 				# Pass the data to libmagic for parsing
-				magic_result = self.magic.buffer(candidate_data)
+				magic_result = self.magic.buffer(data[candidate_offset:candidate_offset+fp.block_peek_size])
 				if not magic_result:
 					continue
 				
--
libgit2 0.26.0