Skip to content

Commit

Permalink
Removed ambiguities from signature parser
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas Zaddach committed Sep 11, 2018
1 parent 3dd8f99 commit 2181f8b
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 96 deletions.
4 changes: 2 additions & 2 deletions plugin/casc/sigalyzer/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class FixedString():
def __init__(self, fixed_bytes):
self.fixed_bytes = fixed_bytes

def clone_append(self, byte):
return self.__class__(self.fixed_bytes + [byte])
def clone_prepend(self, byte):
return self.__class__([byte] + self.fixed_bytes)

def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, " ".join(x.__repr__() for x in self.fixed_bytes))
Expand Down
153 changes: 59 additions & 94 deletions plugin/casc/sigalyzer/sig_yacc.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,66 @@
from casc.sigalyzer.sig_lex import tokens, lexer
import ply.yacc as yacc
import logging
from casc.sigalyzer.common import SignatureParseException, \
FixedByte, FixedString, FixedStringLenTwo, Skip, \
Choice, ShortSkip, Not, HighNibble, LowNibble

def p_signature(p):
'''signature : exprwithfixed
| signature skip signature
| signature ANY signature'''
'''signature : expr
| expr signature'''
if len(p) == 2:
p[0] = p[1]
elif p[2] == '*':
p[0] = p[1] + [Skip(0, Skip.INFINITY)] + p[3]
p[0] = [p[1]]
else:
p[0] = p[1] + [p[2]] + p[3]
if isinstance(p[1], Skip) and isinstance(p[2][0], Skip):
if p[1].max == Skip.INFINITY or p[2][0].max == Skip.INFINITY:
max = Skip.INFINITY
else:
max = p[1],max + p[2][0].max
p[0] = [Skip(p[1].min + p[2][0].min, max)] + p[2][1:]
elif isinstance(p[1], FixedByte) and isinstance(p[2][0], FixedByte):
p[0] = [FixedString([p[1], p[2][0]])] + p[2][1:]
elif isinstance(p[1], FixedByte) and isinstance(p[2][0], FixedString):
p[0] = [p[2][0].clone_prepend(p[1])] + p[2][1:]
else:
p[0] = [p[1]] + p[2]

def p_expr(p):
'''expr : fixedbyte_highnibble
| lownibble_skipbyte
| skip
| any
| shortskip
| choice
| negatedchoice'''
p[0] = p[1]

def p_any(p):
'''any : ANY'''
p[0] = Skip(0, Skip.INFINITY)

def p_hexchar(p):
'''hexchar : DIGIT
| HEXALPHA'''
p[0] = p[1]

def p_fixedbyte_highnibble(p):
'''fixedbyte_highnibble : fixedbyte
| highnibble'''
p[0] = p[1]

def p_fixedbyte(p):
'''fixedbyte : hexchar hexchar'''
p[0] = FixedByte("%s%s" % (p[1], p[2]))

def p_skip(p):
'''skip : LBRACE number MINUS number RBRACE
| LBRACE MINUS number RBRACE
| LBRACE number MINUS RBRACE'''
| LBRACE number MINUS RBRACE
| LBRACE number RBRACE'''
if len(p) == 6:
p[0] = Skip(int(p[2]), int(p[4]))
elif len(p) == 4:
p[0] = Skip(int(p[2]), int(p[2]))
elif p[2] == '-':
p[0] = Skip(0, int(p[3]))
else:
Expand All @@ -34,48 +74,9 @@ def p_number(p):
else:
p[0] = p[1] * 10 + int(p[2])

def p_exprwithfixed(p):
'''exprwithfixed : fixedexpr
| repexpr fixedexpr
| fixedexpr repexpr'''
if len(p) == 2:
p[0] = p[1]
else:
p[0] = p[1] + p[2]


def p_fixedexpr(p):
'''fixedexpr : fixedstringtwo
| anchoredshortskip'''
if isinstance(p[1], FixedStringLenTwo):
p[0] = [p[1]]
else:
p[0] = p[1]

def p_anchoredshortskip(p):
'''anchoredshortskip : fixedbyte fixedbyte LBRACKET number MINUS number RBRACKET fixedbyte
| fixedbyte LBRACKET number MINUS number RBRACKET fixedbyte fixedbyte'''
if p[2] == "[":
p[0] = [FixedString([p[1]]), ShortSkip(int(p[3]), int(p[5])), FixedStringLenTwo([p[7], p[8]])]
else:
p[0] = [FixedStringLenTwo([p[1], p[2]]), ShortSkip(int(p[4]), int(p[6])), FixedString([p[8]])]

def p_repexpr(p):
'''repexpr : expr
| expr repexpr'''
if len(p) == 2:
p[0] = p[1]
else:
p[0] = p[1] + p[2]

def p_expr(p):
'''expr : choice
| negatedchoice
| highnibble
| lownibble
| skipbytes
| fixedstring'''
p[0] = [p[1]]
def p_shortskip(p):
'''shortskip : LBRACKET number MINUS number RBRACKET'''
return ShortSkip(int(p[2]), int(p[4]))

def p_choice(p):
'''choice : LPAREN choiceelems RPAREN'''
Expand All @@ -90,66 +91,30 @@ def p_choiceelems(p):
p[0] = [p[1]] + p[3]

def p_choiceelem(p):
'''choiceelem : choiceexpr
| choiceexpr choiceelem'''
'''choiceelem : expr
| expr choiceelem'''
if len(p) == 2:
p[0] = p[1]
else:
p[0] = p[1] + p[2]

def p_choiceexpr(p):
'''choiceexpr : fixedstring
| expr'''
if isinstance(p[1], FixedByte) or isinstance(p[1], FixedString):
p[0] = [p[1]]
else:
p[0] = p[1]

def p_negatedchoice(p):
'''negatedchoice : NOT choice'''
p[0] = Not(p[3])

def p_hexchar(p):
'''hexchar : DIGIT
| HEXALPHA'''
p[0] = p[1]

def p_fixedbyte(p):
'''fixedbyte : hexchar hexchar'''
p[0] = FixedByte("%s%s" % (p[1], p[2]))

def p_fixedstringtwo(p):
'''fixedstringtwo : fixedbyte fixedbyte
| fixedstringtwo fixedbyte'''
if isinstance(p[1], FixedByte):
p[0] = FixedStringLenTwo([p[1], p[2]])
else:
p[0] = p[1].clone_append(p[2])

def p_fixedstring(p):
'''fixedstring : fixedbyte
| fixedstring fixedbyte'''
if len(p) == 2:
p[0] = FixedString([p[1]])
else:
p[0] = p[1].clone_append(p[2])

def p_highnibble(p):
'''highnibble : hexchar NIBBLEMASK'''
p[0] = HighNibble(p[1])

def p_lownibble_skipbyte(p):
'''lownibble_skipbyte : lownibble
| skipbyte'''
p[0] = p[1]

def p_lownibble(p):
'''lownibble : NIBBLEMASK hexchar'''
p[0] = LowNibble(p[2])

def p_skipbytes(p):
'''skipbytes : skipbyte
| skipbyte skipbytes'''
if len(p) == 2:
p[0] = p[1]
else:
p[0] = Skip(p[2].min + 1, p[2].max + 1)

def p_skipbyte(p):
'''skipbyte : NIBBLEMASK NIBBLEMASK'''
p[0] = Skip(1, 1)
Expand All @@ -166,7 +131,7 @@ def p_error(p):
parser = yacc.yacc(tabmodule = "sigtab", write_tables = False)

def parse_pattern(signature):
return parser.parse(signature, lexer = lexer)
return parser.parse(signature, lexer = lexer, debug = logging.getLogger())
#result = parser.parse("4f5c*2345{-12}ccdd((aa|f?)|bb|cc)????00")
#print(result)

0 comments on commit 2181f8b

Please sign in to comment.