def eval_exprslice(self, expr, **kwargs): """[DEV]: Evaluate an ExprSlice using the current state""" arg = self.eval_expr_visitor(expr.arg, **kwargs) if arg.is_id(TOPSTR): ret = exprid_top(expr) else: ret = ExprSlice(arg, expr.start, expr.stop) return ret
def categorize(self, node, lvl=0, **kwargs): """Recursively apply rules to @node @node: ExprNode to analyze @lvl: actual recusion level """ expr = node.expr log_reduce.debug("\t" * lvl + "Reduce...: %s", node.expr) if isinstance(expr, ExprId): node = ExprNodeId(expr) elif isinstance(expr, ExprInt): node = ExprNodeInt(expr) elif isinstance(expr, ExprLoc): node = ExprNodeLoc(expr) elif isinstance(expr, ExprMem): arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs) node = ExprNodeMem(ExprMem(arg.expr, expr.size)) node.arg = arg elif isinstance(expr, ExprSlice): arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs) node = ExprNodeSlice(ExprSlice(arg.expr, expr.start, expr.stop)) node.arg = arg elif isinstance(expr, ExprOp): new_args = [] for arg in node.args: new_a = self.categorize(arg, lvl=lvl + 1, **kwargs) assert new_a.expr.size == arg.expr.size new_args.append(new_a) node = ExprNodeOp(ExprOp(expr.op, *[x.expr for x in new_args])) node.args = new_args expr = node.expr elif isinstance(expr, ExprCompose): new_args = [] new_expr_args = [] for arg in node.args: arg = self.categorize(arg, lvl=lvl + 1, **kwargs) new_args.append(arg) new_expr_args.append(arg.expr) new_expr = ExprCompose(*new_expr_args) node = ExprNodeCompose(new_expr) node.args = new_args elif isinstance(expr, ExprCond): cond = self.categorize(node.cond, lvl=lvl + 1, **kwargs) src1 = self.categorize(node.src1, lvl=lvl + 1, **kwargs) src2 = self.categorize(node.src2, lvl=lvl + 1, **kwargs) node = ExprNodeCond(ExprCond(cond.expr, src1.expr, src2.expr)) node.cond, node.src1, node.src2 = cond, src1, src2 else: raise TypeError("Unknown Expr Type %r", type(expr)) node.info = self.apply_rules(node, lvl=lvl, **kwargs) log_reduce.debug("\t" * lvl + "Reduce result: %s %r", node.expr, node.info) return node
def simp_slice(e_s, expr): "Slice optimization" # slice(A, 0, a.size) => A if expr.start == 0 and expr.stop == expr.arg.size: return expr.arg # Slice(int) => int if expr.arg.is_int(): total_bit = expr.stop - expr.start mask = (1 << (expr.stop - expr.start)) - 1 return ExprInt(int((expr.arg.arg >> expr.start) & mask), total_bit) # Slice(Slice(A, x), y) => Slice(A, z) if expr.arg.is_slice(): if expr.stop - expr.start > expr.arg.stop - expr.arg.start: raise ValueError('slice in slice: getting more val', str(expr)) return ExprSlice(expr.arg.arg, expr.start + expr.arg.start, expr.start + expr.arg.start + (expr.stop - expr.start)) if expr.arg.is_compose(): # Slice(Compose(A), x) => Slice(A, y) for index, arg in expr.arg.iter_args(): if index <= expr.start and index+arg.size >= expr.stop: return arg[expr.start - index:expr.stop - index] # Slice(Compose(A, B, C), x) => Compose(A, B, C) with truncated A/B/C out = [] for index, arg in expr.arg.iter_args(): # arg is before slice start if expr.start >= index + arg.size: continue # arg is after slice stop elif expr.stop <= index: continue # arg is fully included in slice elif expr.start <= index and index + arg.size <= expr.stop: out.append(arg) continue # arg is truncated at start if expr.start > index: slice_start = expr.start - index else: # arg is not truncated at start slice_start = 0 # a is truncated at stop if expr.stop < index + arg.size: slice_stop = arg.size + expr.stop - (index + arg.size) - slice_start else: slice_stop = arg.size out.append(arg[slice_start:slice_stop]) return ExprCompose(*out) # ExprMem(x, size)[:A] => ExprMem(x, a) # XXXX todo hum, is it safe? if (expr.arg.is_mem() and expr.start == 0 and expr.arg.size > expr.stop and expr.stop % 8 == 0): return ExprMem(expr.arg.arg, size=expr.stop) # distributivity of slice and & # (a & int)[x:y] => 0 if int[x:y] == 0 if expr.arg.is_op("&") and expr.arg.args[-1].is_int(): tmp = e_s.expr_simp_wrapper(expr.arg.args[-1][expr.start:expr.stop]) if tmp.is_int(0): return tmp # distributivity of slice and exprcond # (a?int1:int2)[x:y] => (a?int1[x:y]:int2[x:y]) if expr.arg.is_cond() and expr.arg.src1.is_int() and expr.arg.src2.is_int(): src1 = expr.arg.src1[expr.start:expr.stop] src2 = expr.arg.src2[expr.start:expr.stop] return ExprCond(expr.arg.cond, src1, src2) # (a * int)[0:y] => (a[0:y] * int[0:y]) if expr.start == 0 and expr.arg.is_op("*") and expr.arg.args[-1].is_int(): args = [e_s.expr_simp_wrapper(a[expr.start:expr.stop]) for a in expr.arg.args] return ExprOp(expr.arg.op, *args) # (a >> int)[x:y] => a[x+int:y+int] with int+y <= a.size # (a << int)[x:y] => a[x-int:y-int] with x-int >= 0 if (expr.arg.is_op() and expr.arg.op in [">>", "<<"] and expr.arg.args[1].is_int()): arg, shift = expr.arg.args shift = int(shift) if expr.arg.op == ">>": if shift + expr.stop <= arg.size: return arg[expr.start + shift:expr.stop + shift] elif expr.arg.op == "<<": if expr.start - shift >= 0: return arg[expr.start - shift:expr.stop - shift] else: raise ValueError('Bad case') return expr
def eval_exprslice(self, expr, **kwargs): """[DEV]: Evaluate an ExprSlice using the current state""" arg = self.eval_expr_visitor(expr.arg, **kwargs) ret = ExprSlice(arg, expr.start, expr.stop) return ret
def apply_expr_on_state_visit_cache(self, expr, state, cache, level=0): """ Deep First evaluate nodes: 1. evaluate node's sons 2. simplify """ if expr in cache: ret = cache[expr] elif expr in state: return state[expr] elif expr.is_int(): ret = expr elif expr.is_id(): if isinstance(expr.name, asmblock.asm_label) and expr.name.offset is not None: ret = ExprInt(expr.name.offset, expr.size) elif expr in self.regstop: ret = exprid_top(expr) else: ret = state.get(expr, expr) elif expr.is_mem(): ret = self.manage_mem(expr, state, cache, level) elif expr.is_cond(): cond = self.apply_expr_on_state_visit_cache( expr.cond, state, cache, level + 1) src1 = self.apply_expr_on_state_visit_cache( expr.src1, state, cache, level + 1) src2 = self.apply_expr_on_state_visit_cache( expr.src2, state, cache, level + 1) if cond.is_id(TOPSTR) or src1.is_id(TOPSTR) or src2.is_id(TOPSTR): ret = exprid_top(expr) else: ret = ExprCond(cond, src1, src2) elif expr.is_slice(): arg = self.apply_expr_on_state_visit_cache(expr.arg, state, cache, level + 1) if arg.is_id(TOPSTR): ret = exprid_top(expr) else: ret = ExprSlice(arg, expr.start, expr.stop) elif expr.is_op(): args = [] for oarg in expr.args: arg = self.apply_expr_on_state_visit_cache( oarg, state, cache, level + 1) assert oarg.size == arg.size if arg.is_id(TOPSTR): return exprid_top(expr) args.append(arg) ret = ExprOp(expr.op, *args) elif expr.is_compose(): args = [] for arg in expr.args: arg = self.apply_expr_on_state_visit_cache( arg, state, cache, level + 1) if arg.is_id(TOPSTR): return exprid_top(expr) args.append(arg) ret = ExprCompose(*args) else: raise TypeError("Unknown expr type") ret = self.expr_simp(ret) assert expr.size == ret.size cache[expr] = ret return ret
expr_compose = STR_EXPRCOMPOSE + LPARENTHESIS + pyparsing.delimitedList(expr, delim=',') + RPARENTHESIS expr_op = STR_EXPROP + LPARENTHESIS + string + STR_COMMA + pyparsing.delimitedList(expr, delim=',') + RPARENTHESIS expr_aff = STR_EXPRASSIGN + LPARENTHESIS + expr + STR_COMMA + expr + RPARENTHESIS expr << (expr_int | expr_id | expr_loc | expr_slice | expr_mem | expr_cond | \ expr_compose | expr_op | expr_aff) def parse_loc_key(t): assert len(t) == 2 loc_key, size = LocKey(t[0]), t[1] return ExprLoc(loc_key, size) expr_int.setParseAction(lambda t: ExprInt(*t)) expr_id.setParseAction(lambda t: ExprId(*t)) expr_loc.setParseAction(parse_loc_key) expr_slice.setParseAction(lambda t: ExprSlice(*t)) expr_mem.setParseAction(lambda t: ExprMem(*t)) expr_cond.setParseAction(lambda t: ExprCond(*t)) expr_compose.setParseAction(lambda t: ExprCompose(*t)) expr_op.setParseAction(lambda t: ExprOp(*t)) expr_aff.setParseAction(lambda t: ExprAssign(*t)) def str_to_expr(str_in): """Parse the @str_in and return the corresponoding Expression @str_in: repr string of an Expression""" try: value = expr.parseString(str_in) except: raise RuntimeError("Cannot parse expression %s" % str_in)
from miasm2.expression.parser import str_to_expr from miasm2.expression.expression import ExprInt, ExprId, ExprSlice, ExprMem, \ ExprCond, ExprCompose, ExprOp, ExprAff, ExprLoc, LocKey for expr_test in [ ExprInt(0x12, 32), ExprId('test', 32), ExprLoc(LocKey(12), 32), ExprSlice(ExprInt(0x10, 32), 0, 8), ExprMem(ExprInt(0x10, 32), 32), ExprCond(ExprInt(0x10, 32), ExprInt(0x11, 32), ExprInt(0x12, 32)), ExprCompose(ExprInt(0x10, 16), ExprInt(0x11, 8), ExprInt(0x12, 8)), ExprInt(0x11, 8) + ExprInt(0x12, 8), ExprAff(ExprId('EAX', 32), ExprInt(0x12, 32)), ]: print 'Test: %s' % expr_test assert str_to_expr(repr(expr_test)) == expr_test