Files
manticore/core/parser/parser.py
T
2017-02-13 12:04:15 -05:00

313 lines
7.2 KiB
Python

# Minimal INTEL assembler expression calculator
import ply.yacc as yacc
import copy,struct
from ..smtlib import Operators,Bool
#Lexer
# ------------------------------------------------------------
# calclex.py
#
# tokenizer for a simple expression evaluator for
# numbers and +,-,*,/
# ------------------------------------------------------------
import ply.lex as lex
import re
# List of token names. This is always required
tokens = (
'NUMBER',
'PLUS',
'MINUS',
'TIMES',
'DIVIDE',
'AND',
'OR',
'NEG',
'LPAREN',
'RPAREN',
'LBRAKET',
'RBRAKET',
'REGISTER',
'SEGMENT',
'COLOM',
'PTR',
'TYPE',
'RSHIFT',
'LSHIFT',
'LOR',
'LAND',
'LNOT',
'EQ',
'LT',
'LE',
'GT',
'GE',
)
# Regular expression rules for simple tokens
t_PLUS = r'\+'
t_MINUS = r'-'
t_TIMES = r'\*'
t_DIVIDE = r'/'
t_LPAREN = r'\('
t_RPAREN = r'\)'
t_LBRAKET = r'\['
t_RBRAKET = r'\]'
t_COLOM = r':'
t_AND = r'&'
t_OR = r'\|'
t_NEG = r'~'
t_LSHIFT = r'<<'
t_RSHIFT = r'>>'
t_LAND = r'&&'
t_LOR = r'\|\|'
t_LNOT = r'!'
t_EQ = r'=='
t_LT = r'<'
t_LE = r'<='
t_GT = r'>'
t_GE = r'>='
re_NUMBER = re.compile(r'^(0x[a-fA-F0-9]+|[a-fA-F0-9]+)$')
re_REGISTER = re.compile(r'^(EAX|EBX|ECX|EDX|ESI|EDI|ESP|EBP|RAX|RBX|RCX|RDX|RSI|RDI|RSP|RBP|ZF|CF|SF|EFLAGS)$')
re_SEGMENT = re.compile(r'^(SS|DS|ES|SS|CS)$')
re_TYPE = re.compile(r'^(QWORD|DWORD|WORD|BYTE)$')
re_PTR = re.compile(r'^PTR$')
# A regular expression rule with some action code
def t_TOKEN(t):
'[a-zA-Z0-9]+'
#print t.value,t.lexer.lexdata[t.lexer.lexpos-len(t.value):],re_TYPE.match(t.lexer.lexdata,t.lexer.lexpos-len(t.value))
if re_TYPE.match(t.value):
t.type='TYPE'
elif re_PTR.match(t.value):
t.type='PTR'
elif re_NUMBER.match(t.value):
if t.value.startswith('0x'):
t.value = t.value[2:]
t.value = int(t.value,16)
t.type= 'NUMBER'
elif re_REGISTER.match(t.value):
t.type= 'REGISTER'
elif re_SEGMENT.match(t.value):
t.type= 'SEGMENT'
else:
raise Exception("Unknown:<%s>"%t.value)
return t
# Define a rule so we can track line numbers
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
# A string containing ignored characters (spaces and tabs)
t_ignore = ' \t'
# Error handling rule
def t_error(t):
print "Illegal character '%s'" % t.value[0]
t.lexer.skip(1)
# Build the lexer
lexer = lex.lex()
#parser
precedence = (
('left', 'PLUS', 'MINUS'),
('left', 'DIVIDE'),
('left', 'TIMES'),
('left', 'AND', 'OR'),
('right', 'NEG'),
)
def default_read_memory(address, size):
return "READM(%08x,%d)"%(address,size)
def default_read_register(reg):
return "REG(%s)"%(reg)
def default_get_descriptor(selector):
return (0, 0xfffff000, 'rwx')
default_sizes_32 = { 'QWORD': 8,
'DWORD': 4,
'WORD': 2,
'BYTE': 1 }
default_sizes_64 = { 'QWORD': 8,
'DWORD': 4,
'WORD': 2,
'BYTE': 1 }
functions = { 'read_memory': default_read_memory,
'read_register': default_read_register,
'get_descriptor': default_get_descriptor,
}
sizes = copy.copy(default_sizes_32)
def p_expression_div(p):
'expression : expression DIVIDE expression'
p[0] = p[1] / p[3]
def p_expression_mul(p):
'expression : expression TIMES expression'
p[0] = p[1] * p[3]
def p_expression_plus(p):
'expression : expression PLUS expression'
p[0] = p[1] + p[3]
def p_expression_minus(p):
'expression : expression MINUS expression'
p[0] = p[1] - p[3]
def p_expression_and(p):
'expression : expression AND expression'
p[0] = p[1] & p[3]
def p_expression_or(p):
'expression : expression OR expression'
p[0] = p[1] | p[3]
def p_expression_neg(p):
'expression : NEG expression '
p[0] = ~p[1]
def p_expression_lshift(p):
'expression : expression LSHIFT expression'
p[0] = p[1] << p[3]
def p_expression_rshift(p):
'expression : expression RSHIFT expression'
p[0] = p[1] >> p[3]
def p_expression_deref(p):
'expression : TYPE PTR LBRAKET expression RBRAKET'
size = sizes[p[1]]
address = p[4]
char_list = functions['read_memory'](address, size)
value = Operators.CONCAT(8 * len(char_list), *reversed(map(Operators.ORD, char_list)))
p[0] = value
def p_expression_derefseg(p):
'expression : TYPE PTR SEGMENT COLOM LBRAKET expression RBRAKET'
size = sizes[p[1]]
address = p[6]
seg = functions['read_register'](p[3])
base, limit, _ = functions['get_descriptor'](seg)
address = base + address
char_list = functions['read_memory'](address, size)
value = Operators.CONCAT(8 * len(char_list), *reversed(map(Operators.ORD, char_list)))
p[0] = value
def p_expression_term(p):
'expression : term'
p[0] = p[1]
def p_factor_expr(p):
'expression : LPAREN expression RPAREN'
p[0] = p[2]
def p_term_num(p):
'term : NUMBER'
p[0] = p[1]
def p_term_reg(p):
'term : REGISTER'
p[0] = functions['read_register'](p[1])
def p_expression_eq(p):
'expression : expression EQ expression'
p[0] = p[1] == p[3]
def p_expression_land(p):
'expression : expression LAND expression'
p[0] = p[1] and p[3]
def p_expression_lor(p):
'expression : expression LOR expression'
p[0] = p[1] or p[3]
def p_expression_lnot(p):
'expression : LNOT expression'
p[0] = not p[1]
def p_expression_lt(p):
'expression : expression LT expression'
#p[0] = p[1] < p[3]
p[0] = Operators.ULT(p[1], p[3])
def p_expression_le(p):
'expression : expression LE expression'
#p[0] = p[1] <= p[3]
p[0] = Operators.ULE(p[1], p[3])
def p_expression_gt(p):
'expression : expression GT expression'
#p[0] = p[1] > p[3]
p[0] = Operators.UGT(p[1], p[3])
def p_expression_ge(p):
'expression : expression GE expression'
#p[0] = p[1] >= p[3]
p[0] = Operators.UGE(p[1], p[3])
# Error rule for syntax errors
def p_error(p):
print "Syntax error in input:",p
# Build the parser
parser = yacc.yacc(debug=0, write_tables=0)
def parse(expression,read_memory=None,read_register=None,get_descriptor=None,word_size=32):
global functions, sizes
if read_memory != None:
functions['read_memory'] = read_memory
else:
functions['read_memory'] = default_read_memory
if read_register != None:
functions['read_register'] = read_register
else:
functions['read_register'] = default_read_register
if get_descriptor != None:
functions['get_descriptor'] = get_descriptor
else:
functions['get_descriptor'] = default_get_descriptor
if word_size == 32:
sizes = copy.copy(default_sizes_32)
elif word_size == 64:
sizes = copy.copy(default_sizes_64)
else:
raise Exception ("Not Supported")
result = parser.parse(expression,tracking=True)
del functions['read_memory']
del functions['read_register']
del functions['get_descriptor']
return result
if __name__ == '__main__':
while True:
try:
s = raw_input('calc > ')
except EOFError:
break
if not s: continue
result = parse(s)
print result