Commit 84bce4f9 by devttys0

Added support for the 'many' tag; added support for new type operators

parent 0d9524ba
...@@ -16,16 +16,17 @@ class SignatureResult(object): ...@@ -16,16 +16,17 @@ class SignatureResult(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
# These are set by signature keyword tags # These are set by signature keyword tags
self.jump = 0 self.jump = 0
self.many = False
self.size = 0 self.size = 0
self.name = None self.name = None
self.offset = 0 self.offset = 0
self.adjust = 0
self.strlen = 0 self.strlen = 0
self.string = False self.string = False
self.invalid = False self.invalid = False
self.extract = True self.extract = True
# These are set by code internally # These are set by code internally
self.id = 0
self.file = None self.file = None
self.valid = True self.valid = True
self.display = True self.display = True
...@@ -34,6 +35,8 @@ class SignatureResult(object): ...@@ -34,6 +35,8 @@ class SignatureResult(object):
for (k,v) in binwalk.core.compat.iterator(kwargs): for (k,v) in binwalk.core.compat.iterator(kwargs):
setattr(self, k, v) setattr(self, k, v)
self.valid = (not self.invalid)
class SignatureLine(object): class SignatureLine(object):
def __init__(self, line): def __init__(self, line):
...@@ -50,18 +53,15 @@ class SignatureLine(object): ...@@ -50,18 +53,15 @@ class SignatureLine(object):
except ValueError as e: except ValueError as e:
pass pass
if '&' in parts[1]:
(self.type, self.bitmask) = parts[1].split('&', 1)
self.boolean = '&'
self.bitmask = int(self.bitmask, 0)
elif '|' in parts[1]:
(self.type, self.bitmask) = parts[1].split('|', 1)
self.boolean = '|'
self.bitmask = int(self.bitmask, 0)
else:
self.type = parts[1] self.type = parts[1]
self.boolean = None self.opvalue = None
self.bitmask = None self.operator = None
for operator in ['&', '|', '*', '+', '-', '/']:
if operator in parts[1]:
(self.type, self.opvalue) = parts[1].split(operator, 1)
self.operator = operator
self.opvalue = int(self.opvalue, 0)
break
if parts[2][0] in ['=', '!', '>', '<', '&', '|']: if parts[2][0] in ['=', '!', '>', '<', '&', '|']:
self.condition = parts[2][0] self.condition = parts[2][0]
...@@ -143,8 +143,10 @@ class SignatureLine(object): ...@@ -143,8 +143,10 @@ class SignatureLine(object):
class Signature(object): class Signature(object):
def __init__(self, first_line): def __init__(self, id, first_line):
self.id = id
self.lines = [first_line] self.lines = [first_line]
self.title = first_line.format
self.offset = first_line.offset self.offset = first_line.offset
self.confidence = first_line.size self.confidence = first_line.size
self.regex = self.generate_regex(first_line) self.regex = self.generate_regex(first_line)
...@@ -243,7 +245,7 @@ class Magic(object): ...@@ -243,7 +245,7 @@ class Magic(object):
description = [] description = []
tag_strlen = None tag_strlen = None
max_line_level = 0 max_line_level = 0
tags = {'offset' : offset, 'invalid' : False} tags = {'id' : signature.id, 'offset' : offset, 'invalid' : False}
for line in signature.lines: for line in signature.lines:
if line.level <= max_line_level: if line.level <= max_line_level:
...@@ -286,8 +288,8 @@ class Magic(object): ...@@ -286,8 +288,8 @@ class Magic(object):
dvalue = struct.unpack(line.pkfmt, binwalk.core.compat.str2bytes(self.data[start:end]))[0] dvalue = struct.unpack(line.pkfmt, binwalk.core.compat.str2bytes(self.data[start:end]))[0]
except struct.error as e: except struct.error as e:
dvalue = 0 dvalue = 0
elif line.size: else:
# Strings have line.value == None # Wildcard strings have line.value == None
if line.value is None: if line.value is None:
if [x for x in line.tags if x.name == 'string'] and binwalk.core.compat.has_key(tags, 'strlen'): if [x for x in line.tags if x.name == 'string'] and binwalk.core.compat.has_key(tags, 'strlen'):
dvalue = self.data[start:(start+tags['strlen'])] dvalue = self.data[start:(start+tags['strlen'])]
...@@ -296,10 +298,19 @@ class Magic(object): ...@@ -296,10 +298,19 @@ class Magic(object):
else: else:
dvalue = self.data[start:end] dvalue = self.data[start:end]
if line.boolean == '&': if isinstance(dvalue, int) and line.operator:
dvalue &= line.bitmask if line.operator == '&':
elif line.boolean == '|': dvalue &= line.opvalue
dvalue |= line.bitmask elif line.operator == '|':
dvalue |= line.opvalue
elif line.operator == '*':
dvalue *= line.opvalue
elif line.operator == '+':
dvalue += line.opvalue
elif line.operator == '-':
dvalue -= line.opvalue
elif line.operator == '/':
dvalue /= line.opvalue
if ((line.value is None) or if ((line.value is None) or
(line.condition == '=' and dvalue == line.value) or (line.condition == '=' and dvalue == line.value) or
...@@ -352,15 +363,14 @@ class Magic(object): ...@@ -352,15 +363,14 @@ class Magic(object):
tags['description'] = self.bspace.sub('', " ".join(description)) tags['description'] = self.bspace.sub('', " ".join(description))
#if not tags['description']: # This should never happen
# tags['display'] = False if not tags['description']:
# tags['invalid'] = True tags['display'] = False
tags['invalid'] = True
if self.printable.match(tags['description']).group() != tags['description']: if self.printable.match(tags['description']).group() != tags['description']:
tags['invalid'] = True tags['invalid'] = True
tags['valid'] = (not tags['invalid'])
return tags return tags
def scan(self, data, dlen=None): def scan(self, data, dlen=None):
...@@ -401,9 +411,9 @@ class Magic(object): ...@@ -401,9 +411,9 @@ class Magic(object):
sigline = SignatureLine(line) sigline = SignatureLine(line)
if sigline.level == 0: if sigline.level == 0:
if signature: if signature:
if not self.filtered(signature.lines[0].format): if not self.filtered(signature.title):
self.signatures.append(signature) self.signatures.append(signature)
signature = Signature(sigline) signature = Signature(len(self.signatures), sigline)
elif signature: elif signature:
signature.append(sigline) signature.append(sigline)
else: else:
......
...@@ -68,6 +68,8 @@ class Signature(Module): ...@@ -68,6 +68,8 @@ class Signature(Module):
VERBOSE_FORMAT = "%s %d" VERBOSE_FORMAT = "%s %d"
def init(self): def init(self):
self.one_of_many = None
# If a raw byte sequence was specified, build a magic file from that instead of using the default magic files # If a raw byte sequence was specified, build a magic file from that instead of using the default magic files
# TODO: re-implement this # TODO: re-implement this
#if self.raw_bytes is not None: #if self.raw_bytes is not None:
...@@ -112,6 +114,15 @@ class Signature(Module): ...@@ -112,6 +114,15 @@ class Signature(Module):
if r.jump and (r.jump + r.offset) > r.file.size: if r.jump and (r.jump + r.offset) > r.file.size:
r.valid = False r.valid = False
if r.valid:
# Don't keep displaying signatures that repeat a bunch of times (e.g., JFFS2 nodes)
if r.id == self.one_of_many:
r.display = False
elif r.many:
self.one_of_many = r.id
else:
self.one_of_many = None
def scan_file(self, fp): def scan_file(self, fp):
current_file_offset = 0 current_file_offset = 0
......
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