def MOVSS(cpu, dest, src):
        """
        Moves a scalar single-precision floating-point value

        Moves a scalar single-precision floating-point value from the source operand (second operand)
        to the destination operand (first operand). The source and destination operands can be XMM
        registers or 32-bit memory locations. This instruction can be used to move a single-precision
        floating-point value to and from the low doubleword of an XMM register and a 32-bit memory
        location, or to move a single-precision floating-point value between the low doublewords of
        two XMM registers. The instruction cannot be used to transfer data between memory locations.
        When the source and destination operands are XMM registers, the three high-order doublewords of the
        destination operand remain unchanged. When the source operand is a memory location and destination
        operand is an XMM registers, the three high-order doublewords of the destination operand are cleared to all 0s.

        //MOVSS instruction when source and destination operands are XMM registers:
        if(IsXMM(Source) && IsXMM(Destination))
            Destination[0..31] = Source[0..31];
            //Destination[32..127] remains unchanged
            //MOVSS instruction when source operand is XMM register and destination operand is memory location:
        else if(IsXMM(Source) && IsMemory(Destination))
            Destination = Source[0..31];
        //MOVSS instruction when source operand is memory location and destination operand is XMM register:
        else {
                Destination[0..31] = Source;
                Destination[32..127] = 0;
        }
        """
        if dest.type == 'register' and src.type == 'register':
            assert dest.size == 128 and src.size == 128
            dest.write(dest.read() & ~0xffffffff | src.read() & 0xffffffff)
        elif dest.type == 'memory':
            assert src.type == 'register'
            dest.write(Operators.EXTRACT(src.read(), 0, dest.size))
        else:
            assert src.type == 'memory' and dest.type == 'register'
            assert src.size == 32 and dest.size == 128
            dest.write(Operators.ZEXTEND(src.read(), 128))

def MOVSS ( cpu , dest , src ) : if dest . type == 'register' and src . type == 'register' : assert dest . size == 128 and src . size == 128 dest . write ( dest . read ( ) & ~ 0xffffffff | src . read ( ) & 0xffffffff ) elif dest . type == 'memory' : assert src . type == 'register' dest . write ( Operators . EXTRACT ( src . read ( ) , 0 , dest . size ) ) else : assert src . type == 'memory' and dest . type == 'register' assert src . size == 32 and dest . size == 128 dest . write ( Operators . ZEXTEND ( src . read ( ) , 128 ) )

Moves a scalar single - precision floating - point value


def VEXTRACTF128(cpu, dest, src, offset):
        """Extract Packed Floating-Point Values

        Extracts 128-bits of packed floating-point values from the source
        operand (second operand) at an 128-bit offset from imm8[0] into the
        destination operand (first operand). The destination may be either an
        XMM register or an 128-bit memory location.
        """
        offset = offset.read()
        dest.write(Operators.EXTRACT(src.read(), offset * 128, (offset + 1) * 128))

def VEXTRACTF128 ( cpu , dest , src , offset ) : offset = offset . read ( ) dest . write ( Operators . EXTRACT ( src . read ( ) , offset * 128 , ( offset + 1 ) * 128 ) )


def PSRLQ(cpu, dest, src):
        """Shift Packed Data Right Logical

        Shifts the bits in the individual quadword in the destination operand to the right by
        the number of bits specified in the count operand . As the bits in the data elements
        are shifted right, the empty high-order bits are cleared (set to 0). If the value
        specified by the count operand is greater than  63, then the destination operand is set
        to all 0s.

        if(OperandSize == 64) {
                        //PSRLQ instruction with 64-bit operand:
                        if(Count > 63) Destination[64..0] = 0;
                        else Destination = ZeroExtend(Destination >> Count);
                }
                else {
                        //PSRLQ instruction with 128-bit operand:
                        if(Count > 15) Destination[128..0] = 0;
                        else {
                                Destination[0..63] = ZeroExtend(Destination[0..63] >> Count);
                                Destination[64..127] = ZeroExtend(Destination[64..127] >> Count);
                        }
                }
        """

        count = src.read()
        count = Operators.ITEBV(src.size, Operators.UGT(count, 63), 64, count)
        count = Operators.EXTRACT(count, 0, 64)
        if dest.size == 64:
            dest.write(dest.read() >> count)
        else:
            hi = Operators.EXTRACT(dest.read(), 64, 64) >> count
            low = Operators.EXTRACT(dest.read(), 0, 64) >> count
            dest.write(Operators.CONCAT(128, hi, low))

def PSRLQ ( cpu , dest , src ) : count = src . read ( ) count = Operators . ITEBV ( src . size , Operators . UGT ( count , 63 ) , 64 , count ) count = Operators . EXTRACT ( count , 0 , 64 ) if dest . size == 64 : dest . write ( dest . read ( ) >> count ) else : hi = Operators . EXTRACT ( dest . read ( ) , 64 , 64 ) >> count low = Operators . EXTRACT ( dest . read ( ) , 0 , 64 ) >> count dest . write ( Operators . CONCAT ( 128 , hi , low ) )


def constrain(self, constraint):
        """Constrain state.

        :param manticore.core.smtlib.Bool constraint: Constraint to add
        """
        constraint = self.migrate_expression(constraint)
        self._constraints.add(constraint)

def constrain ( self , constraint ) : constraint = self . migrate_expression ( constraint ) self . _constraints . add ( constraint )


def new_symbolic_buffer(self, nbytes, **options):
        """Create and return a symbolic buffer of length `nbytes`. The buffer is
        not written into State's memory; write it to the state's memory to
        introduce it into the program state.

        :param int nbytes: Length of the new buffer
        :param str label: (keyword arg only) The label to assign to the buffer
        :param bool cstring: (keyword arg only) Whether or not to enforce that the buffer is a cstring
                 (i.e. no NULL bytes, except for the last byte). (bool)
        :param taint: Taint identifier of the new buffer
        :type taint: tuple or frozenset

        :return: :class:`~manticore.core.smtlib.expression.Expression` representing the buffer.
        """
        label = options.get('label')
        avoid_collisions = False
        if label is None:
            label = 'buffer'
            avoid_collisions = True
        taint = options.get('taint', frozenset())
        expr = self._constraints.new_array(name=label, index_max=nbytes, value_bits=8, taint=taint, avoid_collisions=avoid_collisions)
        self._input_symbols.append(expr)

        if options.get('cstring', False):
            for i in range(nbytes - 1):
                self._constraints.add(expr[i] != 0)

        return expr

def new_symbolic_buffer ( self , nbytes , ** options ) : label = options . get ( 'label' ) avoid_collisions = False if label is None : label = 'buffer' avoid_collisions = True taint = options . get ( 'taint' , frozenset ( ) ) expr = self . _constraints . new_array ( name = label , index_max = nbytes , value_bits = 8 , taint = taint , avoid_collisions = avoid_collisions ) self . _input_symbols . append ( expr ) if options . get ( 'cstring' , False ) : for i in range ( nbytes - 1 ) : self . _constraints . add ( expr [ i ] != 0 ) return expr

Create and return a symbolic buffer of length nbytes . The buffer is not written into State s memory ; write it to the state s memory to introduce it into the program state .


def new_symbolic_value(self, nbits, label=None, taint=frozenset()):
        """Create and return a symbolic value that is `nbits` bits wide. Assign
        the value to a register or write it into the address space to introduce
        it into the program state.

        :param int nbits: The bitwidth of the value returned
        :param str label: The label to assign to the value
        :param taint: Taint identifier of this value
        :type taint: tuple or frozenset
        :return: :class:`~manticore.core.smtlib.expression.Expression` representing the value
        """
        assert nbits in (1, 4, 8, 16, 32, 64, 128, 256)
        avoid_collisions = False
        if label is None:
            label = 'val'
            avoid_collisions = True

        expr = self._constraints.new_bitvec(nbits, name=label, taint=taint, avoid_collisions=avoid_collisions)
        self._input_symbols.append(expr)
        return expr

def new_symbolic_value ( self , nbits , label = None , taint = frozenset ( ) ) : assert nbits in ( 1 , 4 , 8 , 16 , 32 , 64 , 128 , 256 ) avoid_collisions = False if label is None : label = 'val' avoid_collisions = True expr = self . _constraints . new_bitvec ( nbits , name = label , taint = taint , avoid_collisions = avoid_collisions ) self . _input_symbols . append ( expr ) return expr

Create and return a symbolic value that is nbits bits wide . Assign the value to a register or write it into the address space to introduce it into the program state .


def concretize(self, symbolic, policy, maxcount=7):
        """ This finds a set of solutions for symbolic using policy.
            This raises TooManySolutions if more solutions than maxcount
        """
        assert self.constraints == self.platform.constraints
        symbolic = self.migrate_expression(symbolic)

        vals = []
        if policy == 'MINMAX':
            vals = self._solver.minmax(self._constraints, symbolic)
        elif policy == 'MAX':
            vals = self._solver.max(self._constraints, symbolic)
        elif policy == 'MIN':
            vals = self._solver.min(self._constraints, symbolic)
        elif policy == 'SAMPLED':
            m, M = self._solver.minmax(self._constraints, symbolic)
            vals += [m, M]
            if M - m > 3:
                if self._solver.can_be_true(self._constraints, symbolic == (m + M) // 2):
                    vals.append((m + M) // 2)
            if M - m > 100:
                for i in (0, 1, 2, 5, 32, 64, 128, 320):
                    if self._solver.can_be_true(self._constraints, symbolic == m + i):
                        vals.append(m + i)
                    if maxcount <= len(vals):
                        break
            if M - m > 1000 and maxcount > len(vals):
                vals += self._solver.get_all_values(self._constraints, symbolic,
                                                    maxcnt=maxcount - len(vals), silent=True)
        elif policy == 'ONE':
            vals = [self._solver.get_value(self._constraints, symbolic)]
        else:
            assert policy == 'ALL'
            vals = solver.get_all_values(self._constraints, symbolic, maxcnt=maxcount, silent=True)

        return tuple(set(vals))

def concretize ( self , symbolic , policy , maxcount = 7 ) : assert self . constraints == self . platform . constraints symbolic = self . migrate_expression ( symbolic ) vals = [ ] if policy == 'MINMAX' : vals = self . _solver . minmax ( self . _constraints , symbolic ) elif policy == 'MAX' : vals = self . _solver . max ( self . _constraints , symbolic ) elif policy == 'MIN' : vals = self . _solver . min ( self . _constraints , symbolic ) elif policy == 'SAMPLED' : m , M = self . _solver . minmax ( self . _constraints , symbolic ) vals += [ m , M ] if M - m > 3 : if self . _solver . can_be_true ( self . _constraints , symbolic == ( m + M ) // 2 ) : vals . append ( ( m + M ) // 2 ) if M - m > 100 : for i in ( 0 , 1 , 2 , 5 , 32 , 64 , 128 , 320 ) : if self . _solver . can_be_true ( self . _constraints , symbolic == m + i ) : vals . append ( m + i ) if maxcount <= len ( vals ) : break if M - m > 1000 and maxcount > len ( vals ) : vals += self . _solver . get_all_values ( self . _constraints , symbolic , maxcnt = maxcount - len ( vals ) , silent = True ) elif policy == 'ONE' : vals = [ self . _solver . get_value ( self . _constraints , symbolic ) ] else : assert policy == 'ALL' vals = solver . get_all_values ( self . _constraints , symbolic , maxcnt = maxcount , silent = True ) return tuple ( set ( vals ) )

This finds a set of solutions for symbolic using policy . This raises TooManySolutions if more solutions than maxcount


def solve_buffer(self, addr, nbytes, constrain=False):
        """
        Reads `nbytes` of symbolic data from a buffer in memory at `addr` and attempts to
        concretize it

        :param int address: Address of buffer to concretize
        :param int nbytes: Size of buffer to concretize
        :param bool constrain: If True, constrain the buffer to the concretized value
        :return: Concrete contents of buffer
        :rtype: list[int]
        """
        buffer = self.cpu.read_bytes(addr, nbytes)
        result = []
        with self._constraints as temp_cs:
            cs_to_use = self.constraints if constrain else temp_cs
            for c in buffer:
                result.append(self._solver.get_value(cs_to_use, c))
                cs_to_use.add(c == result[-1])
        return result

def solve_buffer ( self , addr , nbytes , constrain = False ) : buffer = self . cpu . read_bytes ( addr , nbytes ) result = [ ] with self . _constraints as temp_cs : cs_to_use = self . constraints if constrain else temp_cs for c in buffer : result . append ( self . _solver . get_value ( cs_to_use , c ) ) cs_to_use . add ( c == result [ - 1 ] ) return result

Reads nbytes of symbolic data from a buffer in memory at addr and attempts to concretize it


def _hook_xfer_mem(self, uc, access, address, size, value, data):
        """
        Handle memory operations from unicorn.
        """
        assert access in (UC_MEM_WRITE, UC_MEM_READ, UC_MEM_FETCH)

        if access == UC_MEM_WRITE:
            self._cpu.write_int(address, value, size * 8)

        # If client code is attempting to read a value, we need to bring it
        # in from Manticore state. If we try to mem_write it here, Unicorn
        # will segfault. We add the value to a list of things that need to
        # be written, and ask to restart the emulation.
        elif access == UC_MEM_READ:
            value = self._cpu.read_bytes(address, size)

            if address in self._should_be_written:
                return True

            self._should_be_written[address] = value

            self._should_try_again = True
            return False

        return True

def _hook_xfer_mem ( self , uc , access , address , size , value , data ) : assert access in ( UC_MEM_WRITE , UC_MEM_READ , UC_MEM_FETCH ) if access == UC_MEM_WRITE : self . _cpu . write_int ( address , value , size * 8 ) elif access == UC_MEM_READ : value = self . _cpu . read_bytes ( address , size ) if address in self . _should_be_written : return True self . _should_be_written [ address ] = value self . _should_try_again = True return False return True


def emulate(self, instruction):
        """
        Emulate a single instruction.
        """

        # The emulation might restart if Unicorn needs to bring in a memory map
        # or bring a value from Manticore state.
        while True:

            self.reset()

            # Establish Manticore state, potentially from past emulation
            # attempts
            for base in self._should_be_mapped:
                size, perms = self._should_be_mapped[base]
                self._emu.mem_map(base, size, perms)

            for address, values in self._should_be_written.items():
                for offset, byte in enumerate(values, start=address):
                    if issymbolic(byte):
                        from ..native.cpu.abstractcpu import ConcretizeMemory
                        raise ConcretizeMemory(self._cpu.memory, offset, 8,
                                               "Concretizing for emulation")

                self._emu.mem_write(address, b''.join(values))

            # Try emulation
            self._should_try_again = False

            self._step(instruction)

            if not self._should_try_again:
                break

def
emulate
(
self
,
instruction
)
:
while
True
:
self
.
reset
(
)
for
base
in
self
.
_should_be_mapped
:
size
,
perms
=
self
.
_should_be_mapped
[
base
]
self
.
_emu
.
mem_map
(
base
,
size
,
perms
)
for
address
,
values
in
self
.
_should_be_written
.
items
(
)
:
for
offset
,
byte
in
enumerate
(
values
,
start
=
address
)
:
if
issymbolic
(
byte
)
:
from
.
.
native
.
cpu
.
abstractcpu
import
ConcretizeMemory
raise
ConcretizeMemory
(
self
.
_cpu
.
memory
,
offset
,
8
,
"Concretizing for emulation"
)
self
.
_emu
.
mem_write
(
address
,
b''
.
join
(
values
)
)
self
.
_should_try_again
=
False
self
.
_step
(
instruction
)
if
not
self
.
_should_try_again
:
break


def must_be_true(self, constraints, expression) -> bool:
        """Check if expression is True and that it can not be False with current constraints"""
        solutions = self.get_all_values(constraints, expression, maxcnt=2, silent=True)
        return solutions == [True]

def must_be_true ( self , constraints , expression ) -> bool : solutions = self . get_all_values ( constraints , expression , maxcnt = 2 , silent = True ) return solutions == [ True ]


def min(self, constraints, X: BitVec, M=10000):
        """
        Iteratively finds the minimum value for a symbol within given constraints.

        :param constraints: constraints that the expression must fulfil
        :param X: a symbol or expression
        :param M: maximum number of iterations allowed
        """
        assert isinstance(X, BitVec)
        return self.optimize(constraints, X, 'minimize', M)

def min ( self , constraints , X : BitVec , M = 10000 ) : assert isinstance ( X , BitVec ) return self . optimize ( constraints , X , 'minimize' , M )

Iteratively finds the minimum value for a symbol within given constraints .


def minmax(self, constraints, x, iters=10000):
        """Returns the min and max possible values for x within given constraints"""
        if issymbolic(x):
            m = self.min(constraints, x, iters)
            M = self.max(constraints, x, iters)
            return m, M
        else:
            return x, x

def minmax ( self , constraints , x , iters = 10000 ) : if issymbolic ( x ) : m = self . min ( constraints , x , iters ) M = self . max ( constraints , x , iters ) return m , M else : return x , x


def _solver_version(self) -> Version:
        """
        If we fail to parse the version, we assume z3's output has changed, meaning it's a newer
        version than what's used now, and therefore ok.

        Anticipated version_cmd_output format: 'Z3 version 4.4.2'
                                               'Z3 version 4.4.5 - 64 bit - build hashcode $Z3GITHASH'
        """
        self._reset()
        if self._received_version is None:
            self._send('(get-info :version)')
            self._received_version = self._recv()
        key, version = shlex.split(self._received_version[1:-1])
        return Version(*map(int, version.split('.')))

def
_solver_version
(
self
)
->
Version
:
self
.
_reset
(
)
if
self
.
_received_version
is
:
self
.
_send
(
'(get-info :version)'
)
self
.
_received_version
=
self
.
_recv
(
)
key
,
version
=
shlex
.
split
(
self
.
_received_version
[
1
:
1
]
)
return
Version
(
*
map
(
int
,
version
.
split
(
'.'
)
)
)

If we fail to parse the version we assume z3 s output has changed meaning it s a newer version than what s used now and therefore ok .


def _start_proc(self):
        """Spawns z3 solver process"""
        assert '_proc' not in dir(self) or self._proc is None
        try:
            self._proc = Popen(shlex.split(self._command), stdin=PIPE, stdout=PIPE, bufsize=0, universal_newlines=True)
        except OSError as e:
            print(e, "Probably too many cached expressions? visitors._cache...")
            # Z3 was removed from the system in the middle of operation
            raise Z3NotFoundError  # TODO(mark) don't catch this exception in two places

        # run solver specific initializations
        for cfg in self._init:
            self._send(cfg)


def _reset(self, constraints=None):
        """Auxiliary method to reset the smtlib external solver to initial defaults"""
        if self._proc is None:
            self._start_proc()
        else:
            if self.support_reset:
                self._send("(reset)")

                for cfg in self._init:
                    self._send(cfg)
            else:
                self._stop_proc()
                self._start_proc()
        if constraints is not None:
            self._send(constraints)

def _reset ( self , constraints = None ) : if self . _proc is None : self . _start_proc ( ) else : if self . support_reset : self . _send ( "(reset)" ) for cfg in self . _init : self . _send ( cfg ) else : self . _stop_proc ( ) self . _start_proc ( ) if constraints is not None : self . _send ( constraints )


def _send(self, cmd: str):
        """
        Send a string to the solver.

        :param cmd: a SMTLIBv2 command (ex. (check-sat))
        """
        logger.debug('>%s', cmd)
        try:
            self._proc.stdout.flush()
            self._proc.stdin.write(f'{cmd}\n')
        except IOError as e:
            raise SolverError(str(e))

def _send ( self , cmd : str ) : logger . debug ( '>%s' , cmd ) try : self . _proc . stdout . flush ( ) self . _proc . stdin . write ( f'{cmd}\n' ) except IOError as e : raise SolverError ( str ( e ) )


def _recv(self) -> str:
        """Reads the response from the solver"""
        buf, left, right = self.__readline_and_count()
        bufl = [buf]

        while left != right:
            buf, l, r = self.__readline_and_count()
            bufl.append(buf)
            left += l
            right += r

        buf = ''.join(bufl).strip()

        logger.debug('<%s', buf)
        if '(error' in bufl[0]:
            raise Exception(f"Error in smtlib: {bufl[0]}")
        return buf

def
_recv
(
self
)
->
str
:
buf
,
left
,
right
=
self
.
__readline_and_count
(
)
bufl
=
[
buf
]
while
left
!=
right
:
buf
,
l
,
r
=
self
.
__readline_and_count
(
)
bufl
.
append
(
buf
)
left
+=
l
right
+=
r
buf
=
''
.
join
(
bufl
)
.
strip
(
)
logger
.
debug
(
'<%s'
,
buf
)
if
'(error'
in
bufl
[
0
]
:
raise
Exception
(
f"Error in smtlib: {bufl[0]}"
)
return
buf


def _is_sat(self) -> bool:
        """
        Check the satisfiability of the current state

        :return: whether current state is satisfiable or not.
        """
        logger.debug("Solver.check() ")
        start = time.time()
        self._send('(check-sat)')
        status = self._recv()
        logger.debug("Check took %s seconds (%s)", time.time() - start, status)
        if status not in ('sat', 'unsat', 'unknown'):
            raise SolverError(status)
        if consider_unknown_as_unsat:
            if status == 'unknown':
                logger.info('Found an unknown core, probably a solver timeout')
                status = 'unsat'

        if status == 'unknown':
            raise SolverUnknown(status)

        return status == 'sat'


def _assert(self, expression: Bool):
        """Auxiliary method to send an assert"""
        assert isinstance(expression, Bool)
        smtlib = translate_to_smtlib(expression)
        self._send('(assert %s)' % smtlib)

def
_assert
(
self
,
expression
:
Bool
)
:
assert
isinstance
(
expression
,
Bool
)
smtlib
=
translate_to_smtlib
(
expression
)
self
.
_send
(
'(assert %s)'
%
smtlib
)


def _getvalue(self, expression):
        """
        Ask the solver for one possible assignment for given expression using current set of constraints.
        The current set of expressions must be sat.

        NOTE: This is an internal method: it uses the current solver state (set of constraints!).
        """
        if not issymbolic(expression):
            return expression
        assert isinstance(expression, Variable)

        if isinstance(expression, Array):
            result = bytearray()
            for c in expression:
                expression_str = translate_to_smtlib(c)
                self._send('(get-value (%s))' % expression_str)
                response = self._recv()
                result.append(int('0x{:s}'.format(response.split(expression_str)[1][3:-2]), 16))
            return bytes(result)
        else:
            self._send('(get-value (%s))' % expression.name)
            ret = self._recv()
            assert ret.startswith('((') and ret.endswith('))'), ret

            if isinstance(expression, Bool):
                return {'true': True, 'false': False}[ret[2:-2].split(' ')[1]]
            elif isinstance(expression, BitVec):
                pattern, base = self._get_value_fmt
                m = pattern.match(ret)
                expr, value = m.group('expr'), m.group('value')
                return int(value, base)

        raise NotImplementedError("_getvalue only implemented for Bool and BitVec")

Ask the solver for one possible assignment for given expression using current set of constraints . The current set of expressions must be sat .


def can_be_true(self, constraints, expression):
        """Check if two potentially symbolic values can be equal"""
        if isinstance(expression, bool):
            if not expression:
                return expression
            else:
                # if True check if constraints are feasible
                self._reset(constraints)
                return self._is_sat()
        assert isinstance(expression, Bool)

        with constraints as temp_cs:
            temp_cs.add(expression)
            self._reset(temp_cs.to_string(related_to=expression))
            return self._is_sat()

def can_be_true ( self , constraints , expression ) : if isinstance ( expression , bool ) : if not expression : return expression else : self . _reset ( constraints ) return self . _is_sat ( ) assert isinstance ( expression , Bool ) with constraints as temp_cs : temp_cs . add ( expression ) self . _reset ( temp_cs . to_string ( related_to = expression ) ) return self . _is_sat ( )


def get_all_values(self, constraints, expression, maxcnt=None, silent=False):
        """Returns a list with all the possible values for the symbol x"""
        if not isinstance(expression, Expression):
            return [expression]
        assert isinstance(constraints, ConstraintSet)
        assert isinstance(expression, Expression)
        expression = simplify(expression)
        if maxcnt is None:
            maxcnt = consts.maxsolutions

        with constraints as temp_cs:
            if isinstance(expression, Bool):
                var = temp_cs.new_bool()
            elif isinstance(expression, BitVec):
                var = temp_cs.new_bitvec(expression.size)
            elif isinstance(expression, Array):
                var = temp_cs.new_array(index_max=expression.index_max, value_bits=expression.value_bits, taint=expression.taint).array
            else:
                raise NotImplementedError(f"get_all_values only implemented for {type(expression)} expression type.")

            temp_cs.add(var == expression)
            self._reset(temp_cs.to_string(related_to=var))

            result = []

            while self._is_sat():
                value = self._getvalue(var)
                result.append(value)
                self._assert(var != value)

                if len(result) >= maxcnt:
                    if silent:
                        # do not throw an exception if set to silent
                        # Default is not silent, assume user knows
                        # what they are doing and will check the size
                        # of returned vals list (previous smtlib behavior)
                        break
                    else:
                        raise TooManySolutions(result)

            return result


def get_value(self, constraints, expression):
        """
        Ask the solver for one possible result of given expression using given set of constraints.
        """
        if not issymbolic(expression):
            return expression
        assert isinstance(expression, (Bool, BitVec, Array))
        with constraints as temp_cs:
            if isinstance(expression, Bool):
                var = temp_cs.new_bool()
            elif isinstance(expression, BitVec):
                var = temp_cs.new_bitvec(expression.size)
            elif isinstance(expression, Array):
                var = []
                result = []
                for i in range(expression.index_max):
                    subvar = temp_cs.new_bitvec(expression.value_bits)
                    var.append(subvar)
                    temp_cs.add(subvar == simplify(expression[i]))

                self._reset(temp_cs)
                if not self._is_sat():
                    raise SolverError('Model is not available')

                for i in range(expression.index_max):
                    self._send('(get-value (%s))' % var[i].name)
                    ret = self._recv()
                    assert ret.startswith('((') and ret.endswith('))')
                    pattern, base = self._get_value_fmt
                    m = pattern.match(ret)
                    expr, value = m.group('expr'), m.group('value')
                    result.append(int(value, base))
                return bytes(result)

            temp_cs.add(var == expression)

            self._reset(temp_cs)

        if not self._is_sat():
            raise SolverError('Model is not available')

        self._send('(get-value (%s))' % var.name)
        ret = self._recv()
        if not (ret.startswith('((') and ret.endswith('))')):
            raise SolverError('SMTLIB error parsing response: %s' % ret)

        if isinstance(expression, Bool):
            return {'true': True, 'false': False}[ret[2:-2].split(' ')[1]]
        if isinstance(expression, BitVec):
            pattern, base = self._get_value_fmt
            m = pattern.match(ret)
            expr, value = m.group('expr'), m.group('value')
            return int(value, base)
        raise NotImplementedError("get_value only implemented for Bool and BitVec")

Ask the solver for one possible result of given expression using given set of constraints .


def summarized_name(self, name):
        """
        Produce a summarized record name
          i.e. manticore.core.executor -> m.c.executor
        """
        components = name.split('.')
        prefix = '.'.join(c[0] for c in components[:-1])
        return f'{prefix}.{components[-1]}'

def summarized_name ( self , name ) : components = name . split ( '.' ) prefix = '.' . join ( c [ 0 ] for c in components [ : - 1 ] ) return f'{prefix}.{components[-1]}'

Produce a summarized record name i . e . manticore . core . executor - > m . c . executor


def colored_level_name(self, levelname):
        """
        Colors the logging level in the logging record
        """
        if self.colors_disabled:
            return self.plain_levelname_format.format(levelname)
        else:
            return self.colored_levelname_format.format(self.color_map[levelname], levelname)

def colored_level_name ( self , levelname ) : if self . colors_disabled : return self . plain_levelname_format . format ( levelname ) else : return self . colored_levelname_format . format ( self . color_map [ levelname ] , levelname )


def _find_zero(cpu, constrs, ptr):
    """
    Helper for finding the closest NULL or, effectively NULL byte from a starting address.

    :param Cpu cpu:
    :param ConstraintSet constrs: Constraints for current `State`
    :param int ptr: Address to start searching for a zero from
    :return: Offset from `ptr` to first byte that is 0 or an `Expression` that must be zero
    """

    offset = 0
    while True:
        byt = cpu.read_int(ptr + offset, 8)

        if issymbolic(byt):
            if not solver.can_be_true(constrs, byt != 0):
                break
        else:
            if byt == 0:
                break

        offset += 1

    return offset

def _find_zero ( cpu , constrs , ptr ) : offset = 0 while True : byt = cpu . read_int ( ptr + offset , 8 ) if issymbolic ( byt ) : if not solver . can_be_true ( constrs , byt != 0 ) : break else : if byt == 0 : break offset += 1 return offset

Helper for finding the closest NULL or effectively NULL byte from a starting address .


def strcmp(state, s1, s2):
    """
    strcmp symbolic model.

    Algorithm: Walks from end of string (minimum offset to NULL in either string)
    to beginning building tree of ITEs each time either of the
    bytes at current offset is symbolic.

    Points of Interest:
    - We've been building up a symbolic tree but then encounter two
      concrete bytes that differ. We can throw away the entire symbolic
      tree!
    - If we've been encountering concrete bytes that match
      at the end of the string as we walk forward, and then we encounter
      a pair where one is symbolic, we can forget about that 0 `ret` we've
      been tracking and just replace it with the symbolic subtraction of
      the two

    :param State state: Current program state
    :param int s1: Address of string 1
    :param int s2: Address of string 2
    :return: Symbolic strcmp result
    :rtype: Expression or int
    """

    cpu = state.cpu

    if issymbolic(s1):
        raise ConcretizeArgument(state.cpu, 1)
    if issymbolic(s2):
        raise ConcretizeArgument(state.cpu, 2)

    s1_zero_idx = _find_zero(cpu, state.constraints, s1)
    s2_zero_idx = _find_zero(cpu, state.constraints, s2)
    min_zero_idx = min(s1_zero_idx, s2_zero_idx)

    ret = None

    for offset in range(min_zero_idx, -1, -1):
        s1char = ZEXTEND(cpu.read_int(s1 + offset, 8), cpu.address_bit_size)
        s2char = ZEXTEND(cpu.read_int(s2 + offset, 8), cpu.address_bit_size)

        if issymbolic(s1char) or issymbolic(s2char):
            if ret is None or (not issymbolic(ret) and ret == 0):
                ret = s1char - s2char
            else:
                ret = ITEBV(cpu.address_bit_size, s1char != s2char, s1char - s2char, ret)
        else:
            if s1char != s2char:
                ret = s1char - s2char
            elif ret is None:
                ret = 0

    return ret

def strcmp ( state , s1 , s2 ) : cpu = state . cpu if issymbolic ( s1 ) : raise ConcretizeArgument ( state . cpu , 1 ) if issymbolic ( s2 ) : raise ConcretizeArgument ( state . cpu , 2 ) s1_zero_idx = _find_zero ( cpu , state . constraints , s1 ) s2_zero_idx = _find_zero ( cpu , state . constraints , s2 ) min_zero_idx = min ( s1_zero_idx , s2_zero_idx ) ret = None for offset in range ( min_zero_idx , - 1 , - 1 ) : s1char = ZEXTEND ( cpu . read_int ( s1 + offset , 8 ) , cpu . address_bit_size ) s2char = ZEXTEND ( cpu . read_int ( s2 + offset , 8 ) , cpu . address_bit_size ) if issymbolic ( s1char ) or issymbolic ( s2char ) : if ret is None or ( not issymbolic ( ret ) and ret == 0 ) : ret = s1char - s2char else : ret = ITEBV ( cpu . address_bit_size , s1char != s2char , s1char - s2char , ret ) else : if s1char != s2char : ret = s1char - s2char elif ret is None : ret = 0 return ret


def strlen(state, s):
    """
    strlen symbolic model.

    Algorithm: Walks from end of string not including NULL building ITE tree when current byte is symbolic.

    :param State state: current program state
    :param int s: Address of string
    :return: Symbolic strlen result
    :rtype: Expression or int
    """

    cpu = state.cpu

    if issymbolic(s):
        raise ConcretizeArgument(state.cpu, 1)

    zero_idx = _find_zero(cpu, state.constraints, s)

    ret = zero_idx

    for offset in range(zero_idx - 1, -1, -1):
        byt = cpu.read_int(s + offset, 8)
        if issymbolic(byt):
            ret = ITEBV(cpu.address_bit_size, byt == 0, offset, ret)

    return ret

def strlen ( state , s ) : cpu = state . cpu if issymbolic ( s ) : raise ConcretizeArgument ( state . cpu , 1 ) zero_idx = _find_zero ( cpu , state . constraints , s ) ret = zero_idx for offset in range ( zero_idx - 1 , - 1 , - 1 ) : byt = cpu . read_int ( s + offset , 8 ) if issymbolic ( byt ) : ret = ITEBV ( cpu . address_bit_size , byt == 0 , offset , ret ) return ret


def all_events(cls):
        """
        Return all events that all subclasses have so far registered to publish.
        """
        all_evts = set()
        for cls, evts in cls.__all_events__.items():
            all_evts.update(evts)
        return all_evts

def all_events ( cls ) : all_evts = set ( ) for cls , evts in cls . __all_events__ . items ( ) : all_evts . update ( evts ) return all_evts

Return all events that all subclasses have so far registered to publish .


def forward_events_to(self, sink, include_source=False):
        """This forwards signal to sink"""
        assert isinstance(sink, Eventful), f'{sink.__class__.__name__} is not Eventful'
        self._forwards[sink] = include_source


def get_profiling_stats(self):
        """
        Returns a pstat.Stats instance with profiling results if `run` was called with `should_profile=True`.
        Otherwise, returns `None`.
        """
        profile_file_path = os.path.join(self.workspace, 'profiling.bin')
        try:
            return pstats.Stats(profile_file_path)
        except Exception as e:
            logger.debug(f'Failed to get profiling stats: {e}')
            return None

def
get_profiling_stats
(
self
)
:
profile_file_path
=
os
.
path
.
join
(
self
.
workspace
,
'profiling.bin'
)
try
:
return
pstats
.
Stats
(
profile_file_path
)
except
Exception
as
e
:
logger
.
debug
(
f'Failed to get profiling stats: {e}'
)
return

Returns a pstat . Stats instance with profiling results if run was called with should_profile = True . Otherwise returns None .


def run(self, procs=1, timeout=None, should_profile=False):
        """
        Runs analysis.

        :param int procs: Number of parallel worker processes
        :param timeout: Analysis timeout, in seconds
        """
        assert not self.running, "Manticore is already running."
        self._start_run()

        self._last_run_stats['time_started'] = time.time()
        with self.shutdown_timeout(timeout):
            self._start_workers(procs, profiling=should_profile)

            self._join_workers()
        self._finish_run(profiling=should_profile)

def
run
(
self
,
procs
=
1
,
timeout
=
,
should_profile
=
False
)
:
assert
not
self
.
running
,
"Manticore is already running."
self
.
_start_run
(
)
self
.
_last_run_stats
[
'time_started'
]
=
time
.
time
(
)
with
self
.
shutdown_timeout
(
timeout
)
:
self
.
_start_workers
(
procs
,
profiling
=
should_profile
)
self
.
_join_workers
(
)
self
.
_finish_run
(
profiling
=
should_profile
)


def GetNBits(value, nbits):
    """
    Get the first `nbits` from `value`.

    :param value: Source value from which to extract
    :type value: int or long or BitVec
    :param int nbits: How many bits to extract
    :return: Low `nbits` bits of `value`.
    :rtype int or long or BitVec
    """
    # NOP if sizes are the same
    if isinstance(value, int):
        return Operators.EXTRACT(value, 0, nbits)
    elif isinstance(value, BitVec):
        if value.size < nbits:
            return Operators.ZEXTEND(value, nbits)
        else:
            return Operators.EXTRACT(value, 0, nbits)

def GetNBits ( value , nbits ) : if isinstance ( value , int ) : return Operators . EXTRACT ( value , 0 , nbits ) elif isinstance ( value , BitVec ) : if value . size < nbits : return Operators . ZEXTEND ( value , nbits ) else : return Operators . EXTRACT ( value , 0 , nbits )


def SInt(value, width):
    """
    Convert a bitstring `value` of `width` bits to a signed integer
    representation.

    :param value: The value to convert.
    :type value: int or long or BitVec
    :param int width: The width of the bitstring to consider
    :return: The converted value
    :rtype int or long or BitVec
    """
    return Operators.ITEBV(width, Bit(value, width - 1) == 1,
                           GetNBits(value, width) - 2**width,
                           GetNBits(value, width))

def SInt ( value , width ) : return Operators . ITEBV ( width , Bit ( value , width - 1 ) == 1 , GetNBits ( value , width ) - 2 ** width , GetNBits ( value , width ) )

Convert a bitstring value of width bits to a signed integer representation .


def locked_context(self, key=None, default=dict):
        """ Policy shared context dictionary """
        keys = ['policy']
        if key is not None:
            keys.append(key)
        with self._executor.locked_context('.'.join(keys), default) as policy_context:
            yield policy_context

def locked_context ( self , key = None , default = dict ) : keys = [ 'policy' ] if key is not None : keys . append ( key ) with self . _executor . locked_context ( '.' . join ( keys ) , default ) as policy_context : yield policy_context


def enqueue(self, state):
        """
            Enqueue state.
            Save state on storage, assigns an id to it, then add it to the
            priority queue
        """
        # save the state to secondary storage
        state_id = self._workspace.save_state(state)
        self.put(state_id)
        self._publish('did_enqueue_state', state_id, state)
        return state_id

def enqueue ( self , state ) : state_id = self . _workspace . save_state ( state ) self . put ( state_id ) self . _publish ( 'did_enqueue_state' , state_id , state ) return state_id

Enqueue state . Save state on storage assigns an id to it then add it to the priority queue


def put(self, state_id):
        """ Enqueue it for processing """
        self._states.append(state_id)
        self._lock.notify_all()
        return state_id

def put ( self , state_id ) : self . _states . append ( state_id ) self . _lock . notify_all ( ) return state_id


def get(self):
        """ Dequeue a state with the max priority """

        # A shutdown has been requested
        if self.is_shutdown():
            return None

        # if not more states in the queue, let's wait for some forks
        while len(self._states) == 0:
            # if no worker is running, bail out
            if self.running == 0:
                return None
            # if a shutdown has been requested, bail out
            if self.is_shutdown():
                return None
            # if there ares actually some workers running, wait for state forks
            logger.debug("Waiting for available states")
            self._lock.wait()

        state_id = self._policy.choice(list(self._states))
        if state_id is None:
            return None
        del self._states[self._states.index(state_id)]
        return state_id

def
get
(
self
)
:
if
self
.
is_shutdown
(
)
:
return
while
len
(
self
.
_states
)
==
0
:
if
self
.
running
==
0
:
return
if
self
.
is_shutdown
(
)
:
return
logger
.
debug
(
"Waiting for available states"
)
self
.
_lock
.
wait
(
)
state_id
=
self
.
_policy
.
choice
(
list
(
self
.
_states
)
)
if
state_id
is
:
return
del
self
.
_states
[
self
.
_states
.
index
(
state_id
)
]
return
state_id


def fork(self, state, expression, policy='ALL', setstate=None):
        """
        Fork state on expression concretizations.
        Using policy build a list of solutions for expression.
        For the state on each solution setting the new state with setstate

        For example if expression is a Bool it may have 2 solutions. True or False.

                                 Parent
                            (expression = ??)

                   Child1                         Child2
            (expression = True)             (expression = True)
               setstate(True)                   setstate(False)

        The optional setstate() function is supposed to set the concrete value
        in the child state.

        """
        assert isinstance(expression, Expression)

        if setstate is None:
            setstate = lambda x, y: None

        # Find a set of solutions for expression
        solutions = state.concretize(expression, policy)

        if not solutions:
            raise ExecutorError("Forking on unfeasible constraint set")

        if len(solutions) == 1:
            setstate(state, solutions[0])
            return state

        logger.info("Forking. Policy: %s. Values: %s",
                    policy,
                    ', '.join(f'0x{sol:x}' for sol in solutions))

        self._publish('will_fork_state', state, expression, solutions, policy)

        # Build and enqueue a state for each solution
        children = []
        for new_value in solutions:
            with state as new_state:
                new_state.constrain(expression == new_value)

                # and set the PC of the new state to the concrete pc-dest
                #(or other register or memory address to concrete)
                setstate(new_state, new_value)

                self._publish('did_fork_state', new_state, expression, new_value, policy)

                # enqueue new_state
                state_id = self.enqueue(new_state)
                # maintain a list of children for logging purpose
                children.append(state_id)

        logger.info("Forking current state into states %r", children)
        return None

def
fork
(
self
,
state
,
expression
,
policy
=
'ALL'
,
setstate
=
)
:
assert
isinstance
(
expression
,
Expression
)
if
setstate
is
:
setstate
=
lambda
x
,
y
:
solutions
=
state
.
concretize
(
expression
,
policy
)
if
not
solutions
:
raise
ExecutorError
(
"Forking on unfeasible constraint set"
)
if
len
(
solutions
)
==
1
:
setstate
(
state
,
solutions
[
0
]
)
return
state
logger
.
info
(
"Forking. Policy: %s. Values: %s"
,
policy
,
', '
.
join
(
f'0x{sol:x}'
for
sol
in
solutions
)
)
self
.
_publish
(
'will_fork_state'
,
state
,
expression
,
solutions
,
policy
)
children
=
[
]
for
new_value
in
solutions
:
with
state
as
new_state
:
new_state
.
constrain
(
expression
==
new_value
)
setstate
(
new_state
,
new_value
)
self
.
_publish
(
'did_fork_state'
,
new_state
,
expression
,
new_value
,
policy
)
state_id
=
self
.
enqueue
(
new_state
)
children
.
append
(
state_id
)
logger
.
info
(
"Forking current state into states %r"
,
children
)
return

Fork state on expression concretizations . Using policy build a list of solutions for expression . For the state on each solution setting the new state with setstate


def run(self):
        """
        Entry point of the Executor; called by workers to start analysis.
        """
        # policy_order=self.policy_order
        # policy=self.policy
        current_state = None
        current_state_id = None

        with WithKeyboardInterruptAs(self.shutdown):
            # notify siblings we are about to start a run
            self._notify_start_run()

            logger.debug("Starting Manticore Symbolic Emulator Worker (pid %d).", os.getpid())
            solver = Z3Solver()
            while not self.is_shutdown():
                try:  # handle fatal errors: exceptions in Manticore
                    try:  # handle external (e.g. solver) errors, and executor control exceptions
                        # select a suitable state to analyze
                        if current_state is None:
                            with self._lock:
                                # notify siblings we are about to stop this run
                                self._notify_stop_run()
                                try:
                                    # Select a single state_id
                                    current_state_id = self.get()
                                    # load selected state from secondary storage
                                    if current_state_id is not None:
                                        self._publish('will_load_state', current_state_id)
                                        current_state = self._workspace.load_state(current_state_id)
                                        self.forward_events_from(current_state, True)
                                        self._publish('did_load_state', current_state, current_state_id)
                                        logger.info("load state %r", current_state_id)
                                    # notify siblings we have a state to play with
                                finally:
                                    self._notify_start_run()

                        # If current_state is still None. We are done.
                        if current_state is None:
                            logger.debug("No more states in the queue, byte bye!")
                            break

                        assert current_state is not None
                        assert current_state.constraints is current_state.platform.constraints

                        # Allows to terminate manticore worker on user request
                        while not self.is_shutdown():
                            if not current_state.execute():
                                break
                        else:
                            # Notify this worker is done
                            self._publish('will_terminate_state', current_state, current_state_id, TerminateState('Shutdown'))
                            current_state = None

                    # Handling Forking and terminating exceptions
                    except Concretize as e:
                        # expression
                        # policy
                        # setstate()
                        logger.debug("Generic state fork on condition")
                        current_state = self.fork(current_state, e.expression, e.policy, e.setstate)

                    except TerminateState as e:
                        # Notify this worker is done
                        self._publish('will_terminate_state', current_state, current_state_id, e)

                        logger.debug("Generic terminate state")
                        if e.testcase:
                            self._publish('internal_generate_testcase', current_state, message=str(e))
                        current_state = None

                    except SolverError as e:
                        # raise
                        import traceback
                        trace = traceback.format_exc()
                        logger.error("Exception: %s\n%s", str(e), trace)

                        # Notify this state is done
                        self._publish('will_terminate_state', current_state, current_state_id, e)

                        if solver.check(current_state.constraints):
                            self._publish('internal_generate_testcase', current_state, message="Solver failed" + str(e))
                        current_state = None

                except (Exception, AssertionError) as e:
                    # raise
                    import traceback
                    trace = traceback.format_exc()
                    logger.error("Exception: %s\n%s", str(e), trace)
                    # Notify this worker is done
                    self._publish('will_terminate_state', current_state, current_state_id, e)
                    current_state = None

            assert current_state is None or self.is_shutdown()

            # notify siblings we are about to stop this run
            self._notify_stop_run()

Entry point of the Executor ; called by workers to start analysis .


def linux(cls, path, argv=None, envp=None, entry_symbol=None, symbolic_files=None, concrete_start='', pure_symbolic=False, stdin_size=None, **kwargs):
        """
        Constructor for Linux binary analysis.

        :param str path: Path to binary to analyze
        :param argv: Arguments to provide to the binary
        :type argv: list[str]
        :param envp: Environment to provide to the binary
        :type envp: dict[str, str]
        :param entry_symbol: Entry symbol to resolve to start execution
        :type envp: str
        :param symbolic_files: Filenames to mark as having symbolic input
        :type symbolic_files: list[str]
        :param str concrete_start: Concrete stdin to use before symbolic input
        :param int stdin_size: symbolic stdin size to use
        :param kwargs: Forwarded to the Manticore constructor
        :return: Manticore instance, initialized with a Linux State
        :rtype: Manticore
        """
        if stdin_size is None:
            stdin_size = consts.stdin_size

        try:
            return cls(_make_linux(path, argv, envp, entry_symbol, symbolic_files, concrete_start, pure_symbolic, stdin_size), **kwargs)
        except elftools.common.exceptions.ELFError:
            raise Exception(f'Invalid binary: {path}')

def
linux
(
cls
,
path
,
argv
=
,
envp
=
,
entry_symbol
=
,
symbolic_files
=
,
concrete_start
=
''
,
pure_symbolic
=
False
,
stdin_size
=
,
**
kwargs
)
:
if
stdin_size
is
:
stdin_size
=
consts
.
stdin_size
try
:
return
cls
(
_make_linux
(
path
,
argv
,
envp
,
entry_symbol
,
symbolic_files
,
concrete_start
,
pure_symbolic
,
stdin_size
)
,
**
kwargs
)
except
elftools
.
common
.
exceptions
.
ELFError
:
raise
Exception
(
f'Invalid binary: {path}'
)


def decree(cls, path, concrete_start='', **kwargs):
        """
        Constructor for Decree binary analysis.

        :param str path: Path to binary to analyze
        :param str concrete_start: Concrete stdin to use before symbolic input
        :param kwargs: Forwarded to the Manticore constructor
        :return: Manticore instance, initialized with a Decree State
        :rtype: Manticore
        """
        try:
            return cls(_make_decree(path, concrete_start), **kwargs)
        except KeyError:  # FIXME(mark) magic parsing for DECREE should raise better error
            raise Exception(f'Invalid binary: {path}')

def
decree
(
cls
,
path
,
concrete_start
=
''
,
**
kwargs
)
:
try
:
return
cls
(
_make_decree
(
path
,
concrete_start
)
,
**
kwargs
)
except
KeyError
:
raise
Exception
(
f'Invalid binary: {path}'
)

Constructor for Decree binary analysis .


def _hook_callback(self, state, pc, instruction):
        'Invoke all registered generic hooks'

        # Ignore symbolic pc.
        # TODO(yan): Should we ask the solver if any of the hooks are possible,
        # and execute those that are?

        if issymbolic(pc):
            return

        # Invoke all pc-specific hooks
        for cb in self._hooks.get(pc, []):
            cb(state)

        # Invoke all pc-agnostic hooks
        for cb in self._hooks.get(None, []):
            cb(state)

def
_hook_callback
(
self
,
state
,
pc
,
instruction
)
:
'Invoke all registered generic hooks'
if
issymbolic
(
pc
)
:
return
for
cb
in
self
.
_hooks
.
get
(
pc
,
[
]
)
:
cb
(
state
)
for
cb
in
self
.
_hooks
.
get
(
,
[
]
)
:
cb
(
state
)


def resolve(self, symbol):
        """
        A helper method used to resolve a symbol name into a memory address when
        injecting hooks for analysis.

        :param symbol: function name to be resolved
        :type symbol: string

        :param line: if more functions present, optional line number can be included
        :type line: int or None
        """

        with open(self.binary_path, 'rb') as f:

            elffile = ELFFile(f)

            # iterate over sections and identify symbol table section
            for section in elffile.iter_sections():
                if not isinstance(section, SymbolTableSection):
                    continue

                # get list of symbols by name
                symbols = section.get_symbol_by_name(symbol)
                if not symbols:
                    continue

                # return first indexed memory address for the symbol,
                return symbols[0].entry['st_value']

            raise ValueError(f"The {self.binary_path} ELFfile does not contain symbol {symbol}")

A helper method used to resolve a symbol name into a memory address when injecting hooks for analysis .


def binary_arch(binary):
    """
    helper method for determining binary architecture

    :param binary: str for binary to introspect.
    :rtype bool: True for x86_64, False otherwise
    """

    with open(binary, 'rb') as f:
        elffile = ELFFile(f)
        if elffile['e_machine'] == 'EM_X86_64':
            return True
        else:
            return False

def binary_arch ( binary ) : with open ( binary , 'rb' ) as f : elffile = ELFFile ( f ) if elffile [ 'e_machine' ] == 'EM_X86_64' : return True else : return False


def binary_symbols(binary):
    """
    helper method for getting all binary symbols with SANDSHREW_ prepended.
    We do this in order to provide the symbols Manticore should hook on to
    perform main analysis.

    :param binary: str for binary to instrospect.
    :rtype list: list of symbols from binary
    """

    def substr_after(string, delim):
        return string.partition(delim)[2]

    with open(binary, 'rb') as f:
        elffile = ELFFile(f)

        for section in elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue

            symbols = [sym.name for sym in section.iter_symbols() if sym]
            return [substr_after(name, PREPEND_SYM) for name in symbols
                    if name.startswith(PREPEND_SYM)]

def binary_symbols ( binary ) : def substr_after ( string , delim ) : return string . partition ( delim ) [ 2 ] with open ( binary , 'rb' ) as f : elffile = ELFFile ( f ) for section in elffile . iter_sections ( ) : if not isinstance ( section , SymbolTableSection ) : continue symbols = [ sym . name for sym in section . iter_symbols ( ) if sym ] return [ substr_after ( name , PREPEND_SYM ) for name in symbols if name . startswith ( PREPEND_SYM ) ]

helper method for getting all binary symbols with SANDSHREW_ prepended . We do this in order to provide the symbols Manticore should hook on to perform main analysis .


def get_group(name: str) -> _Group:
    """
    Get a configuration variable group named |name|
    """
    global _groups

    if name in _groups:
        return _groups[name]

    group = _Group(name)
    _groups[name] = group

    return group

def get_group ( name : str ) -> _Group : global _groups if name in _groups : return _groups [ name ] group = _Group ( name ) _groups [ name ] = group return group


def save(f):
    """
    Save current config state to an yml file stream identified by |f|

    :param f: where to write the config file
    """
    global _groups

    c = {}
    for group_name, group in _groups.items():
        section = {var.name: var.value for var in group.updated_vars()}
        if not section:
            continue
        c[group_name] = section

    yaml.safe_dump(c, f, line_break=True)

def save ( f ) : global _groups c = { } for group_name , group in _groups . items ( ) : section = { var . name : var . value for var in group . updated_vars ( ) } if not section : continue c [ group_name ] = section yaml . safe_dump ( c , f , line_break = True )


def parse_config(f):
    """
    Load an yml-formatted configuration from file stream |f|

    :param file f: Where to read the config.
    """

    try:
        c = yaml.safe_load(f)
        for section_name, section in c.items():
            group = get_group(section_name)

            for key, val in section.items():
                group.update(key)
                setattr(group, key, val)
    # Any exception here should trigger the warning; from not being able to parse yaml
    # to reading poorly formatted values
    except Exception:
        raise ConfigError("Failed reading config file. Do you have a local [.]manticore.yml file?")

Load an yml - formatted configuration from file stream |f|


def load_overrides(path=None):
    """
    Load config overrides from the yml file at |path|, or from default paths. If a path
    is provided and it does not exist, raise an exception

    Default paths: ./mcore.yml, ./.mcore.yml, ./manticore.yml, ./.manticore.yml.
    """

    if path is not None:
        names = [path]
    else:
        possible_names = ['mcore.yml', 'manticore.yml']
        names = [os.path.join('.', ''.join(x)) for x in product(['', '.'], possible_names)]

    for name in names:
        try:
            with open(name, 'r') as yml_f:
                logger.info(f'Reading configuration from {name}')
                parse_config(yml_f)
            break
        except FileNotFoundError:
            pass
    else:
        if path is not None:
            raise FileNotFoundError(f"'{path}' not found for config overrides")

Load config overrides from the yml file at |path| or from default paths . If a path is provided and it does not exist raise an exception


def process_config_values(parser: argparse.ArgumentParser, args: argparse.Namespace):
    """
    Bring in provided config values to the args parser, and import entries to the config
    from all arguments that were actually passed on the command line

    :param parser: The arg parser
    :param args: The value that parser.parse_args returned
    """
    # First, load a local config file, if passed or look for one in pwd if it wasn't.
    load_overrides(args.config)

    # Get a list of defined config vals. If these are passed on the command line,
    # update them in their correct group, not in the cli group
    defined_vars = list(get_config_keys())

    command_line_args = vars(args)

    # Bring in the options keys into args
    config_cli_args = get_group('cli')

    # Place all command line args into the cli group (for saving in the workspace). If
    # the value is set on command line, then it takes precedence; otherwise we try to
    # read it from the config file's cli group.
    for k in command_line_args:
        default = parser.get_default(k)
        set_val = getattr(args, k)
        if default is not set_val:
            if k not in defined_vars:
                config_cli_args.update(k, value=set_val)
            else:
                # Update a var's native group
                group_name, key = k.split('.')
                group = get_group(group_name)
                setattr(group, key, set_val)
        else:
            if k in config_cli_args:
                setattr(args, k, getattr(config_cli_args, k))

def process_config_values ( parser : argparse . ArgumentParser , args : argparse . Namespace ) : load_overrides ( args . config ) defined_vars = list ( get_config_keys ( ) ) command_line_args = vars ( args ) config_cli_args = get_group ( 'cli' ) for k in command_line_args : default = parser . get_default ( k ) set_val = getattr ( args , k ) if default is not set_val : if k not in defined_vars : config_cli_args . update ( k , value = set_val ) else : group_name , key = k . split ( '.' ) group = get_group ( group_name ) setattr ( group , key , set_val ) else : if k in config_cli_args : setattr ( args , k , getattr ( config_cli_args , k ) )

Bring in provided config values to the args parser and import entries to the config from all arguments that were actually passed on the command line


def add(self, name: str, default=None, description: str=None):
        """
        Add a variable named |name| to this value group, optionally giving it a
        default value and a description.

        Variables must be added with this method before they can be set or read.
        Reading a variable replaces the variable that was defined previously, but
        updates the description if a new one is set.

        """
        if name in self._vars:
            raise ConfigError(f"{self.name}.{name} already defined.")

        if name == 'name':
            raise ConfigError("'name' is a reserved name for a group.")

        v = _Var(name, description=description, default=default)
        self._vars[name] = v

Add a variable named |name| to this value group optionally giving it a default value and a description .


def update(self, name: str, value=None, default=None, description: str=None):
        """
        Like add, but can tolerate existing values; also updates the value.

        Mostly used for setting fields from imported INI files and modified CLI flags.
        """
        if name in self._vars:
            description = description or self._vars[name].description
            default = default or self._vars[name].default
        elif name == 'name':
            raise ConfigError("'name' is a reserved name for a group.")

        v = _Var(name, description=description, default=default, defined=False)
        v.value = value
        self._vars[name] = v

Like add but can tolerate existing values ; also updates the value .


def get_description(self, name: str) -> str:
        """
        Return the description, or a help string of variable identified by |name|.
        """
        if name not in self._vars:
            raise ConfigError(f"{self.name}.{name} not defined.")

        return self._vars[name].description

def
get_description
(
self
,
name
:
str
)
->
str
:
if
name
not
in
self
.
_vars
:
raise
ConfigError
(
f"{self.name}.{name} not defined."
)
return
self
.
_vars
[
name
]
.
description

Return the description or a help string of variable identified by |name| .


def function_signature_for_name_and_inputs(name: str, inputs: Sequence[Mapping[str, Any]]) -> str:
        """Returns the function signature for the specified name and Solidity JSON metadata inputs array.

        The ABI specification defines the function signature as the function name followed by the parenthesised list of
        parameter types separated by single commas and no spaces.
        See https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector
        """
        return name + SolidityMetadata.tuple_signature_for_components(inputs)

def function_signature_for_name_and_inputs ( name : str , inputs : Sequence [ Mapping [ str , Any ] ] ) -> str : return name + SolidityMetadata . tuple_signature_for_components ( inputs )

Returns the function signature for the specified name and Solidity JSON metadata inputs array .


def get_constructor_arguments(self) -> str:
        """Returns the tuple type signature for the arguments of the contract constructor."""
        item = self._constructor_abi_item
        return '()' if item is None else self.tuple_signature_for_components(item['inputs'])

def get_constructor_arguments ( self ) -> str : item = self . _constructor_abi_item return '()' if item is None else self . tuple_signature_for_components ( item [ 'inputs' ] )

Returns the tuple type signature for the arguments of the contract constructor .


def get_source_for(self, asm_offset, runtime=True):
        """ Solidity source code snippet related to `asm_pos` evm bytecode offset.
            If runtime is False, initialization bytecode source map is used
        """
        srcmap = self.get_srcmap(runtime)

        try:
            beg, size, _, _ = srcmap[asm_offset]
        except KeyError:
            #asm_offset pointing outside the known bytecode
            return ''

        output = ''
        nl = self.source_code[:beg].count('\n') + 1
        snippet = self.source_code[beg:beg + size]
        for l in snippet.split('\n'):
            output += '    %s  %s\n' % (nl, l)
            nl += 1
        return output

def
get_source_for
(
self
,
asm_offset
,
runtime
=
True
)
:
srcmap
=
self
.
get_srcmap
(
runtime
)
try
:
beg
,
size
,
_
,
_
=
srcmap
[
asm_offset
]
except
KeyError
:
return
''
output
=
''
nl
=
self
.
source_code
[
:
beg
]
.
count
(
'\n'
)
+
1
snippet
=
self
.
source_code
[
beg
:
beg
+
size
]
for
l
in
snippet
.
split
(
'\n'
)
:
output
+=
'    %s  %s\n'
%
(
nl
,
l
)
nl
+=
1
return
output

Solidity source code snippet related to asm_pos evm bytecode offset . If runtime is False initialization bytecode source map is used


def constructor_abi(self) -> Dict[str, Any]:
        """Returns a copy of the Solidity JSON ABI item for the contract constructor.

        The content of the returned dict is described at https://solidity.readthedocs.io/en/latest/abi-spec.html#json_
        """
        item = self._constructor_abi_item
        if item:
            return dict(item)
        return {'inputs': [], 'payable': False, 'stateMutability': 'nonpayable', 'type': 'constructor'}

def constructor_abi ( self ) -> Dict [ str , Any ] : item = self . _constructor_abi_item if item : return dict ( item ) return { 'inputs' : [ ] , 'payable' : False , 'stateMutability' : 'nonpayable' , 'type' : 'constructor' }

Returns a copy of the Solidity JSON ABI item for the contract constructor .


def get_abi(self, hsh: bytes) -> Dict[str, Any]:
        """Returns a copy of the Solidity JSON ABI item for the function associated with the selector ``hsh``.

        If no normal contract function has the specified selector, a dict describing the default or non-default
        fallback function is returned.

        The content of the returned dict is described at https://solidity.readthedocs.io/en/latest/abi-spec.html#json_
        """
        if not isinstance(hsh, (bytes, bytearray)):
            raise TypeError('The selector argument must be a concrete byte array')
        sig = self._function_signatures_by_selector.get(hsh)
        if sig is not None:
            return dict(self._function_abi_items_by_signature[sig])
        item = self._fallback_function_abi_item
        if item is not None:
            return dict(item)
        # An item describing the default fallback function.
        return {'payable': False, 'stateMutability': 'nonpayable', 'type': 'fallback'}

Returns a copy of the Solidity JSON ABI item for the function associated with the selector hsh .


def get_func_argument_types(self, hsh: bytes):
        """Returns the tuple type signature for the arguments of the function associated with the selector ``hsh``.

        If no normal contract function has the specified selector,
        the empty tuple type signature ``'()'`` is returned.
        """
        if not isinstance(hsh, (bytes, bytearray)):
            raise TypeError('The selector argument must be a concrete byte array')
        sig = self._function_signatures_by_selector.get(hsh)
        return '()' if sig is None else sig[sig.find('('):]

Returns the tuple type signature for the arguments of the function associated with the selector hsh .


def get_func_return_types(self, hsh: bytes) -> str:
        """Returns the tuple type signature for the output values of the function
        associated with the selector ``hsh``.

        If no normal contract function has the specified selector,
        the empty tuple type signature ``'()'`` is returned.
        """
        if not isinstance(hsh, (bytes, bytearray)):
            raise TypeError('The selector argument must be a concrete byte array')
        abi = self.get_abi(hsh)
        outputs = abi.get('outputs')
        return '()' if outputs is None else SolidityMetadata.tuple_signature_for_components(outputs)

Returns the tuple type signature for the output values of the function associated with the selector hsh .


def get_func_signature(self, hsh: bytes) -> Optional[str]:
        """Returns the signature of the normal function with the selector ``hsh``,
        or ``None`` if no such function exists.

        This function returns ``None`` for any selector that will be dispatched to a fallback function.
        """
        if not isinstance(hsh, (bytes, bytearray)):
            raise TypeError('The selector argument must be a concrete byte array')
        return self._function_signatures_by_selector.get(hsh)

Returns the signature of the normal function with the selector hsh or None if no such function exists .


def map_memory_callback(self, address, size, perms, name, offset, result):
        """
        Catches did_map_memory and copies the mapping into Manticore
        """
        logger.info(' '.join(("Mapping Memory @",
                              hex(address) if type(address) is int else "0x??",
                              hr_size(size), "-",
                              perms, "-",
                              f"{name}:{hex(offset) if name else ''}", "->",
                              hex(result))))
        self._emu.mem_map(address, size, convert_permissions(perms))
        self.copy_memory(address, size)

def
map_memory_callback
(
self
,
address
,
size
,
perms
,
name
,
offset
,
result
)
:
logger
.
info
(
' '
.
join
(
(
"Mapping Memory @"
,
hex
(
address
)
if
type
(
address
)
is
int
else
"0x??"
,
hr_size
(
size
)
,
"-"
,
perms
,
"-"
,
f"{name}:{hex(offset) if name else ''}"
,
"->"
,
hex
(
result
)
)
)
)
self
.
_emu
.
mem_map
(
address
,
size
,
convert_permissions
(
perms
)
)
self
.
copy_memory
(
address
,
size
)


def unmap_memory_callback(self, start, size):
        """Unmap Unicorn maps when Manticore unmaps them"""
        logger.info(f"Unmapping memory from {hex(start)} to {hex(start + size)}")

        mask = (1 << 12) - 1
        if (start & mask) != 0:
            logger.error("Memory to be unmapped is not aligned to a page")

        if (size & mask) != 0:
            size = ((size >> 12) + 1) << 12
            logger.warning("Forcing unmap size to align to a page")

        self._emu.mem_unmap(start, size)


def protect_memory_callback(self, start, size, perms):
        """ Set memory protections in Unicorn correctly """
        logger.info(f"Changing permissions on {hex(start)}:{hex(start + size)} to {perms}")
        self._emu.mem_protect(start, size, convert_permissions(perms))


def _hook_syscall(self, uc, data):
        """
        Unicorn hook that transfers control to Manticore so it can execute the syscall
        """
        logger.debug(f"Stopping emulation at {hex(uc.reg_read(self._to_unicorn_id('RIP')))} to perform syscall")
        self.sync_unicorn_to_manticore()
        from ..native.cpu.abstractcpu import Syscall
        self._to_raise = Syscall()
        uc.emu_stop()


def _hook_write_mem(self, uc, access, address, size, value, data):
        """
        Captures memory written by Unicorn
        """
        self._mem_delta[address] = (value, size)
        return True

def _hook_write_mem ( self , uc , access , address , size , value , data ) : self . _mem_delta [ address ] = ( value , size ) return True


def emulate(self, instruction):
        """
        Wrapper that runs the _step function in a loop while handling exceptions
        """

        # The emulation might restart if Unicorn needs to bring in a memory map
        # or bring a value from Manticore state.
        while True:

            # Try emulation
            self._should_try_again = False
            self._to_raise = None

            self._step(instruction)

            if not self._should_try_again:
                break

def emulate ( self , instruction ) : while True : self . _should_try_again = False self . _to_raise = None self . _step ( instruction ) if not self . _should_try_again : break


def sync_unicorn_to_manticore(self):
        """
        Copy registers and written memory back into Manticore
        """
        self.write_backs_disabled = True
        for reg in self.registers:
            val = self._emu.reg_read(self._to_unicorn_id(reg))
            self._cpu.write_register(reg, val)
        if len(self._mem_delta) > 0:
            logger.debug(f"Syncing {len(self._mem_delta)} writes back into Manticore")
        for location in self._mem_delta:
            value, size = self._mem_delta[location]
            self._cpu.write_int(location, value, size * 8)
        self.write_backs_disabled = False
        self._mem_delta = {}


def write_back_memory(self, where, expr, size):
        """ Copy memory writes from Manticore back into Unicorn in real-time """
        if self.write_backs_disabled:
            return
        if type(expr) is bytes:
            self._emu.mem_write(where, expr)
        else:
            if issymbolic(expr):
                data = [Operators.CHR(Operators.EXTRACT(expr, offset, 8)) for offset in range(0, size, 8)]
                concrete_data = []
                for c in data:
                    if issymbolic(c):
                        c = chr(solver.get_value(self._cpu.memory.constraints, c))
                    concrete_data.append(c)
                data = concrete_data
            else:
                data = [Operators.CHR(Operators.EXTRACT(expr, offset, 8)) for offset in range(0, size, 8)]
            logger.debug(f"Writing back {hr_size(size // 8)} to {hex(where)}: {data}")
            # TODO - the extra encoding is to handle null bytes output as strings when we concretize. That's probably a bug.
            self._emu.mem_write(where, b''.join(b.encode('utf-8') if type(b) is str else b for b in data))

Copy memory writes from Manticore back into Unicorn in real - time


def write_back_register(self, reg, val):
        """ Sync register state from Manticore -> Unicorn"""
        if self.write_backs_disabled:
            return
        if issymbolic(val):
            logger.warning("Skipping Symbolic write-back")
            return
        if reg in self.flag_registers:
            self._emu.reg_write(self._to_unicorn_id('EFLAGS'), self._cpu.read_register('EFLAGS'))
            return
        self._emu.reg_write(self._to_unicorn_id(reg), val)

def
write_back_register
(
self
,
reg
,
val
)
:
if
self
.
write_backs_disabled
:
return
if
issymbolic
(
val
)
:
logger
.
warning
(
"Skipping Symbolic write-back"
)
return
if
reg
in
self
.
flag_registers
:
self
.
_emu
.
reg_write
(
self
.
_to_unicorn_id
(
'EFLAGS'
)
,
self
.
_cpu
.
read_register
(
'EFLAGS'
)
)
return
self
.
_emu
.
reg_write
(
self
.
_to_unicorn_id
(
reg
)
,
val
)

Sync register state from Manticore - > Unicorn


def update_segment(self, selector, base, size, perms):
        """ Only useful for setting FS right now. """
        logger.info("Updating selector %s to 0x%02x (%s bytes) (%s)", selector, base, size, perms)
        if selector == 99:
            self.set_fs(base)
        else:
            logger.error("No way to write segment: %d", selector)


def deprecated(message: str):
    """A decorator for marking functions as deprecated. """
    assert isinstance(message, str), "The deprecated decorator requires a message string argument."

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            warnings.warn(f"`{func.__qualname__}` is deprecated. {message}",
                          category=ManticoreDeprecationWarning, stacklevel=2)
            return func(*args, **kwargs)

        return wrapper

    return decorator

A decorator for marking functions as deprecated .


def perm(lst, func):
    ''' Produce permutations of `lst`, where permutations are mutated by `func`. Used for flipping constraints. highly
    possible that returned constraints can be unsat this does it blindly, without any attention to the constraints
    themselves

    Considering lst as a list of constraints, e.g.

      [ C1, C2, C3 ]

    we'd like to consider scenarios of all possible permutations of flipped constraints, excluding the original list.
    So we'd like to generate:

      [ func(C1),      C2 ,       C3 ],
      [      C1 , func(C2),       C3 ],
      [ func(C1), func(C2),       C3 ],
      [      C1 ,      C2 ,  func(C3)],
      .. etc

    This is effectively treating the list of constraints as a bitmask of width len(lst) and counting up, skipping the
    0th element (unmodified array).

    The code below yields lists of constraints permuted as above by treating list indeces as bitmasks from 1 to
     2**len(lst) and applying func to all the set bit offsets.

    '''
    for i in range(1, 2**len(lst)):
        yield [func(item) if (1<<j)&i else item for (j, item) in enumerate(lst)]

def perm ( lst , func ) : for i in range ( 1 , 2 ** len ( lst ) ) : yield [ func ( item ) if ( 1 << j ) & i else item for ( j , item ) in enumerate ( lst ) ]

Produce permutations of lst where permutations are mutated by func . Used for flipping constraints . highly possible that returned constraints can be unsat this does it blindly without any attention to the constraints themselves


def input_from_cons(constupl, datas):
    ' solve bytes in |datas| based on '
    def make_chr(c):
        try:
            return chr(c)
        except Exception:
            return c
    newset = constraints_to_constraintset(constupl)

    ret = ''
    for data in datas:
        for c in data:
            ret += make_chr(solver.get_value(newset, c))
    return ret

def
input_from_cons
(
constupl
,
datas
)
:
' solve bytes in |datas| based on '
def
make_chr
(
c
)
:
try
:
return
chr
(
c
)
except
Exception
:
return
c
newset
=
constraints_to_constraintset
(
constupl
)
ret
=
''
for
data
in
datas
:
for
c
in
data
:
ret
+=
make_chr
(
solver
.
get_value
(
newset
,
c
)
)
return
ret


def symbolic_run_get_cons(trace):
    '''
    Execute a symbolic run that follows a concrete run; return constraints generated
    and the stdin data produced
    '''

    m2 = Manticore.linux(prog, workspace_url='mem:')
    f = Follower(trace)
    m2.verbosity(VERBOSITY)
    m2.register_plugin(f)

    def on_term_testcase(mcore, state, stateid, err):
        with m2.locked_context() as ctx:
            readdata = []
            for name, fd, data in state.platform.syscall_trace:
                if name in ('_receive', '_read') and fd == 0:
                    readdata.append(data)
            ctx['readdata'] = readdata
            ctx['constraints'] = list(state.constraints.constraints)

    m2.subscribe('will_terminate_state', on_term_testcase)

    m2.run()

    constraints = m2.context['constraints']
    datas = m2.context['readdata']

    return constraints, datas

def symbolic_run_get_cons ( trace ) : m2 = Manticore . linux ( prog , workspace_url = 'mem:' ) f = Follower ( trace ) m2 . verbosity ( VERBOSITY ) m2 . register_plugin ( f ) def on_term_testcase ( mcore , state , stateid , err ) : with m2 . locked_context ( ) as ctx : readdata = [ ] for name , fd , data in state . platform . syscall_trace : if name in ( '_receive' , '_read' ) and fd == 0 : readdata . append ( data ) ctx [ 'readdata' ] = readdata ctx [ 'constraints' ] = list ( state . constraints . constraints ) m2 . subscribe ( 'will_terminate_state' , on_term_testcase ) m2 . run ( ) constraints = m2 . context [ 'constraints' ] datas = m2 . context [ 'readdata' ] return constraints , datas

Execute a symbolic run that follows a concrete run ; return constraints generated and the stdin data produced


def empty_platform(cls, arch):
        """
        Create a platform without an ELF loaded.

        :param str arch: The architecture of the new platform
        :rtype: Linux
        """
        platform = cls(None)
        platform._init_cpu(arch)
        platform._init_std_fds()
        return platform

def empty_platform ( cls , arch ) : platform = cls ( None ) platform . _init_cpu ( arch ) platform . _init_std_fds ( ) return platform

Create a platform without an ELF loaded .


def _execve(self, program, argv, envp):
        """
        Load `program` and establish program state, such as stack and arguments.

        :param program str: The ELF binary to load
        :param argv list: argv array
        :param envp list: envp array
        """
        argv = [] if argv is None else argv
        envp = [] if envp is None else envp

        logger.debug(f"Loading {program} as a {self.arch} elf")

        self.load(program, envp)
        self._arch_specific_init()

        self._stack_top = self.current.STACK
        self.setup_stack([program] + argv, envp)

        nprocs = len(self.procs)
        nfiles = len(self.files)
        assert nprocs > 0
        self.running = list(range(nprocs))

        # Each process can wait for one timeout
        self.timers = [None] * nprocs
        # each fd has a waitlist
        self.rwait = [set() for _ in range(nfiles)]
        self.twait = [set() for _ in range(nfiles)]

        # Install event forwarders
        for proc in self.procs:
            self.forward_events_from(proc)

Load program and establish program state such as stack and arguments .


def _init_arm_kernel_helpers(self):
        """
        ARM kernel helpers

        https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt
        """

        page_data = bytearray(b'\xf1\xde\xfd\xe7' * 1024)

        # Extracted from a RPi2
        preamble = binascii.unhexlify(
            'ff0300ea' +
            '650400ea' +
            'f0ff9fe5' +
            '430400ea' +
            '220400ea' +
            '810400ea' +
            '000400ea' +
            '870400ea'
        )

        # XXX(yan): The following implementations of cmpxchg and cmpxchg64 were
        # handwritten to not use any exclusive instructions (e.g. ldrexd) or
        # locking. For actual implementations, refer to
        # arch/arm64/kernel/kuser32.S in the Linux source code.
        __kuser_cmpxchg64 = binascii.unhexlify(
            '30002de9' +  # push    {r4, r5}
            '08c09de5' +  # ldr     ip, [sp, #8]
            '30009ce8' +  # ldm     ip, {r4, r5}
            '010055e1' +  # cmp     r5, r1
            '00005401' +  # cmpeq   r4, r0
            '0100a013' +  # movne   r0, #1
            '0000a003' +  # moveq   r0, #0
            '0c008c08' +  # stmeq   ip, {r2, r3}
            '3000bde8' +  # pop     {r4, r5}
            '1eff2fe1'   # bx      lr
        )

        __kuser_dmb = binascii.unhexlify(
            '5bf07ff5' +  # dmb ish
            '1eff2fe1'   # bx lr
        )

        __kuser_cmpxchg = binascii.unhexlify(
            '003092e5' +  # ldr     r3, [r2]
            '000053e1' +  # cmp     r3, r0
            '0000a003' +  # moveq   r0, #0
            '00108205' +  # streq   r1, [r2]
            '0100a013' +  # movne   r0, #1
            '1eff2fe1'   # bx      lr
        )

        # Map a TLS segment
        self._arm_tls_memory = self.current.memory.mmap(None, 4, 'rw ')

        __kuser_get_tls = binascii.unhexlify(
            '04009FE5' +  # ldr r0, [pc, #4]
            '010090e8' +  # ldm r0, {r0}
            '1eff2fe1'   # bx lr
        ) + struct.pack('<I', self._arm_tls_memory)

        tls_area = b'\x00' * 12

        version = struct.pack('<I', 5)

        def update(address, code):
            page_data[address:address + len(code)] = code

        # Offsets from Documentation/arm/kernel_user_helpers.txt in Linux
        update(0x000, preamble)
        update(0xf60, __kuser_cmpxchg64)
        update(0xfa0, __kuser_dmb)
        update(0xfc0, __kuser_cmpxchg)
        update(0xfe0, __kuser_get_tls)
        update(0xff0, tls_area)
        update(0xffc, version)

        self.current.memory.mmap(0xffff0000, len(page_data), 'r x', page_data)

def
_init_arm_kernel_helpers
(
self
)
:
page_data
=
bytearray
(
b'\xf1\xde\xfd\xe7'
*
1024
)
preamble
=
binascii
.
unhexlify
(
'ff0300ea'
+
'650400ea'
+
'f0ff9fe5'
+
'430400ea'
+
'220400ea'
+
'810400ea'
+
'000400ea'
+
'870400ea'
)
__kuser_cmpxchg64
=
binascii
.
unhexlify
(
'30002de9'
+
'08c09de5'
+
'30009ce8'
+
'010055e1'
+
'00005401'
+
'0100a013'
+
'0000a003'
+
'0c008c08'
+
'3000bde8'
+
'1eff2fe1'
)
__kuser_dmb
=
binascii
.
unhexlify
(
'5bf07ff5'
+
'1eff2fe1'
)
__kuser_cmpxchg
=
binascii
.
unhexlify
(
'003092e5'
+
'000053e1'
+
'0000a003'
+
'00108205'
+
'0100a013'
+
'1eff2fe1'
)
self
.
_arm_tls_memory
=
self
.
current
.
memory
.
mmap
(
,
4
,
'rw '
)
__kuser_get_tls
=
binascii
.
unhexlify
(
'04009FE5'
+
'010090e8'
+
'1eff2fe1'
)
+
struct
.
pack
(
'<I'
,
self
.
_arm_tls_memory
)
tls_area
=
b'\x00'
*
12
version
=
struct
.
pack
(
'<I'
,
5
)
def
update
(
address
,
code
)
:
page_data
[
address
:
address
+
len
(
code
)
]
=
code
update
(
0x000
,
preamble
)
update
(
0xf60
,
__kuser_cmpxchg64
)
update
(
0xfa0
,
__kuser_dmb
)
update
(
0xfc0
,
__kuser_cmpxchg
)
update
(
0xfe0
,
__kuser_get_tls
)
update
(
0xff0
,
tls_area
)
update
(
0xffc
,
version
)
self
.
current
.
memory
.
mmap
(
0xffff0000
,
len
(
page_data
)
,
'r x'
,
page_data
)


def _open(self, f):
        """
        Adds a file descriptor to the current file descriptor list

        :rtype: int
        :param f: the file descriptor to add.
        :return: the index of the file descriptor in the file descr. list
        """
        if None in self.files:
            fd = self.files.index(None)
            self.files[fd] = f
        else:
            fd = len(self.files)
            self.files.append(f)
        return fd

def _open ( self , f ) : if None in self . files : fd = self . files . index ( None ) self . files [ fd ] = f else : fd = len ( self . files ) self . files . append ( f ) return fd


def sys_openat(self, dirfd, buf, flags, mode):
        """
        Openat SystemCall - Similar to open system call except dirfd argument
        when path contained in buf is relative, dirfd is referred to set the relative path
        Special value AT_FDCWD set for dirfd to set path relative to current directory

        :param dirfd: directory file descriptor to refer in case of relative path at buf
        :param buf: address of zero-terminated pathname
        :param flags: file access bits
        :param mode: file permission mode
        """

        filename = self.current.read_string(buf)
        dirfd = ctypes.c_int32(dirfd).value

        if os.path.isabs(filename) or dirfd == self.FCNTL_FDCWD:
            return self.sys_open(buf, flags, mode)

        try:
            dir_entry = self._get_fd(dirfd)
        except FdError as e:
            logger.info("openat: Not valid file descriptor. Returning EBADF")
            return -e.err

        if not isinstance(dir_entry, Directory):
            logger.info("openat: Not directory descriptor. Returning ENOTDIR")
            return -errno.ENOTDIR

        dir_path = dir_entry.name

        filename = os.path.join(dir_path, filename)
        try:
            f = self._sys_open_get_file(filename, flags)
            logger.debug(f"Opening file {filename} for real fd {f.fileno()}")
        except IOError as e:
            logger.info(f"Could not open file {filename}. Reason: {e!s}")
            return -e.errno if e.errno is not None else -errno.EINVAL

        return self._open(f)

Openat SystemCall - Similar to open system call except dirfd argument when path contained in buf is relative dirfd is referred to set the relative path Special value AT_FDCWD set for dirfd to set path relative to current directory


def sys_rename(self, oldnamep, newnamep):
        """
        Rename filename `oldnamep` to `newnamep`.

        :param int oldnamep: pointer to oldname
        :param int newnamep: pointer to newname
        """
        oldname = self.current.read_string(oldnamep)
        newname = self.current.read_string(newnamep)

        ret = 0
        try:
            os.rename(oldname, newname)
        except OSError as e:
            ret = -e.errno

        return ret

def sys_rename ( self , oldnamep , newnamep ) : oldname = self . current . read_string ( oldnamep ) newname = self . current . read_string ( newnamep ) ret = 0 try : os . rename ( oldname , newname ) except OSError as e : ret = - e . errno return ret


def sys_fsync(self, fd):
        """
        Synchronize a file's in-core state with that on disk.
        """

        ret = 0
        try:
            self.files[fd].sync()
        except IndexError:
            ret = -errno.EBADF
        except FdError:
            ret = -errno.EINVAL

        return ret

def sys_fsync ( self , fd ) : ret = 0 try : self . files [ fd ] . sync ( ) except IndexError : ret = - errno . EBADF except FdError : ret = - errno . EINVAL return ret

Synchronize a file s in - core state with that on disk .


def sys_rt_sigaction(self, signum, act, oldact):
        """Wrapper for sys_sigaction"""
        return self.sys_sigaction(signum, act, oldact)

def sys_rt_sigaction ( self , signum , act , oldact ) : return self . sys_sigaction ( signum , act , oldact )


def sys_rt_sigprocmask(self, cpu, how, newset, oldset):
        """Wrapper for sys_sigprocmask"""
        return self.sys_sigprocmask(cpu, how, newset, oldset)

def sys_rt_sigprocmask ( self , cpu , how , newset , oldset ) : return self . sys_sigprocmask ( cpu , how , newset , oldset )


def sys_chroot(self, path):
        """
        An implementation of chroot that does perform some basic error checking,
        but does not actually chroot.

        :param path: Path to chroot
        """
        if path not in self.current.memory:
            return -errno.EFAULT

        path_s = self.current.read_string(path)
        if not os.path.exists(path_s):
            return -errno.ENOENT

        if not os.path.isdir(path_s):
            return -errno.ENOTDIR

        return -errno.EPERM

def sys_chroot ( self , path ) : if path not in self . current . memory : return - errno . EFAULT path_s = self . current . read_string ( path ) if not os . path . exists ( path_s ) : return - errno . ENOENT if not os . path . isdir ( path_s ) : return - errno . ENOTDIR return - errno . EPERM

An implementation of chroot that does perform some basic error checking but does not actually chroot .


def sys_mmap_pgoff(self, address, size, prot, flags, fd, offset):
        """Wrapper for mmap2"""
        return self.sys_mmap2(address, size, prot, flags, fd, offset)

def sys_mmap_pgoff ( self , address , size , prot , flags , fd , offset ) : return self . sys_mmap2 ( address , size , prot , flags , fd , offset )


def syscall(self):
        """
        Syscall dispatcher.
        """

        index = self._syscall_abi.syscall_number()

        try:
            table = getattr(linux_syscalls, self.current.machine)
            name = table.get(index, None)
            implementation = getattr(self, name)
        except (AttributeError, KeyError):
            if name is not None:
                raise SyscallNotImplemented(index, name)
            else:
                raise Exception(f"Bad syscall index, {index}")

        return self._syscall_abi.invoke(implementation)

def
syscall
(
self
)
:
index
=
self
.
_syscall_abi
.
syscall_number
(
)
try
:
table
=
getattr
(
linux_syscalls
,
self
.
current
.
machine
)
name
=
table
.
get
(
index
,
)
implementation
=
getattr
(
self
,
name
)
except
(
AttributeError
,
KeyError
)
:
if
name
is
not
:
raise
SyscallNotImplemented
(
index
,
name
)
else
:
raise
Exception
(
f"Bad syscall index, {index}"
)
return
self
.
_syscall_abi
.
invoke
(
implementation
)


def sched(self):
        """ Yield CPU.
            This will choose another process from the running list and change
            current running process. May give the same cpu if only one running
            process.
        """
        if len(self.procs) > 1:
            logger.debug("SCHED:")
            logger.debug(f"\tProcess: {self.procs!r}")
            logger.debug(f"\tRunning: {self.running!r}")
            logger.debug(f"\tRWait: {self.rwait!r}")
            logger.debug(f"\tTWait: {self.twait!r}")
            logger.debug(f"\tTimers: {self.timers!r}")
            logger.debug(f"\tCurrent clock: {self.clocks}")
            logger.debug(f"\tCurrent cpu: {self._current}")

        if len(self.running) == 0:
            logger.debug("None running checking if there is some process waiting for a timeout")
            if all([x is None for x in self.timers]):
                raise Deadlock()
            self.clocks = min(x for x in self.timers if x is not None) + 1
            self.check_timers()
            assert len(self.running) != 0, "DEADLOCK!"
            self._current = self.running[0]
            return
        next_index = (self.running.index(self._current) + 1) % len(self.running)
        next_running_idx = self.running[next_index]
        if len(self.procs) > 1:
            logger.debug(f"\tTransfer control from process {self._current} to {next_running_idx}")
        self._current = next_running_idx

Yield CPU . This will choose another process from the running list and change current running process . May give the same cpu if only one running process .


def wait(self, readfds, writefds, timeout):
        """ Wait for file descriptors or timeout.
            Adds the current process in the correspondent waiting list and
            yield the cpu to another running process.
        """
        logger.debug("WAIT:")
        logger.debug(f"\tProcess {self._current} is going to wait for [ {readfds!r} {writefds!r} {timeout!r} ]")
        logger.debug(f"\tProcess: {self.procs!r}")
        logger.debug(f"\tRunning: {self.running!r}")
        logger.debug(f"\tRWait: {self.rwait!r}")
        logger.debug(f"\tTWait: {self.twait!r}")
        logger.debug(f"\tTimers: {self.timers!r}")

        for fd in readfds:
            self.rwait[fd].add(self._current)
        for fd in writefds:
            self.twait[fd].add(self._current)
        if timeout is not None:
            self.timers[self._current] = self.clocks + timeout
        procid = self._current
        # self.sched()
        next_index = (self.running.index(procid) + 1) % len(self.running)
        self._current = self.running[next_index]
        logger.debug(f"\tTransfer control from process {procid} to {self._current}")
        logger.debug(f"\tREMOVING {procid!r} from {self.running!r}. Current: {self._current!r}")
        self.running.remove(procid)
        if self._current not in self.running:
            logger.debug("\tCurrent not running. Checking for timers...")
            self._current = None
            self.check_timers()

Wait for file descriptors or timeout . Adds the current process in the correspondent waiting list and yield the cpu to another running process .


def awake(self, procid):
        """ Remove procid from waitlists and reestablish it in the running list """
        logger.debug(f"Remove procid:{procid} from waitlists and reestablish it in the running list")
        for wait_list in self.rwait:
            if procid in wait_list:
                wait_list.remove(procid)
        for wait_list in self.twait:
            if procid in wait_list:
                wait_list.remove(procid)
        self.timers[procid] = None
        self.running.append(procid)
        if self._current is None:
            self._current = procid


def signal_receive(self, fd):
        """ Awake one process waiting to receive data on fd """
        connections = self.connections
        if connections(fd) and self.twait[connections(fd)]:
            procid = random.sample(self.twait[connections(fd)], 1)[0]
            self.awake(procid)

def signal_receive ( self , fd ) : connections = self . connections if connections ( fd ) and self . twait [ connections ( fd ) ] : procid = random . sample ( self . twait [ connections ( fd ) ] , 1 ) [ 0 ] self . awake ( procid )


def check_timers(self):
        """ Awake process if timer has expired """
        if self._current is None:
            # Advance the clocks. Go to future!!
            advance = min([self.clocks] + [x for x in self.timers if x is not None]) + 1
            logger.debug(f"Advancing the clock from {self.clocks} to {advance}")
            self.clocks = advance
        for procid in range(len(self.timers)):
            if self.timers[procid] is not None:
                if self.clocks > self.timers[procid]:
                    self.procs[procid].PC += self.procs[procid].instruction.size
                    self.awake(procid)