diff --git a/manticore/core/cpu/x86.py b/manticore/core/cpu/x86.py index 35d0adc..4893b9e 100644 --- a/manticore/core/cpu/x86.py +++ b/manticore/core/cpu/x86.py @@ -13,7 +13,7 @@ from .abstractcpu import ( from ..smtlib import Operators, BitVec, Bool, BitVecConstant, operator, visitors -from ..memory import MemoryException +from ..memory import MemoryException, ConcretizeMemory from ...utils.helpers import issymbolic logger = logging.getLogger(__name__) @@ -597,6 +597,9 @@ class AMD64RegFile(RegisterFile): self._cache[name] = value return value + def sizeof(self, reg): + return self._table[reg].size + ########################### # Operand Wrapper class AMD64Operand(Operand): @@ -4880,6 +4883,224 @@ class X86Cpu(Cpu): # res = res | (0xff << i) op0.write(res) + ############################################################################ + # Implementation of PCMPxSTRx Instructions: + # + PCMPESTRM, PCMPESTRI, PCMPISTRM, PCMPISTRI + ## + # ''' + # See Ref: https://software.intel.com/sites/default/files/m/8/b/8/D9156103.pdf + + # :param cpu: current CPU. + # :param op0: compare oprand 1 + # :param op1: compare oprand 2 + # :param op2: control byte + # - op2[3:2] : + # + 00: Equal Any + # + 01: Ranges + # + 10: Equal Each + # + 11: Equal Ordered + # ''' + ############################################################################# + def _pcmpxstrx_srcdat_format(self, ctlbyte): + # Parse CTL Byte + ## Source Data Format + if ((Operators.EXTRACT(ctlbyte, 0, 2) & 1) == 0 ): + stepsize = 8 + else: + stepsize = 16 + return stepsize + + def _pcmpxstri_output_selection(self, ctlbyte, res): + ## Output Selection + ### PCMPESTRI/PCMPISTRI + stepsize = self._pcmpxstrx_srcdat_format(ctlbyte) + if (Operators.EXTRACT(ctlbyte, 6, 1) == 0): + oecx = 0 + tres = res + while ((tres & 1) == 0): + oecx += 1 + tres >>= 1 + return oecx + else: + oecx = 128/stepsize - 1 + tres = res + msbmask = (1 << (128/stepsize - 1)) + while ((tres & msbmask) == 0): + oecx -= 1 + tres = (tres << 1) & ((msbmask << 1) - 1) + return oecx + + def _pcmpxstrm_output_selection(self, ctlbyte, res): + ## Output Selection + ### PCMPESTRM/PCMPISTRM + if (Operators.EXTRACT(ctlbyte, 6, 1) == 0): + return res + else: + stepsize = self._pcmpxstrx_srcdat_format(ctlbyte) + xmmres = 0 + for i in range(0, 128, stepsize): + if (res&1 == 1): + xmmres |= (((1 << stepsize) - 1) << i) + res >>= 1 + return xmmres + + def _pcmpistrx_varg(self, arg, ctlbyte): + step = self._pcmpxstrx_srcdat_format(ctlbyte) + result = [] + for i in range(0, 128, step): + uc = Operators.EXTRACT(arg, i, step) + if uc == 0: + break + result.append(uc) + return result + + def _pcmpestrx_varg(self, arg, regname, ctlbyte): + reg = self.read_register(regname) + if (issymbolic(reg)): + raise ConcretizeRegister(self, regname, "Concretize PCMPESTRx ECX/EDX") + smask = 1 << (self.regfile.sizeof(regname) - 1) + step = self._pcmpxstrx_srcdat_format(ctlbyte) + if (reg & smask == 1): + val = Operators.NOT(reg - 1) + else: + val = reg + if (val > 128/step): + val = 128/step + result = [] + for i in range(val): + uc = Operators.EXTRACT(arg, i*step, step) + result.append(uc) + return result + + def _pcmpxstrx_aggregation_operation(self, varg0, varg1, ctlbyte): + ## + needle = [e for e in varg0] + haystack = [e for e in varg1] + + ## Aggregation Operation + res = 0 + stepsize = self._pcmpxstrx_srcdat_format(ctlbyte) + xmmsize = 128 + if (Operators.EXTRACT(ctlbyte, 2, 2) == 0): + #raise NotImplementedError("pcmpistrx Equal any") + for i in range(len(haystack)): + if haystack[i] in needle: + res |= (1 << i) + elif (Operators.EXTRACT(ctlbyte, 2, 2) == 1): + #raise NotImplementedError("pcmpistrx Ranges") + assert len(needle)%2 == 0 + for i in range(len(haystack)): + for j in range(0, len(needle), 2): + if haystack[i] >= needle[j] and haystack[i] <= needle[j+1]: + res |= (1 << i) + break + elif (Operators.EXTRACT(ctlbyte, 2, 2) == 2): + #raise NotImplementedError("pcmpistrx Equal each") + # Equal Each requires Null Byte Comparison Here + while len(needle) < xmmsize/stepsize: + needle.append('\x00') + while len(haystack) < xmmsize/stepsize: + haystack.append('\x00') + for i in range(xmmsize/stepsize): + res = Operators.ITEBV(xmmsize, needle[i] == haystack[i], res|(1 << i), res) + elif (Operators.EXTRACT(ctlbyte, 2, 2) == 3): + #raise NotImplementedError("pcmpistrx Equal ordered") + if len(haystack) < len(needle): + return 0 + for i in range(len(haystack)): + subneedle = needle[: (xmmsize/stepsize - i) if len(needle)+i > xmmsize/stepsize else len(needle)] + res = Operators.ITEBV(xmmsize, haystack[i:i+len(subneedle)] == subneedle, res|(1 << i), res) + return res + + def _pcmpxstrx_polarity(self, res1, ctlbyte, arg2len): + ## Polarity + stepsize = self._pcmpxstrx_srcdat_format(ctlbyte) + if (Operators.EXTRACT(ctlbyte, 4, 2) == 0): + res2 = res1 + pass + if (Operators.EXTRACT(ctlbyte, 4, 2) == 1): + res2 = ((1 << (128/stepsize)) - 1) ^ res1 + if (Operators.EXTRACT(ctlbyte, 4, 2) == 2): + res2 = res1 + pass + if (Operators.EXTRACT(ctlbyte, 4, 2) == 3): + res2 = ((1 << arg2len) - 1) ^ res1 + pass + return res2 + + def _pcmpxstrx_setflags(self, res, varg0, varg1, ctlbyte): + stepsize = self._pcmpxstrx_srcdat_format(ctlbyte) + self.ZF = len(varg1) < 128/stepsize + self.SF = len(varg0) < 128/stepsize + self.CF = res != 0 + self.OF = res & 1 + self.AF = False + self.PF = False + + def _pcmpxstrx_operands(self, op0, op1, op2): + arg0 = op0.read() + arg1 = op1.read() + ctlbyte = op2.read() + if (issymbolic(arg0)): + # XMM Register + assert op0.type == 'register' + raise ConcretizeRegister(self, op0.reg, "Concretize for PCMPXSTRX") + if (issymbolic(arg1)): + if (op1.type == 'register'): + # XMM Register + raise ConcretizeRegister(self, op1.reg, "Concretize for PCMPXSTRX") + else: + # Memory + raise ConcretizeMemory(self.memory, op1.address(), op0.size) + assert(not issymbolic(ctlbyte)) + return (arg0, arg1, ctlbyte) + + @instruction + def PCMPISTRI(cpu, op0, op1, op2): + arg0, arg1, ctlbyte = cpu._pcmpxstrx_operands(op0, op1, op2) + varg0 = cpu._pcmpistrx_varg(arg0, ctlbyte) + varg1 = cpu._pcmpistrx_varg(arg1, ctlbyte) + res = cpu._pcmpxstrx_aggregation_operation(varg0, varg1, ctlbyte) + res = cpu._pcmpxstrx_polarity(res, ctlbyte, len(varg1)) + if (res == 0): + cpu.ECX = 128/cpu._pcmpxstrx_srcdat_format(ctlbyte) + else: + cpu.ECX = cpu._pcmpxstri_output_selection(ctlbyte, res) + cpu._pcmpxstrx_setflags(res, varg0, varg1, ctlbyte) + + @instruction + def PCMPISTRM(cpu, op0, op1, op2): + arg0, arg1, ctlbyte = cpu._pcmpxstrx_operands(op0, op1, op2) + varg0 = cpu._pcmpistrx_varg(arg0, ctlbyte) + varg1 = cpu._pcmpistrx_varg(arg1, ctlbyte) + res = cpu._pcmpxstrx_aggregation_operation(varg0, varg1, ctlbyte) + res = cpu._pcmpxstrx_polarity(res, ctlbyte, len(varg1)) + cpu.XMM0 = cpu._pcmpxstrm_output_selection(ctlbyte, res) + cpu._pcmpxstrx_setflags(res, varg0, varg1, ctlbyte) + + @instruction + def PCMPESTRI(cpu, op0, op1, op2): + arg0, arg1, ctlbyte = cpu._pcmpxstrx_operands(op0, op1, op2) + varg0 = cpu._pcmpestrx_varg(arg0, 'EAX', ctlbyte) + varg1 = cpu._pcmpestrx_varg(arg1, 'EDX', ctlbyte) + res = cpu._pcmpxstrx_aggregation_operation(varg0, varg1, ctlbyte) + res = cpu._pcmpxstrx_polarity(res, ctlbyte, len(varg1)) + if (res == 0): + cpu.ECX = 128/cpu._pcmpxstrx_srcdat_format(ctlbyte) + else: + cpu.ECX = cpu._pcmpxstri_output_selection(ctlbyte, res) + cpu._pcmpxstrx_setflags(res, varg0, varg1, ctlbyte) + + @instruction + def PCMPESTRM(cpu, op0, op1, op2): + arg0, arg1, ctlbyte = cpu._pcmpxstrx_operands(op0, op1, op2) + varg0 = cpu._pcmpestrx_varg(arg0, 'EAX', ctlbyte) + varg1 = cpu._pcmpestrx_varg(arg1, 'EDX', ctlbyte) + res = cpu._pcmpxstrx_aggregation_operation(varg0, varg1, ctlbyte) + res = cpu._pcmpxstrx_polarity(res, ctlbyte, len(varg1)) + cpu.XMM0 = cpu._pcmpxstrm_output_selection(ctlbyte, res) + cpu._pcmpxstrx_setflags(res, varg0, varg1, ctlbyte) + @instruction def PMOVMSKB(cpu, op0, op1): ''' diff --git a/manticore/core/state.py b/manticore/core/state.py index 64ad78b..bad7e43 100644 --- a/manticore/core/state.py +++ b/manticore/core/state.py @@ -139,7 +139,7 @@ class State(Eventful): except ConcretizeMemory as e: expression = self.cpu.read_int(e.address, e.size) def setstate(state, value): - state.cpu.write_int(e.reg_name, value, e.size) + state.cpu.write_int(e.address, value, e.size) raise Concretize(e.message, expression=expression, setstate=setstate, diff --git a/tests/auto/make_tests.py b/tests/auto/make_tests.py index b96adcb..d2cb803 100644 --- a/tests/auto/make_tests.py +++ b/tests/auto/make_tests.py @@ -16,6 +16,8 @@ for test in tests: cnt = op_count.get(test['mnemonic'],0) if cnt > 1000: #No more than 1000 instructions of each kind continue + if test['mnemonic'] != 'PCMPISTRI' and test['mnemonic'] != 'PCMPISTRM' and test['mnemonic'] != 'PCMPESTRI' and test['mnemonic'] != 'PCMPESTRM': + continue op_count[test['mnemonic']] = cnt+1 test_dic["%s_%d"%(test['mnemonic'], op_count[test['mnemonic']])] = test except Exception,e: @@ -216,6 +218,7 @@ for test_name in sorted(test_dic.keys()): print """ cs.add(cpu.%s == 0x%x)"""%(reg_name, value) + pc_reg = 'RIP' if 'RIP' in test['pre']['registers'] else 'EIP' print """ done = False while not done: @@ -226,8 +229,27 @@ for test_name in sorted(test_dic.keys()): symbol = getattr(cpu, e.reg_name) values = solver.get_all_values(cs, symbol) self.assertEqual(len(values), 1) - setattr(cpu, e.reg_name, values[0])""" - + setattr(cpu, e.reg_name, values[0]) + setattr(cpu, '{PC}', {PC_VAL})""".format( + PC=pc_reg, + PC_VAL=hex(test['pre']['registers'][pc_reg])) + print """ + except ConcretizeMemory,e: + symbol = getattr(cpu, '{FRAME_BASE}') + if isinstance(symbol, Expression): + values = solver.get_all_values(cs, symbol) + self.assertEqual(len(values), 1) + setattr(cpu, '{FRAME_BASE}', values[0]) + for i in range(e.size): + symbol = mem[e.address+i] + if isinstance(symbol, Expression): + values = solver.get_all_values(cs, symbol) + self.assertEqual(len(values), 1) + mem[e.address+i] = values[0] + setattr(cpu, '{PC}', {PC_VAL})""".format( + FRAME_BASE='RBP' if 'RBP' in test['pre']['registers'] else 'EBP', + PC=pc_reg, + PC_VAL=hex(test['pre']['registers'][pc_reg])) print """ diff --git a/tests/auto/trace.py b/tests/auto/trace.py index b819831..85ada73 100644 --- a/tests/auto/trace.py +++ b/tests/auto/trace.py @@ -121,7 +121,7 @@ while True: pc = gdb.getR({'i386': 'EIP', 'amd64': 'RIP'}[arch]) print hex(pc) gdb.stepi() - print gdb.correspond('info registers') + print gdb.correspond('info registers\n') except Exception,e: print e print "# Processed %d instructions." % count diff --git a/tests/test_allinsts.py b/tests/test_x86.py similarity index 100% rename from tests/test_allinsts.py rename to tests/test_x86.py diff --git a/tests/test_x86_pcmpxstrx.py b/tests/test_x86_pcmpxstrx.py new file mode 100644 index 0000000..da02af1 --- /dev/null +++ b/tests/test_x86_pcmpxstrx.py @@ -0,0 +1,34249 @@ + +import unittest +import functools +from manticore.core.cpu.x86 import * +from manticore.core.smtlib import Operators +from manticore.core.memory import * + + +def skipIfNotImplemented(f): + # XXX(yan) the inner function name must start with test_ + @functools.wraps(f) + def test_inner(*args, **kwargs): + try: + return f(*args, **kwargs) + except NotImplementedError, e: + raise unittest.SkipTest(e.message) + + return test_inner + +def forAllTests(decorator): + def decorate(cls): + for attr in cls.__dict__: + if not attr.startswith('test_'): + continue + method = getattr(cls, attr) + if callable(method): + setattr(cls, attr, decorator(method)) + return cls + + return decorate + +@forAllTests(skipIfNotImplemented) +class CPUTest(unittest.TestCase): + _multiprocess_can_split_ = True + + class ROOperand(object): + ''' Mocking class for operand ronly ''' + def __init__(self, size, value): + self.size = size + self.value = value + def read(self): + return self.value & ((1<