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):
return re.findall(r'\"(.*)\"', string)[0]
except:
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:
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 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 EXTRACT_FILE - Path to the extract configuration file (used when -e 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 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
VERSION = "1.0"
VERSION = "1.2.1"
# Sub directories
BINWALK_USER_DIR = ".binwalk"
BINWALK_MAGIC_DIR = "magic"
BINWALK_CONFIG_DIR = "config"
BINWALK_PLUGINS_DIR = "plugins"
# File names
PLUGINS = "plugins"
EXTRACT_FILE = "extract.conf"
BINWALK_MAGIC_FILE = "binwalk"
BINCAST_MAGIC_FILE = "bincast"
......@@ -61,16 +64,18 @@ class Config:
}
# 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.BINCAST_MAGIC_FILE] = self._user_file(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.EXTRACT_FILE] = self._user_file(self.BINWALK_CONFIG_DIR, self.EXTRACT_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_path(self.BINWALK_MAGIC_DIR, self.BINCAST_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_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
self.paths['system'][self.BINWALK_MAGIC_FILE] = self._system_file(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.BINARCH_MAGIC_FILE] = self._system_file(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.BINWALK_MAGIC_FILE] = self._system_path(self.BINWALK_MAGIC_DIR, self.BINWALK_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_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_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):
'''
......@@ -119,7 +124,7 @@ class Config:
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.
......@@ -130,7 +135,7 @@ class Config:
'''
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.
......
......@@ -7,20 +7,23 @@
#################################################################################################################
# Assumes these utilities are installed in $PATH.
gzip compressed data:gz:gzip -d -f '%e'
lzma compressed data:7z:7zr e -y '%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...
posix tar archive:tar:tar xvf '%e'
^gzip compressed data:gz:gzip -d -f '%e'
^lzma compressed data:7z:7zr e -y '%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...
^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.
# If not, change the file paths appropriately.
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
cpio archive:cpio:/opt/firmware-mod-kit/trunk/uncpio.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
^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
ext2 filesystem:ext2
romfs filesystem:romfs
cramfs filesystem:cramfs
private key:key
^ext2 filesystem:ext2
^romfs filesystem:romfs
^private key:key
This diff is collapsed.
import os
import re
import sys
import shlex
import tempfile
import subprocess
from config import *
from common import file_size
from common import file_size, unique_file_name
class Extractor:
'''
......@@ -20,7 +21,7 @@ class Extractor:
# Create extraction rules for scan results containing the string 'gzip compressed data' and 'filesystem'.
# The former will be saved to disk with a file extension of 'gz' and the command 'gunzip <file name on disk>' will be executed (note the %e placeholder).
# The latter will be saved to disk with a file extension of 'fs' and no command will be executed.
# These rules will take precedence over subsequent rules with the same match string.
# These rules will be ignored if there were previous rules with the same match string.
bw.extractor.add_rule(['gzip compressed data:gz:gunzip %e', 'filesystem:fs'])
# Load the extraction rules from the default extract.conf file(s).
......@@ -40,6 +41,9 @@ class Extractor:
# Place holder for the extracted file name in the command
FILE_NAME_PLACEHOLDER = '%e'
# Max size of data to read/write at one time when extracting data
MAX_READ_SIZE = 10 * 1024 * 1024
def __init__(self, verbose=False):
'''
Class constructor.
......@@ -54,24 +58,37 @@ class Extractor:
self.verbose = verbose
self.extract_rules = {}
self.remove_after_execute = False
self.extract_path = os.getcwd()
def add_rule(self, rule):
def add_rule(self, txtrule=None, regex=None, extension=None, cmd=None):
'''
Adds a set of rules to the extraction rule list.
@rule - Rule string, or list of rule strings, in the format <case insensitive matching string>:<file extension>[:<command to run>]
@txtrule - Rule string, or list of rule strings, in the format <regular expression>:<file extension>[:<command to run>]
@regex - If rule string is not specified, this is the regular expression string to use.
@extension - If rule string is not specified, this is the file extension to use.
@cmd - If rule string is not specified, this is the command to run.
Alternatively a callable object may be specified, which will be passed one argument: the path to the file to extract.
Returns None.
'''
rules = []
match = False
r = {
'extension' : '',
'cmd' : ''
'cmd' : '',
'regex' : None
}
if type(rule) != type([]):
rules = [rule]
if not txtrule and regex and extension:
txtrule = '%s:%s' % (regex, extension)
if cmd:
txtrule += ':%s' % cmd
if not isinstance(txtrule, type([])):
rules = [txtrule]
else:
rules = rule
rules = txtrule
for rule in rules:
r['cmd'] = ''
......@@ -79,21 +96,60 @@ class Extractor:
try:
values = self._parse_rule(rule)
match = values[0].lower()
match = values[0]
r['regex'] = re.compile(values[0])
r['extension'] = values[1]
r['cmd'] = values[2]
except:
pass
if not match and regex and extension:
match = regex
r['regex'] = re.compile(regex)
r['extension'] = extension
r['cmd'] = cmd
# Verify that the match string and file extension were retrieved.
# Only add the rule if it is a new one (first come, first served).
if match and r['extension'] and not self.extract_rules.has_key(match):
self.extract_rules[match] = {}
self.extract_rules[match]['cmd'] = r['cmd']
self.extract_rules[match]['extension'] = r['extension']
self.extract_rules[match]['regex'] = r['regex']
# Once any rule is added, set self.enabled to True
self.enabled = True
def remove_rule(self, text):
'''
Remove all rules that match a specified text.
@text - The text to match against.
Returns the number of rules removed.
'''
i = 0
for key in self.extract_rules.keys():
if self.extract_rules[key]['regex'].match(text):
del self.extract_rules[key]
i += 1
return i
def clear_rules(self):
'''
Deletes all extraction rules.
Returns None.
'''
self.extract_rules = {}
self.enabled = False
def get_rules(self):
'''
Returns a dictionary of all extraction rules.
'''
return self.extract_rules
def enable_delayed_extract(self, tf=None):
'''
Enables / disables the delayed extraction feature.
......@@ -142,6 +198,16 @@ class Extractor:
if self.verbose:
raise Exception("Extractor.load_defaults failed to load file '%s': %s" % (extract_file, str(e)))
def output_directory(self, path):
'''
Set the output directory for extracted files.
@path - The extraction path.
Returns None.
'''
self.extract_path = path
def cleanup_extracted_files(self, tf=None):
'''
Set the action to take after a file is extracted.
......@@ -170,15 +236,25 @@ class Extractor:
Returns the name of the extracted file (blank string if nothing was extracted).
'''
fname = ''
cleanup_extracted_fname = True
original_dir = os.getcwd()
if not os.path.exists(self.extract_path):
os.mkdir(self.extract_path)
file_path = os.path.realpath(file_name)
if os.path.isfile(file_path):
os.chdir(self.extract_path)
rule = self._match(description)
if rule is not None:
fname = self._dd(file_name, offset, size, rule['extension'], output_file_name=name)
fname = self._dd(file_path, offset, size, rule['extension'], output_file_name=name)
if rule['cmd']:
# Many extraction utilities will extract the file to a new file, just without
# the file extension (i.e., myfile.7z => myfile). If the presumed resulting
# the file extension (i.e., myfile.7z -> myfile). If the presumed resulting
# file name already exists before executing the extract command, do not attempt
# to clean it up even if its resulting file size is 0.
if self.remove_after_execute:
......@@ -206,8 +282,10 @@ class Extractor:
os.unlink(extracted_fname)
except:
pass
else:
fname = ''
fname = os.path.join(self.extract_path, fname)
os.chdir(original_dir)
return fname
......@@ -280,7 +358,7 @@ class Extractor:
description = description.lower()
for (m, rule) in self.extract_rules.iteritems():
if m in description:
if rule['regex'].search(description):
return rule
return None
......@@ -306,23 +384,23 @@ class Extractor:
Returns the extracted file name.
'''
# Default extracted file name is <hex offset>.<extension>
altname = "%X.%s" % (offset, extension)
total_size = 0
if not output_file_name or output_file_name is None:
fname = altname
# Default extracted file name is <hex offset>.<extension>
bname = "%X" % offset
else:
fname = "%s.%s" % (output_file_name, extension)
# Strip the output file name of invalid/dangerous characters (like file paths)
bname = os.path.basename(output_file_name)
# Sanitize output file name of invalid/dangerous characters (like file paths)
fname = os.path.basename(fname)
fname = unique_file_name(bname, extension)
try:
# Open the target file and seek to the offset
fdin = open(file_name, "rb")
fdin.seek(offset)
# Open the extracted file
# Open the output file
try:
fdout = open(fname, "wb")
except:
......@@ -330,8 +408,14 @@ class Extractor:
fname = altname
fdout = open(fname, "wb")
# Read size bytes from target file and write it to the extracted file
fdout.write(fdin.read(size))
# Read data from target file in chunks and write it to the extracted file
while total_size < size:
block_size = size - total_size
if block_size > self.MAX_READ_SIZE:
block_size = self.MAX_READ_SIZE
fdout.write(fdin.read(block_size))
total_size += block_size
# Cleanup
fdout.close()
......@@ -352,11 +436,14 @@ class Extractor:
'''
tmp = None
try:
if callable(cmd):
cmd(fname)
else:
# If not in verbose mode, create a temporary file to redirect stdout and stderr to
if not self.verbose:
tmp = tempfile.TemporaryFile()
try:
# Replace all instances of FILE_NAME_PLACEHOLDER in the command with fname
cmd = cmd.replace(self.FILE_NAME_PLACEHOLDER, fname)
......
import re
import common
from smartsig import SmartSignature
from smartsignature import SmartSignature
class MagicFilter:
'''
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.
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
......@@ -58,7 +60,7 @@ class MagicFilter:
Adds a new filter which explicitly includes results that contain
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
a FILTER_INCLUDE match will be excluded. If False,
signatures that contain the FILTER_INCLUDE match will
......@@ -67,22 +69,21 @@ class MagicFilter:
Returns None.
'''
include_filter = {
'type' : self.FILTER_INCLUDE,
'filter' : ''
}
if type(match) != type([]):
if not isinstance(match, type([])):
matches = [match]
else:
matches = match
for m in matches:
include_filter = {}
if m:
if exclusive and not self.exclusive_filter:
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)
def exclude(self, match):
......@@ -90,23 +91,22 @@ class MagicFilter:
Adds a new filter which explicitly excludes results that contain
the specified matching text.
@match - Case insensitive text, or list of texts, to match.
@match - Regex, or list of regexs, to match.
Returns None.
'''
exclude_filter = {
'type' : self.FILTER_EXCLUDE,
'filter' : ''
}
if type(match) != type([]):
if not isinstance(match, type([])):
matches = [match]
else:
matches = match
for m in matches:
exclude_filter = {}
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)
def filter(self, data):
......@@ -124,7 +124,7 @@ class MagicFilter:
# 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).
for f in self.filters:
if f['filter'] in data:
if f['regex'].search(data):
return f['type']
# If there was not explicit match and exclusive filtering is enabled, return FILTER_EXCLUDE.
......@@ -166,7 +166,7 @@ class MagicFilter:
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.
@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.
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:
'''
# Add any specified filters to self.grep_filters
if filters:
if type(filters) != type([]):
if not isinstance(filters, type([])):
gfilters = [filters]
else:
gfilters = filters
for gfilter in gfilters:
# 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
if data is not None:
......@@ -194,7 +194,7 @@ class MagicFilter:
# If a filter exists in data, return True
for gfilter in self.grep_filters:
if gfilter in data:
if gfilter.search(data):
return True
# Else, return False
......
# MIPS prologue
# addiu $sp, -XX
# 27 BD FF XX
1 string \377\275\47 MIPSEL function prologue
0 string \47\275\377 MIPS function prologue
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 function epilogue
0 lelong 0x03e00008 MIPSEL function epilogue
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 function epilogue
0 lelong 0x4E800020 PowerPC little endian function epilogue
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 function prologue
2 leshort 0xE92D ARM function prologue
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 function epilogue
2 leshort 0xE8BD ARM function epilogue
0 beshort 0xE8BD ARMEB instructions, function epilogue
0 leshort 0xE8BD ARM instructions, function epilogue{offset-adjust:-2}
# x86 epilogue
# push ebp
# 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 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
......
This diff is collapsed.
import re
import os.path
import tempfile
from common import str2int
......@@ -23,9 +24,6 @@ class MagicParser:
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'
LITTLE_ENDIAN = 'little'
......@@ -37,18 +35,6 @@ class MagicParser:
# If libmagic returns multiple results, they are delimited with this string.
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):
'''
Class constructor.
......@@ -60,7 +46,6 @@ class MagicParser:
'''
self.matches = set([])
self.signatures = {}
self.sigset = {}
self.filter = filter
self.smart = smart
self.raw_fd = None
......@@ -68,10 +53,10 @@ class MagicParser:
self.fd = tempfile.NamedTemporaryFile()
def __del__(self):
'''
Class deconstructor.
'''
try:
self.cleanup()
except:
pass
def cleanup(self):
'''
......@@ -105,38 +90,34 @@ class MagicParser:
self.raw_fd.seek(0)
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
while simultaneously removing filtered signatures.
@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
deleted when the class deconstructor is called.
'''
if type(file_name) == type([]):
if isinstance(file_name, type([])):
files = file_name
else:
files = [file_name]
for fname in files:
if os.path.exists(fname):
self.parse_file(fname, filter_short_signatures, pre_filter_signatures)
self.parse_file(fname)
self.fd.seek(0)
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
by the existing filter rules.
@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.
'''
......@@ -153,61 +134,29 @@ class MagicParser:
entry = self._parse_line(line)
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 self.filter.filter(entry['description']) == self.filter.FILTER_INCLUDE:
include = True
if include:
include = True
self.signature_count += 1
if not self.signatures.has_key(entry['offset']):
self.signatures[entry['offset']] = []
if entry['condition'][:self.MATCH_INDEX_SIZE] not in self.signatures[entry['offset']]:
self.signatures[entry['offset']].append(entry['condition'][:self.MATCH_INDEX_SIZE])
if entry['condition'] not in self.signatures[entry['offset']]:
self.signatures[entry['offset']].append(entry['condition'])
else:
include = False
# Keep writing lines of the signature to the temporary magic file until
# we detect a signature that should not be included.
if include:
self.fd.write(line)
self.build_signature_set()
except Exception, 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)