Commit 4c136d1a authored by Devon Kearns's avatar Devon Kearns

Merge tag 'upstream/1.2.1'

Upstream version 1.2.1
parents d6acf069 e2e4d59b
This diff is collapsed.
This diff is collapsed.
...@@ -66,3 +66,26 @@ def get_quoted_strings(string): ...@@ -66,3 +66,26 @@ def get_quoted_strings(string):
return re.findall(r'\"(.*)\"', string)[0] return re.findall(r'\"(.*)\"', string)[0]
except: except:
return '' return ''
def unique_file_name(base_name, extension=''):
'''
Creates a unique file name based on the specified base name.
@base_name - The base name to use for the unique file name.
@extension - The file extension to use for the unique file name.
Returns a unique file string.
'''
idcount = 0
if extension and not extension.startswith('.'):
extension = '.%s' % extension
fname = base_name + extension
while os.path.exists(fname):
fname = "%s-%d%s" % (base_name, idcount, extension)
idcount += 1
return fname
...@@ -27,19 +27,22 @@ class Config: ...@@ -27,19 +27,22 @@ class Config:
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 BINCAST_MAGIC_FILE - Path to the bincast magic file (used when -C is specified with the command line binwalk script) o BINCAST_MAGIC_FILE - Path to the bincast magic file (used when -C is specified with the command line binwalk script).
o BINARCH_MAGIC_FILE - Path to the binarch magic file (used when -A is specified with the command line binwalk script) o BINARCH_MAGIC_FILE - Path to the binarch magic file (used when -A is specified with the command line binwalk script).
o EXTRACT_FILE - Path to the extract configuration file (used when -e is specified with the command line binwalk script) o EXTRACT_FILE - Path to the extract configuration file (used when -e is specified with the command line binwalk script).
o PLUGINS - Path to the plugins directory.
''' '''
# Release version # Release version
VERSION = "1.0" VERSION = "1.2.1"
# 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"
# File names # File names
PLUGINS = "plugins"
EXTRACT_FILE = "extract.conf" EXTRACT_FILE = "extract.conf"
BINWALK_MAGIC_FILE = "binwalk" BINWALK_MAGIC_FILE = "binwalk"
BINCAST_MAGIC_FILE = "bincast" BINCAST_MAGIC_FILE = "bincast"
...@@ -61,16 +64,18 @@ class Config: ...@@ -61,16 +64,18 @@ class Config:
} }
# Build the paths to all user-specific files # Build the paths to all user-specific files
self.paths['user'][self.BINWALK_MAGIC_FILE] = self._user_file(self.BINWALK_MAGIC_DIR, self.BINWALK_MAGIC_FILE) self.paths['user'][self.BINWALK_MAGIC_FILE] = self._user_path(self.BINWALK_MAGIC_DIR, self.BINWALK_MAGIC_FILE)
self.paths['user'][self.BINCAST_MAGIC_FILE] = self._user_file(self.BINWALK_MAGIC_DIR, self.BINCAST_MAGIC_FILE) self.paths['user'][self.BINCAST_MAGIC_FILE] = self._user_path(self.BINWALK_MAGIC_DIR, self.BINCAST_MAGIC_FILE)
self.paths['user'][self.BINARCH_MAGIC_FILE] = self._user_file(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE) self.paths['user'][self.BINARCH_MAGIC_FILE] = self._user_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE)
self.paths['user'][self.EXTRACT_FILE] = self._user_file(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE) self.paths['user'][self.EXTRACT_FILE] = self._user_path(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE)
self.paths['user'][self.PLUGINS] = self._user_path(self.BINWALK_PLUGINS_DIR)
# Build the paths to all system-wide files # Build the paths to all system-wide files
self.paths['system'][self.BINWALK_MAGIC_FILE] = self._system_file(self.BINWALK_MAGIC_DIR, self.BINWALK_MAGIC_FILE) self.paths['system'][self.BINWALK_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINWALK_MAGIC_FILE)
self.paths['system'][self.BINCAST_MAGIC_FILE] = self._system_file(self.BINWALK_MAGIC_DIR, self.BINCAST_MAGIC_FILE) self.paths['system'][self.BINCAST_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINCAST_MAGIC_FILE)
self.paths['system'][self.BINARCH_MAGIC_FILE] = self._system_file(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE) self.paths['system'][self.BINARCH_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE)
self.paths['system'][self.EXTRACT_FILE] = self._system_file(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE) 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)
def _get_system_dir(self): def _get_system_dir(self):
''' '''
...@@ -119,7 +124,7 @@ class Config: ...@@ -119,7 +124,7 @@ class Config:
return fpath return fpath
def _user_file(self, subdir, basename): def _user_path(self, subdir, basename=''):
''' '''
Gets the full path to the 'subdir/basename' file in the user binwalk directory. Gets the full path to the 'subdir/basename' file in the user binwalk directory.
...@@ -130,7 +135,7 @@ class Config: ...@@ -130,7 +135,7 @@ class Config:
''' '''
return self._file_path(os.path.join(self.user_dir, self.BINWALK_USER_DIR, subdir), basename) return self._file_path(os.path.join(self.user_dir, self.BINWALK_USER_DIR, subdir), basename)
def _system_file(self, subdir, basename): def _system_path(self, subdir, basename=''):
''' '''
Gets the full path to the 'subdir/basename' file in the system binwalk directory. Gets the full path to the 'subdir/basename' file in the system binwalk directory.
......
...@@ -7,20 +7,23 @@ ...@@ -7,20 +7,23 @@
################################################################################################################# #################################################################################################################
# Assumes these utilities are installed in $PATH. # Assumes these utilities are installed in $PATH.
gzip compressed data:gz:gzip -d -f '%e' ^gzip compressed data:gz:gzip -d -f '%e'
lzma compressed data:7z:7zr e -y '%e' ^lzma compressed data:7z:7zr e -y '%e'
bzip2 compressed data:bz2:bzip2 -d -f '%e' ^bzip2 compressed data:bz2:bzip2 -d -f '%e'
zip archive data:zip:jar xf '%e' # jar does a better job of unzipping than unzip does... ^zip archive data:zip:jar xf '%e' # jar does a better job of unzipping than unzip does...
posix tar archive:tar:tar xvf '%e' ^posix tar archive:tar:tar xvf '%e'
^rar archive data:rar:unrar e '%e'
^arj archive data.*comment header:arj:arj e '%e'
# These assume the firmware-mod-kit is installed to /opt/firmware-mod-kit. # These assume the firmware-mod-kit is installed to /opt/firmware-mod-kit.
# If not, change the file paths appropriately. # If not, change the file paths appropriately.
squashfs filesystem:squashfs:/opt/firmware-mod-kit/trunk/unsquashfs_all.sh '%e' ^squashfs filesystem:squashfs:/opt/firmware-mod-kit/trunk/unsquashfs_all.sh '%e'
jffs2 filesystem:jffs2:/opt/firmware-mod-kit/trunk/src/jffs2/unjffs2 '%e' # requires root ^jffs2 filesystem:jffs2:/opt/firmware-mod-kit/trunk/src/jffs2/unjffs2 '%e' # requires root
cpio archive:cpio:/opt/firmware-mod-kit/trunk/uncpio.sh '%e' ^ascii cpio archive:cpio:/opt/firmware-mod-kit/trunk/uncpio.sh '%e'
^cramfs filesystem:cramfs:/opt/firmware-mod-kit/trunk/uncramfs_all.sh '%e'
^bff volume entry:bff:/opt/firmware-mod-kit/trunk/src/bff/bffxtractor.py '%e'
# Extract, but don't run anything # Extract, but don't run anything
ext2 filesystem:ext2 ^ext2 filesystem:ext2
romfs filesystem:romfs ^romfs filesystem:romfs
cramfs filesystem:cramfs ^private key:key
private key:key
This diff is collapsed.
This diff is collapsed.
import re
import common import common
from smartsig import SmartSignature from smartsignature import SmartSignature
class MagicFilter: class MagicFilter:
''' '''
Class to filter libmagic results based on include/exclude rules and false positive detection. Class to filter libmagic results based on include/exclude rules and false positive detection.
An instance of this class is available via the Binwalk.filter object. An instance of this class is available via the Binwalk.filter object.
Note that all filter strings should be in lower case.
Example code which creates include, exclude, and grep filters before running a Binwalk scan: Example code which creates include, exclude, and grep filters before running a binwalk scan:
import binwalk import binwalk
...@@ -58,7 +60,7 @@ class MagicFilter: ...@@ -58,7 +60,7 @@ class MagicFilter:
Adds a new filter which explicitly includes results that contain Adds a new filter which explicitly includes results that contain
the specified matching text. the specified matching text.
@match - Case insensitive text, or list of texts, to match. @match - Regex, or list of regexs, to match.
@exclusive - If True, then results that do not explicitly contain @exclusive - If True, then results that do not explicitly contain
a FILTER_INCLUDE match will be excluded. If False, a FILTER_INCLUDE match will be excluded. If False,
signatures that contain the FILTER_INCLUDE match will signatures that contain the FILTER_INCLUDE match will
...@@ -67,22 +69,21 @@ class MagicFilter: ...@@ -67,22 +69,21 @@ class MagicFilter:
Returns None. Returns None.
''' '''
include_filter = { if not isinstance(match, type([])):
'type' : self.FILTER_INCLUDE,
'filter' : ''
}
if type(match) != type([]):
matches = [match] matches = [match]
else: else:
matches = match matches = match
for m in matches: for m in matches:
include_filter = {}
if m: if m:
if exclusive and not self.exclusive_filter: if exclusive and not self.exclusive_filter:
self.exclusive_filter = True self.exclusive_filter = True
include_filter['filter'] = m.lower() include_filter['type'] = self.FILTER_INCLUDE
include_filter['filter'] = m
include_filter['regex'] = re.compile(m)
self.filters.append(include_filter) self.filters.append(include_filter)
def exclude(self, match): def exclude(self, match):
...@@ -90,23 +91,22 @@ class MagicFilter: ...@@ -90,23 +91,22 @@ class MagicFilter:
Adds a new filter which explicitly excludes results that contain Adds a new filter which explicitly excludes results that contain
the specified matching text. the specified matching text.
@match - Case insensitive text, or list of texts, to match. @match - Regex, or list of regexs, to match.
Returns None. Returns None.
''' '''
exclude_filter = { if not isinstance(match, type([])):
'type' : self.FILTER_EXCLUDE,
'filter' : ''
}
if type(match) != type([]):
matches = [match] matches = [match]
else: else:
matches = match matches = match
for m in matches: for m in matches:
exclude_filter = {}
if m: if m:
exclude_filter['filter'] = m.lower() exclude_filter['type'] = self.FILTER_EXCLUDE
exclude_filter['filter'] = m
exclude_filter['regex'] = re.compile(m)
self.filters.append(exclude_filter) self.filters.append(exclude_filter)
def filter(self, data): def filter(self, data):
...@@ -124,7 +124,7 @@ class MagicFilter: ...@@ -124,7 +124,7 @@ class MagicFilter:
# Loop through the filters to see if any of them are a match. # Loop through the filters to see if any of them are a match.
# If so, return the registered type for the matching filter (FILTER_INCLUDE | FILTER_EXCLUDE). # If so, return the registered type for the matching filter (FILTER_INCLUDE | FILTER_EXCLUDE).
for f in self.filters: for f in self.filters:
if f['filter'] in data: if f['regex'].search(data):
return f['type'] return f['type']
# If there was not explicit match and exclusive filtering is enabled, return FILTER_EXCLUDE. # If there was not explicit match and exclusive filtering is enabled, return FILTER_EXCLUDE.
...@@ -166,7 +166,7 @@ class MagicFilter: ...@@ -166,7 +166,7 @@ class MagicFilter:
Add or check case-insensitive grep filters against the supplied data string. Add or check case-insensitive grep filters against the supplied data string.
@data - Data string to check grep filters against. Not required if filters is specified. @data - Data string to check grep filters against. Not required if filters is specified.
@filters - Filter, or list of filters, to add to the grep filters list. Not required if data is specified. @filters - Regex, or list of regexs, to add to the grep filters list. Not required if data is specified.
Returns None if data is not specified. Returns None if data is not specified.
If data is specified, returns True if the data contains a grep filter, or if no grep filters exist. If data is specified, returns True if the data contains a grep filter, or if no grep filters exist.
...@@ -174,14 +174,14 @@ class MagicFilter: ...@@ -174,14 +174,14 @@ class MagicFilter:
''' '''
# Add any specified filters to self.grep_filters # Add any specified filters to self.grep_filters
if filters: if filters:
if type(filters) != type([]): if not isinstance(filters, type([])):
gfilters = [filters] gfilters = [filters]
else: else:
gfilters = filters gfilters = filters
for gfilter in gfilters: for gfilter in gfilters:
# Filters are case insensitive # Filters are case insensitive
self.grep_filters.append(gfilter.lower()) self.grep_filters.append(re.compile(gfilter))
# Check the data against all grep filters until one is found # Check the data against all grep filters until one is found
if data is not None: if data is not None:
...@@ -194,7 +194,7 @@ class MagicFilter: ...@@ -194,7 +194,7 @@ class MagicFilter:
# If a filter exists in data, return True # If a filter exists in data, return True
for gfilter in self.grep_filters: for gfilter in self.grep_filters:
if gfilter in data: if gfilter.search(data):
return True return True
# Else, return False # Else, return False
......
# MIPS prologue # MIPS prologue
# addiu $sp, -XX # addiu $sp, -XX
# 27 BD FF XX # 27 BD FF XX
1 string \377\275\47 MIPSEL function prologue 0 string \377\275\47 MIPSEL instructions, function prologue{offset-adjust:-1}
0 string \47\275\377 MIPS function prologue 0 string \47\275\377 MIPS instructions, function prologue
# MIPS epilogue # MIPS epilogue
# jr $ra # jr $ra
0 belong 0x03e00008 MIPS function epilogue 0 belong 0x03e00008 MIPS instructions, function epilogue
0 lelong 0x03e00008 MIPSEL 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 # PowerPC epilogue
# blr # blr
0 belong 0x4E800020 PowerPC big endian function epilogue 0 belong 0x4E800020 PowerPC big endian instructions, function epilogue
0 lelong 0x4E800020 PowerPC little endian function epilogue 0 lelong 0x4E800020 PowerPC little endian instructions, function epilogue
# ARM prologue # ARM prologue
# STMFD SP!, {XX} # STMFD SP!, {XX}
0 beshort 0xE92D ARMEB function prologue 0 beshort 0xE92D ARMEB instructions, function prologue
2 leshort 0xE92D ARM function prologue 0 leshort 0xE92D ARM instructions, function prologue{offset-adjust:-2}
# ARM epilogue # ARM epilogue
# LDMFD SP!, {XX} # LDMFD SP!, {XX}
0 beshort 0xE8BD ARMEB function epilogue 0 beshort 0xE8BD ARMEB instructions, function epilogue
2 leshort 0xE8BD ARM function epilogue 0 leshort 0xE8BD ARM instructions, function epilogue{offset-adjust:-2}
# x86 epilogue # x86 epilogue
# push ebp # push ebp
# move ebp, esp # move ebp, esp
0 string \x55\x89\xE5 Intel x86 function epilogue 0 string \x55\x89\xE5 Intel x86 instructions, function epilogue
0 belong x Hex: 0x%.8X 0 belong x Hex: 0x%.8X
#0 string x String: %s #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 lelong x Little Endian Long: %d
0 belong x Big Endian Long: %d 0 belong x Big Endian Long: %d
0 leshort x Little Endian Short: %d 0 leshort x Little Endian Short: %d
......
This diff is collapsed.
import re
import os.path import os.path
import tempfile import tempfile
from common import str2int from common import str2int
...@@ -23,9 +24,6 @@ class MagicParser: ...@@ -23,9 +24,6 @@ class MagicParser:
All magic files generated by this class will be deleted when the class deconstructor is called. All magic files generated by this class will be deleted when the class deconstructor is called.
''' '''
SHORT_SIZE = 2
SHORTS = ['beshort', 'leshort', 'byte']
BIG_ENDIAN = 'big' BIG_ENDIAN = 'big'
LITTLE_ENDIAN = 'little' LITTLE_ENDIAN = 'little'
...@@ -37,18 +35,6 @@ class MagicParser: ...@@ -37,18 +35,6 @@ class MagicParser:
# If libmagic returns multiple results, they are delimited with this string. # If libmagic returns multiple results, they are delimited with this string.
RESULT_SEPERATOR = "\\012- " RESULT_SEPERATOR = "\\012- "
# Size of the keys used in the matches set. Limited to 2
# as the key is the magic signature of a given magic file entry.
# Entries can have variable length signatures, but the lowest
# common demonitor is 2, so the first two bytes of the signature
# is used as the key. Does this result in collisions and false
# positives? Yes. But false positives are filtered out by the
# MagicFilter class. The main purpose of MagicParser.match is to
# limit the number of calls to libmagic without itself incurring
# large computational overhead. And for that purpose, this is
# quite effective.
MATCH_INDEX_SIZE = 2
def __init__(self, filter=None, smart=None): def __init__(self, filter=None, smart=None):
''' '''
Class constructor. Class constructor.
...@@ -60,7 +46,6 @@ class MagicParser: ...@@ -60,7 +46,6 @@ class MagicParser:
''' '''
self.matches = set([]) self.matches = set([])
self.signatures = {} self.signatures = {}
self.sigset = {}
self.filter = filter self.filter = filter
self.smart = smart self.smart = smart
self.raw_fd = None self.raw_fd = None
...@@ -68,10 +53,10 @@ class MagicParser: ...@@ -68,10 +53,10 @@ class MagicParser:
self.fd = tempfile.NamedTemporaryFile() self.fd = tempfile.NamedTemporaryFile()
def __del__(self): def __del__(self):
''' try:
Class deconstructor. self.cleanup()
''' except:
self.cleanup() pass
def cleanup(self): def cleanup(self):
''' '''
...@@ -105,38 +90,34 @@ class MagicParser: ...@@ -105,38 +90,34 @@ class MagicParser:
self.raw_fd.seek(0) self.raw_fd.seek(0)
return self.raw_fd.name return self.raw_fd.name
def parse(self, file_name, filter_short_signatures=True, pre_filter_signatures=True): def parse(self, file_name):
''' '''
Parses magic file(s) and contatenates them into a single temporary magic file Parses magic file(s) and contatenates them into a single temporary magic file
while simultaneously removing filtered signatures. while simultaneously removing filtered signatures.
@file_name - Magic file, or list of magic files, to parse. @file_name - Magic file, or list of magic files, to parse.
@filter_short_signatures - Set to False to include entries with short (2 byte) magic signatures.
@pre_filter_signatures - Set to False to disable smart signature keywords.
Returns the name of the generated temporary magic file, which will be automatically Returns the name of the generated temporary magic file, which will be automatically
deleted when the class deconstructor is called. deleted when the class deconstructor is called.
''' '''
if type(file_name) == type([]): if isinstance(file_name, type([])):
files = file_name files = file_name
else: else:
files = [file_name] files = [file_name]
for fname in files: for fname in files:
if os.path.exists(fname): if os.path.exists(fname):
self.parse_file(fname, filter_short_signatures, pre_filter_signatures) self.parse_file(fname)
self.fd.seek(0) self.fd.seek(0)
return self.fd.name return self.fd.name
def parse_file(self, file_name, filter_short_signatures=True, pre_filter_signatures=True): def parse_file(self, file_name):
''' '''
Parses a magic file and appends valid signatures to the temporary magic file, as allowed Parses a magic file and appends valid signatures to the temporary magic file, as allowed
by the existing filter rules. by the existing filter rules.
@file_name - Magic file to parse. @file_name - Magic file to parse.
@filter_short_signatures - Set to False to include entries with short (2 byte) magic signatures.
@pre_filter_signatures - Set to False to disable smart signature keywords.
Returns None. Returns None.
''' '''
...@@ -153,61 +134,29 @@ class MagicParser: ...@@ -153,61 +134,29 @@ class MagicParser:
entry = self._parse_line(line) entry = self._parse_line(line)
if entry is not None: if entry is not None:
# Once an entry is identified, default to excluding the entry
include = False
if pre_filter_signatures:
# If the smart signature include keyword is specified for this entry,
# add an include filter for this signature description.
if self.smart.include(entry['description']):
self.filter.include(entry['description'], exclusive=False)
include = True
# If we haven't already explicitly included this entry, and we are
# filtering out short signatures and this is a short signature, then
# add an exclude filter for this signature description
if not include and filter_short_signatures and self._is_short(entry):
self.filter.exclude(entry['description'])
# If this signature is marked for inclusion, include it. # If this signature is marked for inclusion, include it.
if self.filter.filter(entry['description']) == self.filter.FILTER_INCLUDE: if self.filter.filter(entry['description']) == self.filter.FILTER_INCLUDE:
include = True
include = True
if include:
self.signature_count += 1 self.signature_count += 1
if not self.signatures.has_key(entry['offset']): if not self.signatures.has_key(entry['offset']):
self.signatures[entry['offset']] = [] self.signatures[entry['offset']] = []
if entry['condition'][:self.MATCH_INDEX_SIZE] not in self.signatures[entry['offset']]: if entry['condition'] not in self.signatures[entry['offset']]:
self.signatures[entry['offset']].append(entry['condition'][:self.MATCH_INDEX_SIZE]) self.signatures[entry['offset']].append(entry['condition'])
else:
include = False
# Keep writing lines of the signature to the temporary magic file until # Keep writing lines of the signature to the temporary magic file until
# we detect a signature that should not be included. # we detect a signature that should not be included.
if include: if include:
self.fd.write(line) self.fd.write(line)
self.build_signature_set()
except Exception, e: except Exception, e:
raise Exception("Error parsing magic file '%s' on line %d: %s" % (file_name, line_count, str(e))) raise Exception("Error parsing magic file '%s' on line %d: %s" % (file_name, line_count, str(e)))
# Generate a dictionary of offsets with a set of signatures
for (offset, siglist) in self.signatures.iteritems():
self.sigset[offset] = set(siglist)
def _is_short(self, entry):
'''
Determines if a signature entry has a short (2 byte) signature or not.
@entry - Entry dictionary, as returned by self._parse_line().
Returns True if the signature is short, False if not short.
'''
if entry['type'] in self.SHORTS:
return True
elif 'string' in entry['type']:
if len(entry['condition'].decode('string_escape')) <= self.SHORT_SIZE:
return True
return False
def _parse_line(self, line): def _parse_line(self, line):
''' '''
Parses a signature line into its four parts (offset, type, condition and description), Parses a signature line into its four parts (offset, type, condition and description),
...@@ -253,7 +202,7 @@ class MagicParser: ...@@ -253,7 +202,7 @@ class MagicParser:
raise Exception("%s :: %s", (str(e), line)) raise Exception("%s :: %s", (str(e), line))
# If this is a string, get the length of the string # If this is a string, get the length of the string
if 'string' in entry['type']: if 'string' in entry['type'] or entry['condition'] == self.WILDCARD:
entry['length'] = len(entry['condition']) entry['length'] = len(entry['condition'])
# Else, we need to jump through a few more hoops... # Else, we need to jump through a few more hoops...
else: else:
...@@ -267,14 +216,10 @@ class MagicParser: ...@@ -267,14 +216,10 @@ class MagicParser:
# Try to convert the condition to an integer. This does not allow # Try to convert the condition to an integer. This does not allow
# for more advanced conditions for the first line of a signature, # for more advanced conditions for the first line of a signature,
# but needing that is rare. # but needing that is rare.
if entry['condition'] != self.WILDCARD: try:
try: intval = str2int(entry['condition'].strip('L'))
intval = str2int(entry['condition'].strip('L')) except Exception, e:
except Exception, e: raise Exception("Failed to evaluate condition for '%s' type: '%s', condition: '%s', error: %s" % (entry['description'], entry['type'], entry['condition'], str(e)))
raise Exception("Failed to evaluate condition for '%s' type: '%s', condition: '%s', error: %s" % (entry['description'], entry['type'], entry['condition'], str(e)))
else:
intval = 0
entry['length'] = 1
# How long is the field type? # How long is the field type?
if entry['type'] == 'byte': if entry['type'] == 'byte':
...@@ -295,15 +240,41 @@ class MagicParser: ...@@ -295,15 +240,41 @@ class MagicParser:
''' '''
Builds a list of signature tuples. Builds a list of signature tuples.
Returns a list of tuples in the format: [(<signature offset>, [set of 2-byte signatures])]. Returns a list of tuples in the format: [(<signature offset>, [signature regex])].
'''
signature_set = []
for (offset, sigs) in self.signatures.iteritems():
for sig in sigs:
if sig == self.WILDCARD:
sig = re.compile('.')
else:
sig = re.compile(re.escape(sig))
signature_set.append(sig)
self.signature_set = set(signature_set)
return self.signature_set
def find_signature_candidates(self, data):
''' '''
signatures = [] Finds candidate signatures inside of the data buffer.
Called internally by Binwalk.single_scan.
@data - Data to scan for candidate signatures.
Returns an ordered list of offsets inside of data at which candidate offsets were found.
'''
candidate_offsets = []
for regex in self.signature_set:
candidate_offsets += [match.start() for match in regex.finditer(data)]
for (offset, sigset) in self.sigset.iteritems(): candidate_offsets = list(set(candidate_offsets))
signatures.append((