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