Commit 84e83d0f by devttys0

Added --cast option

parent 5c4291ec
...@@ -2,32 +2,35 @@ import binwalk.core.C ...@@ -2,32 +2,35 @@ import binwalk.core.C
from binwalk.core.compat import * from binwalk.core.compat import *
class Magic(object): class Magic(object):
''' '''
Minimalist Python wrapper around libmagic. Minimalist Python wrapper around libmagic.
''' '''
LIBMAGIC_FUNCTIONS = [ LIBMAGIC_FUNCTIONS = [
binwalk.core.C.Function(name="magic_open", type=int), binwalk.core.C.Function(name="magic_open", type=int),
binwalk.core.C.Function(name="magic_load", type=int), binwalk.core.C.Function(name="magic_load", type=int),
binwalk.core.C.Function(name="magic_buffer", type=str), binwalk.core.C.Function(name="magic_buffer", type=str),
] ]
MAGIC_NO_CHECK_TEXT = 0x020000 MAGIC_CONTINUE = 0x000020
MAGIC_NO_CHECK_APPTYPE = 0x008000 MAGIC_NO_CHECK_TEXT = 0x020000
MAGIC_NO_CHECK_TOKENS = 0x100000 MAGIC_NO_CHECK_APPTYPE = 0x008000
MAGIC_NO_CHECK_ENCODING = 0x200000 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
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: def __init__(self, magic_file=None, flags=0):
self.magic_file = str2bytes(magic_file) if magic_file:
self.magic_file = str2bytes(magic_file)
self.libmagic = binwalk.core.C.Library("magic", self.LIBMAGIC_FUNCTIONS) else:
self.magic_file = None
self.magic_cookie = self.libmagic.magic_open(self.MAGIC_FLAGS)
self.libmagic.magic_load(self.magic_cookie, self.magic_file) self.libmagic = binwalk.core.C.Library("magic", self.LIBMAGIC_FUNCTIONS)
def buffer(self, data): self.magic_cookie = self.libmagic.magic_open(self.MAGIC_FLAGS | flags)
return self.libmagic.magic_buffer(self.magic_cookie, str2bytes(data), len(data)) 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))
...@@ -3,159 +3,162 @@ import binwalk.core.common as common ...@@ -3,159 +3,162 @@ import binwalk.core.common as common
from binwalk.core.compat import * from binwalk.core.compat import *
class Settings: class Settings:
''' '''
Binwalk settings class, used for accessing user and system file paths and general configuration settings. Binwalk settings class, used for accessing user and system file paths and general configuration settings.
After instatiating the class, file paths can be accessed via the self.paths dictionary. After instatiating the class, file paths can be accessed via the self.paths dictionary.
System file paths are listed under the 'system' key, user file paths under the 'user' key. System file paths are listed under the 'system' key, user file paths under the 'user' key.
Valid file names under both the 'user' and 'system' keys are as follows: Valid file names under both the 'user' and 'system' keys are as follows:
o BINWALK_MAGIC_FILE - Path to the default binwalk magic file. o BINWALK_MAGIC_FILE - Path to the default binwalk magic file.
o PLUGINS - Path to the plugins directory. o PLUGINS - Path to the plugins directory.
''' '''
# Release version # Release version
VERSION = "2.0.0 alpha" VERSION = "2.0.0 alpha"
# Sub directories # Sub directories
BINWALK_USER_DIR = ".binwalk" BINWALK_USER_DIR = ".binwalk"
BINWALK_MAGIC_DIR = "magic" BINWALK_MAGIC_DIR = "magic"
BINWALK_CONFIG_DIR = "config" BINWALK_CONFIG_DIR = "config"
BINWALK_PLUGINS_DIR = "plugins" BINWALK_PLUGINS_DIR = "plugins"
# File names # File names
PLUGINS = "plugins" PLUGINS = "plugins"
EXTRACT_FILE = "extract.conf" EXTRACT_FILE = "extract.conf"
BINWALK_MAGIC_FILE = "binwalk" BINWALK_MAGIC_FILE = "binwalk"
BINARCH_MAGIC_FILE = "binarch" BINARCH_MAGIC_FILE = "binarch"
BINCAST_MAGIC_FILE = "bincast"
def __init__(self):
''' def __init__(self):
Class constructor. Enumerates file paths and populates self.paths. '''
''' Class constructor. Enumerates file paths and populates self.paths.
# Path to the user binwalk directory '''
self.user_dir = self._get_user_dir() # Path to the user binwalk directory
# Path to the system wide binwalk directory self.user_dir = self._get_user_dir()
self.system_dir = self._get_system_dir() # Path to the system wide binwalk directory
self.system_dir = self._get_system_dir()
# Dictionary of all absolute user/system file paths
self.paths = { # Dictionary of all absolute user/system file paths
'user' : {}, self.paths = {
'system' : {}, 'user' : {},
} 'system' : {},
}
# Build the paths to all user-specific files
self.paths['user'][self.BINWALK_MAGIC_FILE] = self._user_path(self.BINWALK_MAGIC_DIR, self.BINWALK_MAGIC_FILE) # Build the paths to all user-specific files
self.paths['user'][self.BINARCH_MAGIC_FILE] = self._user_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE) self.paths['user'][self.BINWALK_MAGIC_FILE] = self._user_path(self.BINWALK_MAGIC_DIR, self.BINWALK_MAGIC_FILE)
self.paths['user'][self.EXTRACT_FILE] = self._user_path(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE) self.paths['user'][self.BINARCH_MAGIC_FILE] = self._user_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE)
self.paths['user'][self.PLUGINS] = self._user_path(self.BINWALK_PLUGINS_DIR) self.paths['user'][self.BINCAST_MAGIC_FILE] = self._user_path(self.BINWALK_MAGIC_DIR, self.BINCAST_MAGIC_FILE)
self.paths['user'][self.EXTRACT_FILE] = self._user_path(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE)
# Build the paths to all system-wide files self.paths['user'][self.PLUGINS] = self._user_path(self.BINWALK_PLUGINS_DIR)
self.paths['system'][self.BINWALK_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINWALK_MAGIC_FILE)
self.paths['system'][self.BINARCH_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE) # Build the paths to all system-wide files
self.paths['system'][self.EXTRACT_FILE] = self._system_path(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE) self.paths['system'][self.BINWALK_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINWALK_MAGIC_FILE)
self.paths['system'][self.PLUGINS] = self._system_path(self.BINWALK_PLUGINS_DIR) self.paths['system'][self.BINARCH_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE)
self.paths['system'][self.BINCAST_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINCAST_MAGIC_FILE)
def find_magic_file(self, fname, system_only=False, user_only=False): self.paths['system'][self.EXTRACT_FILE] = self._system_path(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE)
''' self.paths['system'][self.PLUGINS] = self._system_path(self.BINWALK_PLUGINS_DIR)
Finds the specified magic file name in the system / user magic file directories.
def find_magic_file(self, fname, system_only=False, user_only=False):
@fname - The name of the magic file. '''
@system_only - If True, only the system magic file directory will be searched. Finds the specified magic file name in the system / user magic file directories.
@user_only - If True, only the user magic file directory will be searched.
@fname - The name of the magic file.
If system_only and user_only are not set, the user directory is always searched first. @system_only - If True, only the system magic file directory will be searched.
@user_only - If True, only the user magic file directory will be searched.
Returns the path to the file on success; returns None on failure.
''' If system_only and user_only are not set, the user directory is always searched first.
loc = None
Returns the path to the file on success; returns None on failure.
if not system_only: '''
fpath = self._user_path(self.BINWALK_MAGIC_DIR, fname) loc = None
if os.path.exists(fpath) and common.file_size(fpath) > 0:
loc = fpath if not system_only:
fpath = self._user_path(self.BINWALK_MAGIC_DIR, fname)
if loc is None and not user_only: if os.path.exists(fpath) and common.file_size(fpath) > 0:
fpath = self._system_path(self.BINWALK_MAGIC_DIR, fname) loc = fpath
if os.path.exists(fpath) and common.file_size(fpath) > 0:
loc = fpath if loc is None and not user_only:
fpath = self._system_path(self.BINWALK_MAGIC_DIR, fname)
return fpath if os.path.exists(fpath) and common.file_size(fpath) > 0:
loc = fpath
def _get_system_dir(self):
''' return fpath
Find the directory where the binwalk module is installed on the system.
''' def _get_system_dir(self):
try: '''
root = __file__ Find the directory where the binwalk module is installed on the system.
if os.path.islink(root): '''
root = os.path.realpath(root) try:
return os.path.dirname(os.path.dirname(os.path.abspath(root))) root = __file__
except KeyboardInterrupt as e: if os.path.islink(root):
raise e root = os.path.realpath(root)
except Exception: return os.path.dirname(os.path.dirname(os.path.abspath(root)))
return '' except KeyboardInterrupt as e:
raise e
def _get_user_dir(self): except Exception:
''' return ''
Get the user's home directory.
''' def _get_user_dir(self):
try: '''
# This should work in both Windows and Unix environments Get the user's home directory.
return os.getenv('USERPROFILE') or os.getenv('HOME') '''
except KeyboardInterrupt as e: try:
raise e # This should work in both Windows and Unix environments
except Exception: return os.getenv('USERPROFILE') or os.getenv('HOME')
return '' except KeyboardInterrupt as e:
raise e
def _file_path(self, dirname, filename): except Exception:
''' return ''
Builds an absolute path and creates the directory and file if they don't already exist.
def _file_path(self, dirname, filename):
@dirname - Directory path. '''
@filename - File name. Builds an absolute path and creates the directory and file if they don't already exist.
Returns a full path of 'dirname/filename'. @dirname - Directory path.
''' @filename - File name.
if not os.path.exists(dirname):
try: Returns a full path of 'dirname/filename'.
os.makedirs(dirname) '''
except KeyboardInterrupt as e: if not os.path.exists(dirname):
raise e try:
except Exception: os.makedirs(dirname)
pass except KeyboardInterrupt as e:
raise e
fpath = os.path.join(dirname, filename) except Exception:
pass
if not os.path.exists(fpath):
try: fpath = os.path.join(dirname, filename)
open(fpath, "w").close()
except KeyboardInterrupt as e: if not os.path.exists(fpath):
raise e try:
except Exception: open(fpath, "w").close()
pass except KeyboardInterrupt as e:
raise e
return fpath except Exception:
pass
def _user_path(self, subdir, basename=''):
''' return fpath
Gets the full path to the 'subdir/basename' file in the user binwalk directory.
def _user_path(self, subdir, basename=''):
@subdir - Subdirectory inside the user binwalk directory. '''
@basename - File name inside the subdirectory. Gets the full path to the 'subdir/basename' file in the user binwalk directory.
Returns the full path to the 'subdir/basename' file. @subdir - Subdirectory inside the user binwalk directory.
''' @basename - File name inside the subdirectory.
return self._file_path(os.path.join(self.user_dir, self.BINWALK_USER_DIR, subdir), basename)
Returns the full path to the 'subdir/basename' file.
def _system_path(self, subdir, basename=''): '''
''' return self._file_path(os.path.join(self.user_dir, self.BINWALK_USER_DIR, subdir), basename)
Gets the full path to the 'subdir/basename' file in the system binwalk directory.
def _system_path(self, subdir, basename=''):
@subdir - Subdirectory inside the system binwalk directory. '''
@basename - File name inside the subdirectory. Gets the full path to the 'subdir/basename' file in the system binwalk directory.
Returns the full path to the 'subdir/basename' file. @subdir - Subdirectory inside the system binwalk directory.
''' @basename - File name inside the subdirectory.
return self._file_path(os.path.join(self.system_dir, subdir), basename)
Returns the full path to the 'subdir/basename' file.
'''
return self._file_path(os.path.join(self.system_dir, subdir), basename)
...@@ -5,143 +5,158 @@ from binwalk.core.module import Module, Option, Kwarg ...@@ -5,143 +5,158 @@ from binwalk.core.module import Module, Option, Kwarg
class Signature(Module): class Signature(Module):
TITLE = "Signature Scan" TITLE = "Signature Scan"
ORDER = 10 ORDER = 10
CLI = [ CLI = [
Option(short='B', Option(short='B',
long='signature', long='signature',
kwargs={'enabled' : True}, kwargs={'enabled' : True},
description='Scan target file(s) for file signatures'), description='Scan target file(s) for file signatures'),
Option(short='R', Option(short='R',
long='raw-bytes', long='raw-bytes',
kwargs={'raw_bytes' : None}, kwargs={'raw_bytes' : None},
type=str, type=str,
description='Scan target file(s) for the specified sequence of bytes'), description='Scan target file(s) for the specified sequence of bytes'),
Option(short='A', Option(short='A',
long='opcodes', long='opcodes',
kwargs={'enabled' : True, 'search_for_opcodes' : True}, kwargs={'enabled' : True, 'search_for_opcodes' : True},
description='Scan target file(s) for common executable opcodes'), description='Scan target file(s) for common executable opcodes'),
Option(short='m', Option(short='C',
long='magic', long='cast',
kwargs={'magic_files' : []}, kwargs={'enabled' : True, 'cast_data_types' : True},
type=list, description='Cast offsets as various data types'),
dtype='file', Option(short='m',
description='Specify a custom magic file to use'), long='magic',
Option(short='b', kwargs={'magic_files' : []},
long='dumb', type=list,
kwargs={'dumb_scan' : True}, dtype='file',
description='Disable smart signature keywords'), description='Specify a custom magic file to use'),
] Option(short='b',
long='dumb',
KWARGS = [ kwargs={'dumb_scan' : True},
Kwarg(name='enabled', default=False), description='Disable smart signature keywords'),
Kwarg(name='raw_bytes', default=None), ]
Kwarg(name='search_for_opcodes', default=False),
Kwarg(name='dumb_scan', default=False), KWARGS = [
Kwarg(name='magic_files', default=[]), Kwarg(name='enabled', default=False),
] Kwarg(name='raw_bytes', default=None),
Kwarg(name='search_for_opcodes', default=False),
VERBOSE_FORMAT = "%s %d" Kwarg(name='cast_data_types', default=False),
Kwarg(name='dumb_scan', default=False),
def init(self): Kwarg(name='magic_files', default=[]),
# Create Signature and MagicParser class instances. These are mostly for internal use. ]
self.smart = binwalk.core.smart.Signature(self.config.filter, ignore_smart_signatures=self.dumb_scan)
self.parser = binwalk.core.parser.MagicParser(self.config.filter, self.smart) VERBOSE_FORMAT = "%s %d"
# If a raw byte sequence was specified, build a magic file from that instead of using the default magic files def init(self):
if self.raw_bytes is not None: flags = 0
self.magic_files = [self.parser.file_from_string(self.raw_bytes)]
# Create Signature and MagicParser class instances. These are mostly for internal use.
# Use the system default magic file if no other was specified self.smart = binwalk.core.smart.Signature(self.config.filter, ignore_smart_signatures=self.dumb_scan)
if not self.magic_files: self.parser = binwalk.core.parser.MagicParser(self.config.filter, self.smart)
if self.search_for_opcodes:
self.magic_files = [ # If a raw byte sequence was specified, build a magic file from that instead of using the default magic files
self.config.settings.paths['user'][self.config.settings.BINARCH_MAGIC_FILE], if self.raw_bytes is not None:
self.config.settings.paths['system'][self.config.settings.BINARCH_MAGIC_FILE], self.magic_files = [self.parser.file_from_string(self.raw_bytes)]
]
else: # Use the system default magic file if no other was specified
# Append the user's magic file first so that those signatures take precedence # Append the user's magic file first so that those signatures take precedence
self.magic_files = [ if not self.magic_files:
self.config.settings.paths['user'][self.config.settings.BINWALK_MAGIC_FILE], if self.search_for_opcodes:
self.config.settings.paths['system'][self.config.settings.BINWALK_MAGIC_FILE], flags |= binwalk.core.magic.Magic.MAGIC_CONTINUE
]
self.magic_files = [
# Parse the magic file(s) and initialize libmagic self.config.settings.paths['user'][self.config.settings.BINARCH_MAGIC_FILE],
self.mfile = self.parser.parse(self.magic_files) self.config.settings.paths['system'][self.config.settings.BINARCH_MAGIC_FILE],
self.magic = binwalk.core.magic.Magic(self.mfile) ]
elif self.cast_data_types:
# Once the temporary magic files are loaded into libmagic, we don't need them anymore; delete the temp files self.magic_files = [
self.parser.rm_magic_files() self.config.settings.paths['user'][self.config.settings.BINCAST_MAGIC_FILE],
self.config.settings.paths['system'][self.config.settings.BINCAST_MAGIC_FILE],
self.VERBOSE = ["Signatures:", self.parser.signature_count] ]
else:
def validate(self, r): self.magic_files = [
''' self.config.settings.paths['user'][self.config.settings.BINWALK_MAGIC_FILE],
Called automatically by self.result. self.config.settings.paths['system'][self.config.settings.BINWALK_MAGIC_FILE],
''' ]
if not r.description:
r.valid = False # Parse the magic file(s) and initialize libmagic
self.mfile = self.parser.parse(self.magic_files)
if r.size and (r.size + r.offset) > r.file.size: self.magic = binwalk.core.magic.Magic(self.mfile, flags)
r.valid = False
# Once the temporary magic files are loaded into libmagic, we don't need them anymore; delete the temp files
if r.jump and (r.jump + r.offset) > r.file.size: self.parser.rm_magic_files()
r.valid = False
self.VERBOSE = ["Signatures:", self.parser.signature_count]
def scan_file(self, fp):
current_file_offset = 0 def validate(self, r):
'''
while True: Called automatically by self.result.
(data, dlen) = fp.read_block() '''
if not data: if not r.description:
break r.valid = False
current_block_offset = 0 if r.size and (r.size + r.offset) > r.file.size:
block_start = fp.tell() - dlen r.valid = False
self.status.completed = block_start - fp.offset
if r.jump and (r.jump + r.offset) > r.file.size:
for candidate_offset in self.parser.find_signature_candidates(data, dlen): r.valid = False
# current_block_offset is set when a jump-to-offset keyword is encountered while def scan_file(self, fp):
# processing signatures. This points to an offset inside the current data block current_file_offset = 0
# that scanning should jump to, so ignore any subsequent candidate signatures that
# occurr before this offset inside the current data block. while True:
if candidate_offset < current_block_offset: (data, dlen) = fp.read_block()
continue if not data:
break
# Pass the data to libmagic for parsing
magic_result = self.magic.buffer(data[candidate_offset:candidate_offset+fp.block_peek_size]) current_block_offset = 0
if not magic_result: block_start = fp.tell() - dlen
continue self.status.completed = block_start - fp.offset
# The smart filter parser returns a binwalk.core.module.Result object for candidate_offset in self.parser.find_signature_candidates(data, dlen):
r = self.smart.parse(magic_result)
# current_block_offset is set when a jump-to-offset keyword is encountered while
if self.config.filter.valid_result(r.description): # processing signatures. This points to an offset inside the current data block
# that scanning should jump to, so ignore any subsequent candidate signatures that
# Set the absolute offset inside the target file # occurr before this offset inside the current data block.
r.offset = block_start + candidate_offset + r.adjust if candidate_offset < current_block_offset:
continue
# Provide an instance of the current file object
r.file = fp # Pass the data to libmagic for parsing
magic_result = self.magic.buffer(data[candidate_offset:candidate_offset+fp.block_peek_size])
# Register the result for futher processing/display if not magic_result:
self.result(r=r) continue
# Is this a valid result and did it specify a jump-to-offset keyword? # The smart filter parser returns a binwalk.core.module.Result object
if r.valid and r.jump > 0: r = self.smart.parse(magic_result)
absolute_jump_offset = r.offset + r.jump
current_block_offset = candidate_offset + r.jump if self.config.filter.valid_result(r.description):
# If the jump-to-offset is beyond the confines of the current block, seek the file to # Set the absolute offset inside the target file
# that offset and quit processing this block of data. r.offset = block_start + candidate_offset + r.adjust
if absolute_jump_offset >= fp.tell():
fp.seek(r.offset + r.jump) # Provide an instance of the current file object
break r.file = fp
def run(self): # Register the result for futher processing/display
for fp in iter(self.next_file, None): self.result(r=r)
self.header()
self.scan_file(fp) # Is this a valid result and did it specify a jump-to-offset keyword?
self.footer() if r.valid and r.jump > 0:
absolute_jump_offset = r.offset + r.jump
current_block_offset = candidate_offset + r.jump
# If the jump-to-offset is beyond the confines of the current block, seek the file to
# that offset and quit processing this block of data.
if absolute_jump_offset >= fp.tell():
fp.seek(r.offset + r.jump)
break
def run(self):
for fp in iter(self.next_file, None):
self.header()
self.scan_file(fp)
self.footer()
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