diff --git a/core/cpu/x86.py b/core/cpu/x86.py index 65389cb..60029f1 100644 --- a/core/cpu/x86.py +++ b/core/cpu/x86.py @@ -144,9 +144,17 @@ def repe(old_method): #register/flag descriptors class AMD64RegFile(RegisterFile): Regspec = collections.namedtuple('RegSpec', 'register_id ty offset size reset') + _flags = { + 'CF': 0, + 'PF': 2, + 'AF': 4, + 'ZF': 6, + 'SF': 7, + 'IF': 9, + 'DF': 10, + 'OF': 11 + } _table = { - 'RFLAGS': Regspec('RFLAGS', int, 0, 64, False), - 'EFLAGS': Regspec('RFLAGS', int, 0, 32, False), 'CS': Regspec('CS', int, 0, 16, False), 'DS': Regspec('DS', int, 0, 16, False), 'ES': Regspec('ES', int, 0, 16, False), @@ -248,14 +256,14 @@ class AMD64RegFile(RegisterFile): 'TOP' : Regspec('FPSW', int, 11, 3, False), 'FPTAG': Regspec('FPTAG', int, 0, 16, False), 'FPCW': Regspec('FPCW', int, 0, 16, False), - 'CF': Regspec('RFLAGS', bool, 0, 1, False), - 'PF': Regspec('RFLAGS', bool, 2, 1, False), - 'AF': Regspec('RFLAGS', bool, 4, 1, False), - 'ZF': Regspec('RFLAGS', bool, 6, 1, False), - 'SF': Regspec('RFLAGS', bool, 7, 1, False), - 'IF': Regspec('RFLAGS', bool, 9, 1, False), - 'DF': Regspec('RFLAGS', bool, 10, 1, False), - 'OF': Regspec('RFLAGS', bool, 11, 1, False), + 'CF': Regspec('CF', bool, 0, 1, False), + 'PF': Regspec('PF', bool, 0, 1, False), + 'AF': Regspec('AF', bool, 0, 1, False), + 'ZF': Regspec('ZF', bool, 0, 1, False), + 'SF': Regspec('SF', bool, 0, 1, False), + 'IF': Regspec('IF', bool, 0, 1, False), + 'DF': Regspec('DF', bool, 0, 1, False), + 'OF': Regspec('OF', bool, 0, 1, False), 'YMM0': Regspec('YMM0', int, 0, 256, False), 'YMM1': Regspec('YMM1', int, 0, 256, False), 'YMM2': Regspec('YMM2', int, 0, 256, False), @@ -341,16 +349,16 @@ class AMD64RegFile(RegisterFile): 'FS' : () , 'GS' : () , 'SS' : () , - 'RFLAGS' : ('AF', 'CF', 'DF', 'EFLAGS', 'IF', 'OF', 'PF', 'SF', 'ZF') , - 'EFLAGS' : ('AF', 'CF', 'DF', 'IF', 'OF', 'PF', 'RFLAGS', 'SF', 'ZF') , - 'AF': ('EFLAGS', 'RFLAGS') , - 'CF' : ('EFLAGS', 'RFLAGS') , - 'DF' : ('EFLAGS', 'RFLAGS') , - 'IF' : ('EFLAGS', 'RFLAGS') , - 'OF' : ('EFLAGS', 'RFLAGS') , - 'PF' : ('EFLAGS', 'RFLAGS') , - 'SF' : ('EFLAGS', 'RFLAGS') , - 'ZF' : ('EFLAGS', 'RFLAGS') , + 'RFLAGS' : ('EFLAGS', 'AF', 'CF', 'DF', 'IF', 'OF', 'PF', 'SF', 'ZF') , + 'EFLAGS' : ('RFLAGS', 'AF', 'CF', 'DF', 'IF', 'OF', 'PF', 'SF', 'ZF') , + 'AF' : ('RFLAGS', 'EFLAGS') , + 'CF' : ('RFLAGS', 'EFLAGS') , + 'DF' : ('RFLAGS', 'EFLAGS') , + 'IF' : ('RFLAGS', 'EFLAGS') , + 'OF' : ('RFLAGS', 'EFLAGS') , + 'PF' : ('RFLAGS', 'EFLAGS') , + 'SF' : ('RFLAGS', 'EFLAGS') , + 'ZF' : ('RFLAGS', 'EFLAGS') , 'FPSW' : ('TOP',) , 'TOP' : ('FPSW',) , 'FPCW' : () , @@ -453,7 +461,7 @@ class AMD64RegFile(RegisterFile): 'YMM0', 'YMM1', 'YMM2', 'YMM3', 'YMM4', 'YMM5', 'YMM6', 'YMM7', 'YMM8', 'YMM9', 'YMM10', 'YMM11', 'YMM12', 'YMM13', 'YMM14', 'YMM15', 'CS','DS','ES','SS', 'FS', 'GS', - 'RFLAGS'): + 'AF', 'CF', 'DF', 'IF', 'OF', 'PF', 'SF', 'ZF'): self._registers[reg] = 0 for reg in ('FP0', 'FP1', 'FP2', 'FP3', 'FP4', 'FP5', 'FP6', 'FP7'): @@ -463,7 +471,7 @@ class AMD64RegFile(RegisterFile): self._registers[reg] = 0 self._cache = {} for name in ('AF', 'CF', 'DF', 'IF', 'OF', 'PF', 'SF', 'ZF'): - self.write(name, 0) + self.write(name, False) def reg_name(self, reg_id): return reg_id @@ -473,9 +481,8 @@ class AMD64RegFile(RegisterFile): @property def all_registers(self): - return tuple( self._table.keys() + - ['FP0', 'FP1', 'FP2', 'FP3', 'FP4', 'FP5', 'FP6', 'FP7'] + - self._aliases.keys() ) + return tuple( self._table.keys() + + ['FP0', 'FP1', 'FP2', 'FP3', 'FP4', 'FP5', 'FP6', 'FP7'] + ['EFLAGS', 'RFLAGS'] + self._aliases.keys() ) @property def canonical_registers(self): @@ -522,15 +529,12 @@ class AMD64RegFile(RegisterFile): raise TypeError if not isinstance(value, (bool, Bool)): value = (value != 0) - new_value = self._registers[register_id] & (~(1<= offset+size typed_setter = {int: self._set_bv, bool: self._set_flag, float: self._set_float}[ty] value = typed_setter(register_id, register_size, offset, size, reset, value) + self._update_cache(name, value) + return value + + def _update_cache(self,name, value): self._cache[name] = value for affected in self._affects[name]: assert affected != name self._cache.pop(affected, None) - return value def read(self, reg_id): name = self.reg_name(reg_id) if name in ('ST0', 'ST1', 'ST2', 'ST3', 'ST4', 'ST5', 'ST6', 'ST7'): name = 'FP%d' % ((self.read('TOP') + int(name[2]) ) & 7) - if name in self._cache: return self._cache[name] + if 'FLAGS' in name: + value = self._get_flags(name) + self._cache[name] = value + return value register_id, ty, offset, size, reset = self._table[name] if register_id != name: register_size = self._table[register_id].size @@ -582,6 +625,7 @@ class AMD64RegFile(RegisterFile): assert register_size >= offset+size typed_getter = {int: self._get_bv, bool: self._get_flag, float: self._get_float}[ty] value = typed_getter(register_id, register_size, offset, size) + self._cache[name] = value return value ########################### @@ -778,9 +822,9 @@ class X86Cpu(Cpu): else: # TODO: only concretize registers the instruction touches if cpu.mode == CS_MODE_64: - regs = ('RAX', 'RCX', 'RDX', 'RBX', 'RSP', 'RBP', 'RSI', 'RDI', 'R8', 'R9', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15', 'RIP', 'EFLAGS', 'YMM0', 'YMM1', 'YMM2', 'YMM3', 'YMM4', 'YMM5', 'YMM6', 'YMM7', 'YMM8', 'YMM9', 'YMM10', 'YMM11', 'YMM12', 'YMM13', 'YMM14', 'YMM15') + regs = ('RAX', 'RCX', 'RDX', 'RBX', 'RSP', 'RBP', 'RSI', 'RDI', 'R8', 'R9', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15', 'RIP', 'YMM0', 'YMM1', 'YMM2', 'YMM3', 'YMM4', 'YMM5', 'YMM6', 'YMM7', 'YMM8', 'YMM9', 'YMM10', 'YMM11', 'YMM12', 'YMM13', 'YMM14', 'YMM15') else: - regs = ('EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI', 'EIP', 'EFLAGS', 'XMM0', 'XMM1', 'XMM2', 'XMM3', 'XMM4', 'XMM5', 'XMM6', 'XMM7') + regs = ('EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI', 'EIP', 'XMM0', 'XMM1', 'XMM2', 'XMM3', 'XMM4', 'XMM5', 'XMM6', 'XMM7') regs += ('FPSW', 'FPCW', 'FPTAG', 'FP0', 'FP1', 'FP2', 'FP3', 'FP4', 'FP5', 'FP6', 'FP7') @@ -2574,9 +2618,7 @@ class X86Cpu(Cpu): @param src: source operand. ''' - # TODO(yan): Add an interface to query a register's size, or hard-code - # 32 below. - eflags_size = cpu.regfile._table['EFLAGS'].size + eflags_size = 32 val = cpu.AH & 0xD5 | 0x02 cpu.EFLAGS = Operators.ZEXTEND(val, eflags_size) diff --git a/core/smtlib/expression.py b/core/smtlib/expression.py index e60306f..eda8d10 100644 --- a/core/smtlib/expression.py +++ b/core/smtlib/expression.py @@ -354,7 +354,7 @@ class BitVec(Expression): return BitVecArithmeticShiftLeft(self, self.cast(other)) def Bool(self): - return BoolVariable(self != 0) + return self != 0 class BitVecVariable(BitVec, Variable): def __init__(self, *args, **kwargs): diff --git a/test/test_cpu_manual.py b/test/test_cpu_manual.py index f89cbbe..ff40f0a 100644 --- a/test/test_cpu_manual.py +++ b/test/test_cpu_manual.py @@ -20,6 +20,27 @@ class RWOperand(ROOperand): sizes = {'RAX': 64, 'EAX': 32, 'AX': 16, 'AL': 8, 'AH': 8, 'RCX': 64, 'ECX': 32, 'CX': 16, 'CL': 8, 'CH': 8, 'RDX': 64, 'EDX': 32, 'DX': 16, 'DL': 8, 'DH': 8, 'RBX': 64, 'EBX': 32, 'BX': 16, 'BL': 8, 'BH': 8, 'RSP': 64, 'ESP': 32, 'SP': 16, 'SPL': 8, 'RBP': 64, 'EBP': 32, 'BP': 16, 'BPL': 8, 'RSI': 64, 'ESI': 32, 'SI': 16, 'SIL': 8, 'RDI': 64, 'EDI': 32, 'DI': 16, 'DIL': 8, 'R8': 64, 'R8D': 32, 'R8W': 16, 'R8B': 8, 'R9': 64, 'R9D': 32, 'R9W': 16, 'R9B': 8, 'R10': 64, 'R10D': 32, 'R10W': 16, 'R10B': 8, 'R11': 64, 'R11D': 32, 'R11W': 16, 'R11B': 8, 'R12': 64, 'R12D': 32, 'R12W': 16, 'R12B': 8, 'R13': 64, 'R13D': 32, 'R13W': 16, 'R13B': 8, 'R14': 64, 'R14D': 32, 'R14W': 16, 'R14B': 8, 'R15': 64, 'R15D': 32, 'R15W': 16, 'R15B': 8, 'ES': 16, 'CS': 16, 'SS': 16, 'DS': 16, 'FS': 16, 'GS': 16, 'RIP': 64, 'EIP':32, 'IP': 16, 'RFLAGS': 64, 'EFLAGS': 32, 'FLAGS': 16, 'XMM0': 128, 'XMM1': 128, 'XMM2': 128, 'XMM3': 128, 'XMM4': 128, 'XMM5': 128, 'XMM6': 128, 'XMM7': 128, 'XMM8': 128, 'XMM9': 128, 'XMM10': 128, 'XMM11': 128, 'XMM12': 128, 'XMM13': 128, 'XMM14': 128, 'XMM15': 128, 'YMM0': 256, 'YMM1': 256, 'YMM2': 256, 'YMM3': 256, 'YMM4': 256, 'YMM5': 256, 'YMM6': 256, 'YMM7': 256, 'YMM8': 256, 'YMM9': 256, 'YMM10': 256, 'YMM11': 256, 'YMM12': 256, 'YMM13': 256, 'YMM14': 256, 'YMM15': 256} class SymCPUTest(unittest.TestCase): + _flag_offsets = { + 'CF': 0, + 'PF': 2, + 'AF': 4, + 'ZF': 6, + 'SF': 7, + 'IF': 9, + 'DF': 10, + 'OF': 11, + } + + _flags={ + 'CF': 0x00001, + 'PF': 0x00004, + 'AF': 0x00010, + 'ZF': 0x00040, + 'SF': 0x00080, + 'DF': 0x00400, + 'OF': 0x00800, + 'IF': 0x00200,} + class ROOperand(object): ''' Mocking class for operand ronly ''' def __init__(self, size, value): @@ -85,15 +106,6 @@ class SymCPUTest(unittest.TestCase): def testFlagAccess(self): - _flags={ - 'CF': 0x00001, - 'PF': 0x00004, - 'AF': 0x00010, - 'ZF': 0x00040, - 'SF': 0x00080, - 'DF': 0x00400, - 'OF': 0x00800, - 'IF': 0x00200,} cpu = self.cpu cpu.RFLAGS = 0 @@ -107,88 +119,174 @@ class SymCPUTest(unittest.TestCase): #flag to register CF cpu.CF = True - self.assertTrue( cpu.RFLAGS&_flags['CF'] !=0) + self.assertTrue( cpu.RFLAGS&self._flags['CF'] !=0) cpu.CF = False - self.assertTrue( cpu.RFLAGS&_flags['CF'] ==0) + self.assertTrue( cpu.RFLAGS&self._flags['CF'] ==0) #register to flag CF - cpu.RFLAGS |= _flags['CF'] + cpu.RFLAGS |= self._flags['CF'] self.assertTrue(cpu.CF) - cpu.RFLAGS &= ~_flags['CF'] + cpu.RFLAGS &= ~self._flags['CF'] self.assertFalse(cpu.CF) #flag to register PF cpu.PF = True - self.assertTrue( cpu.RFLAGS&_flags['PF'] !=0) + self.assertTrue( cpu.RFLAGS&self._flags['PF'] !=0) cpu.PF = False - self.assertTrue( cpu.RFLAGS&_flags['PF'] ==0) + self.assertTrue( cpu.RFLAGS&self._flags['PF'] ==0) #register to flag PF - cpu.RFLAGS |= _flags['PF'] + cpu.RFLAGS |= self._flags['PF'] self.assertTrue(cpu.PF) - cpu.RFLAGS &= ~_flags['PF'] + cpu.RFLAGS &= ~self._flags['PF'] self.assertFalse(cpu.PF) #flag to register AF cpu.AF = True - self.assertTrue( cpu.RFLAGS&_flags['AF'] !=0) + self.assertTrue( cpu.RFLAGS&self._flags['AF'] !=0) cpu.AF = False - self.assertTrue( cpu.RFLAGS&_flags['AF'] ==0) + self.assertTrue( cpu.RFLAGS&self._flags['AF'] ==0) #register to flag AF - cpu.RFLAGS |= _flags['AF'] + cpu.RFLAGS |= self._flags['AF'] self.assertTrue(cpu.AF) - cpu.RFLAGS &= ~_flags['AF'] + cpu.RFLAGS &= ~self._flags['AF'] self.assertFalse(cpu.AF) #flag to register ZF cpu.ZF = True - self.assertTrue( (cpu.RFLAGS&_flags['ZF']) !=0) + self.assertTrue( (cpu.RFLAGS&self._flags['ZF']) !=0) cpu.ZF = False - self.assertTrue( cpu.RFLAGS&_flags['ZF'] ==0) + self.assertTrue( cpu.RFLAGS&self._flags['ZF'] ==0) #register to flag ZF - cpu.RFLAGS |= _flags['ZF'] + cpu.RFLAGS |= self._flags['ZF'] self.assertTrue(cpu.ZF) - cpu.RFLAGS &= ~_flags['ZF'] + cpu.RFLAGS &= ~self._flags['ZF'] self.assertFalse(cpu.ZF) #flag to register SF cpu.SF = True - self.assertTrue( cpu.RFLAGS&_flags['SF'] !=0) + self.assertTrue( cpu.RFLAGS&self._flags['SF'] !=0) cpu.SF = False - self.assertTrue( cpu.RFLAGS&_flags['SF'] ==0) + self.assertTrue( cpu.RFLAGS&self._flags['SF'] ==0) #register to flag SF - cpu.RFLAGS |= _flags['SF'] + cpu.RFLAGS |= self._flags['SF'] self.assertTrue(cpu.SF) - cpu.RFLAGS &= ~_flags['SF'] + cpu.RFLAGS &= ~self._flags['SF'] self.assertFalse(cpu.SF) #flag to register DF cpu.DF = True - self.assertTrue( cpu.RFLAGS&_flags['DF'] !=0) + self.assertTrue( cpu.RFLAGS&self._flags['DF'] !=0) cpu.DF = False - self.assertTrue( cpu.RFLAGS&_flags['DF'] ==0) + self.assertTrue( cpu.RFLAGS&self._flags['DF'] ==0) #register to flag DF - cpu.RFLAGS |= _flags['DF'] + cpu.RFLAGS |= self._flags['DF'] self.assertTrue(cpu.DF) - cpu.RFLAGS &= ~_flags['DF'] + cpu.RFLAGS &= ~self._flags['DF'] self.assertFalse(cpu.DF) #flag to register OF cpu.OF = True - self.assertTrue( cpu.RFLAGS&_flags['OF'] !=0) + self.assertTrue( cpu.RFLAGS&self._flags['OF'] !=0) cpu.OF = False - self.assertTrue( cpu.RFLAGS&_flags['OF'] ==0) + self.assertTrue( cpu.RFLAGS&self._flags['OF'] ==0) #register to flag - cpu.RFLAGS |= _flags['OF'] + cpu.RFLAGS |= self._flags['OF'] self.assertTrue(cpu.OF) - cpu.RFLAGS &= ~_flags['OF'] + cpu.RFLAGS &= ~self._flags['OF'] self.assertFalse(cpu.OF) + def _check_flags_CPAZSIDO(self, c, p, a, z, s, i, d, o): + self.assertEqual(self.cpu.CF, c) + self.assertEqual(self.cpu.PF, p) + self.assertEqual(self.cpu.AF, a) + self.assertEqual(self.cpu.ZF, z) + self.assertEqual(self.cpu.SF, s) + self.assertEqual(self.cpu.IF, i) + self.assertEqual(self.cpu.DF, d) + self.assertEqual(self.cpu.OF, o) + + def _construct_flag_bitfield(self, flags): + return reduce(operator.or_, (self._flags[f] for f in flags)) + + def _construct_sym_flag_bitfield(self, flags): + return reduce(operator.or_, (BitVecConstant(32, self._flags[f]) for f in flags)) + + def test_set_eflags(self): + self.assertEqual(self.cpu.EFLAGS, 0) + + flags = ['CF', 'PF', 'AF', 'ZF', 'SF'] + self.cpu.EFLAGS = self._construct_flag_bitfield(flags) + + self._check_flags_CPAZSIDO(1, 1, 1, 1, 1, 0, 0, 0) + + def test_get_eflags(self): + self.assertEqual(self.cpu.EFLAGS, 0) + + flags = ['CF', 'AF', 'SF'] + self.cpu.CF = 1 + self.cpu.AF = 1 + self.cpu.SF = 1 + self.cpu.DF = 0 + + self.assertEqual(self.cpu.EFLAGS, self._construct_flag_bitfield(flags)) + + def test_set_sym_eflags(self): + def check_flag(obj, flag): + equal = obj.operands[0] + extract = equal.operands[0] + assert isinstance(obj, Bool) + assert extract.begining == self._flag_offsets[flag] + assert extract.end == extract.begining + + flags = ['CF', 'PF', 'AF', 'ZF'] + sym_bitfield = self._construct_sym_flag_bitfield(flags) + self.cpu.EFLAGS = sym_bitfield + + check_flag(self.cpu.CF, 'CF') + check_flag(self.cpu.PF, 'PF') + check_flag(self.cpu.AF, 'AF') + check_flag(self.cpu.ZF, 'ZF') + + def test_get_sym_eflags(self): + def flatten_ors(x): + ''' + Retrieve all nodes of a BitVecOr expression tree + ''' + assert isinstance(x, BitVecOr) + if any(isinstance(op, BitVecOr) for op in x.operands): + ret = [] + for op in x.operands: + if isinstance(op, BitVecOr): + ret += flatten_ors(op) + else: + ret.append(op) + return ret + else: + return list(x.operands) + + self.cpu.CF = 1 + self.cpu.AF = 1 + + a = BitVecConstant(32, 1).Bool() + b = BitVecConstant(32, 0).Bool() + self.cpu.ZF = a + self.cpu.SF = b + + flags = flatten_ors(self.cpu.EFLAGS) + + self.assertTrue(isinstance(self.cpu.EFLAGS, BitVecOr)) + self.assertEqual(len(flags), 8) + + self.assertEqual(self.cpu.CF, 1) + self.assertEqual(self.cpu.AF, 1) + self.assertIs(self.cpu.ZF, a) + self.assertIs(self.cpu.SF, b) def testRegisterAccess(self): cpu = self.cpu