예제 #1
0
    def enter_Extract(self, arg):
        hb = arg.high_bit
        lb = arg.low_bit

        val = self.computeExp(arg.expr)
        size = self.lastSize

        #https://github.com/BinaryAnalysisPlatform/bap/blob/master/lib/bap/bap.mli#L2299
        if hb > size - 1:
            hb = size - 1
        if lb < 0:
            lb = 0

        if val.isSym:
            self.result = val.Extract(hb, lb)
        else:
            val2 = bin(val.val)[2:].zfill(size)
            val2 = val2[::
                        -1]  #Invert bits so its easier to return result (hb - lb converts to lb - hb)

            result = val2[lb:hb + 1]  #Inclusive the last
            result = result[::-1]  #Invert again
            self.result = ADT(twoComplement(int(result, 2), hb - lb + 1))

        copyInformation(val, self.result)
        self.lastSize = hb - lb + 1  #size of result is how many bits we've taken from expression value
        return True
예제 #2
0
    def enter_SLE(self, arg):

        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)
        rhsSize = self.lastSize

        if not lhs.isSym:
            if bitIsSet(lhs.val, lhsSize -
                        1):  #If 32th bit is set <=> number is negative
                lhs = -lhs
                lhs = lhs.twoComplement(lhsSize)
                lhs = -lhs  #Get real value from two complement negative

        if not rhs.isSym:
            if bitIsSet(rhs.val, rhsSize -
                        1):  #If 32th bit is set <=> number is negative
                rhs = -rhs
                rhs = rhs.twoComplement(rhsSize)
                rhs = -rhs  #Get real value from two complement negative

        if lhs.isSym or rhs.isSym:
            self.result = ADT(
                If(lhs.val <= rhs.val, BitVecVal(1, 1), BitVecVal(0, 1)))
        else:
            self.result = ADT(lhs.val <= rhs.val)

        copyInformation(lhs, self.result)
        copyInformation(rhs, self.result)

        return True
예제 #3
0
    def enter_Ite(self, arg):
        cond = self.computeExp(arg.cond)
        assert cond.val == 1 or cond.val == 0 or cond.isSym

        if cond.val == 1:
            self.result = self.computeExp(arg.true)
        elif cond.val == 0:
            self.result = self.computeExp(arg.false)
        else:
            canBeTrue = self.mem.isItPossible(cond.val == True)
            canBeFalse = self.mem.isItPossible(cond.val == False)

            assert canBeTrue or canBeFalse  #I mean, it has to be one of them...

            if canBeTrue and canBeFalse:
                name = 'ite_{}'.format(self.mem.genSymName(
                ))  #Generate unique name for symbolic var

                val1 = self.computeExp(arg.true)
                val2 = self.computeExp(arg.false)
                var = BitVec(name, self.lastSize)

                self.mem.addRestr(
                    Or(And(cond.val == True, var == val1.val),
                       And(cond == False, var == val2.val)))
                self.result = ADT(var)
            elif canBeTrue:  #If condition can only be true
                self.mem.addRestr(cond.val == True)
                self.result = self.computeExp(arg.true)
            elif canBeFalse:  #If condition can only be false
                self.mem.addRestr(
                    cond.val == False)  #Add restriction to solver
                self.result = self.computeExp(arg.false)

        return True
예제 #4
0
    def enter_SMOD(self, arg):

        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)
        rhsSize = self.lastSize

        if not lhs.isSym:
            if bitIsSet(lhs.val, lhsSize -
                        1):  #If 32th bit is set <=> number is negative
                lhs = -lhs
                lhs = lhs.twoComplement(lhsSize)
                lhs = -lhs  #Get real value from two complement negative

        if not rhs.isSym:
            if bitIsSet(rhs.val, rhsSize -
                        1):  #If 32th bit is set <=> number is negative
                rhs = -rhs
                rhs = rhs.twoComplement(rhsSize)
                rhs = -rhs  #Get real value from two complement negative

        if not lhs.isSym and not rhs.isSym:
            result = ADT(self.trunc_divmod(lhs.val, rhs.val))
        else:
            result = lhs % rhs  #% operator in z3 is signed modulus already

        self.result = result.twoComplement(lhsSize)
        self.lastSize = lhsSize
        return True
예제 #5
0
    def enter_Load(self, arg):
        toLoad = arg.idx
        val = self.computeExp(toLoad)

        if type(val) == TLSAccess:
            self.result = ADT(self.mem.tlsLoad(val.addr, arg.size))
        else:
            val = self.mem.load(val.val, size=arg.size)
            self.result = val.twoComplement(arg.size)

        self.lastSize = arg.size
        return True
예제 #6
0
    def enter_LOW(self, arg):
        val = self.computeExp(arg.expr)

        if val.isSym:
            self.result = val.Extract(arg.size - 1, 0)
        else:
            bits = '1' * arg.size
            self.result = ADT(twoComplement(val.val & int(bits, 2), arg.size))

        copyInformation(val, self.result)
        self.lastSize = arg.size
        return True
예제 #7
0
    def enter_EQ(self, arg):

        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)
        if lhs.isSym or rhs.isSym:
            self.result = ADT(
                If(lhs.val == rhs.val, BitVecVal(1, 1), BitVecVal(0, 1)))
        else:
            self.result = ADT(lhs.val == rhs.val)

        copyInformation(lhs, self.result)
        copyInformation(rhs, self.result)

        return True
예제 #8
0
    def enter_HIGH(self, arg):
        val = self.computeExp(arg.expr)
        size = self.lastSize

        if val.isSym:
            self.result = val.Extract(size - 1, size - arg.size)
        else:
            bits = '1' * arg.size
            bits = bits + '0' * (size - arg.size)
            mask = int(bits, 2)
            self.result = ADT(
                twoComplement((val.val & mask) >> (size - arg.size), arg.size))
            copyInformation(val, self.result)

        self.lastSize = arg.size
        return True
예제 #9
0
    def enter_ARSHIFT(self, arg):

        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)

        if lhs.isSym or rhs.isSym:
            self.result = lhs.LShR(rhs)
        else:
            self.result = lhs.copy()
            for i in range(rhs.val):
                self.result = (self.result >> ADT(1))
                if bitIsSet(lhs.val, lhsSize - 1):
                    self.result = ADT(pow(2, lhsSize - 1)) + self.result
            self.result = self.result.twoComplement(lhsSize)

        self.lastSize = lhsSize
        return True
예제 #10
0
    def enter_SIGNED(self, arg):
        afterSize = arg.size
        val = self.computeExp(arg.expr)
        beforeSize = self.lastSize

        if val.isSym:
            self.result = val.SignExt(afterSize - beforeSize)
        else:
            val2 = bin(val.val)[2:].zfill(beforeSize)
            if val2[0] == '1':  #If MSB is 1, extend with 1's
                extend = '1' * (afterSize - beforeSize
                                )  #How many bits to extend
            else:
                extend = '0' * (afterSize - beforeSize)

            result = int(extend + val2, 2)
            self.result = ADT(twoComplement(result, afterSize))
            copyInformation(val, self.result)

        self.lastSize = afterSize
        return True
예제 #11
0
    def enter_Concat(self, arg):
        lhs = self.computeExp(arg.lhs)
        sizeLhs = self.lastSize
        rhs = self.computeExp(arg.rhs)
        sizeRhs = self.lastSize

        if lhs.isSym or rhs.isSym:
            if not lhs.isSym:
                lhs.val = BitVecVal(lhs.val, sizeLhs)
            if not rhs.isSym:
                rhs.val = BitVecVal(rhs.val, sizeRhs)
            self.result = lhs.Concat(rhs)
        else:
            rhs2 = bin(rhs.val)[2:].zfill(sizeRhs)
            lhs2 = bin(lhs.val)[2:].zfill(sizeLhs)
            self.result = ADT(
                int(lhs2 + rhs2,
                    2))  #Join them together and take the integer value
            copyInformation(lhs, self.result)
            copyInformation(rhs, self.result)

        self.lastSize = sizeLhs + sizeRhs
        return True
예제 #12
0
 def enter_Int(self, arg):
     self.result = ADT(twoComplement(arg.value, arg.size))
     self.lastSize = arg.size
     return True
예제 #13
0
 def enter_Unknown(self, arg):
     self.result = ADT(0x0)  #UNKNOWN IS 0x0, everyone knows that
     return True
예제 #14
0
 def enter_CpuExn(self, arg):
     print("CPU Exception occured on one of the memories. Maybe div by 0")
     print(arg)
     self.mem.hlt = True
     self.result = ADT(0x0)
     return True
예제 #15
0
class BilExec(bap.bil.Visitor):
    ''' Computes expressions in bil
			All methods return True to stop computation-
			Loads from memories always return ADTs and store's should also store ADTs 

		#Missing enter_In, enter_Out, enter_Both and enter_While '''
    def __init__(self, mem, prog):
        self.prog = prog
        self.remainingCode = None
        self.reset(mem)

    def reset(self, mem):
        self.mem = mem
        self.result = None  #Last result
        self.lastSize = None  #Useful to know size of last computed subexpression
        self.new_mems = []

    def getNewMems(self):
        toReturn = self.new_mems
        self.new_mems = []
        return toReturn

    def computeExp(self, exp, nullIsFine=False):
        if exp == ():
            return None

        assert type(exp) != tuple

        runSafetyPolicies(exp, self, self.mem)
        if config.VULN_FOUND:
            return None

        self.run(exp)

        if not nullIsFine and self.result == None and not isinstance(
                exp, bap.bil.Jmp):
            print('ERROR - result for', exp, ' is NULL')
            print('This should never happen!')
            terminate()

        res = self.result

        if res is not None and res.isSym:
            res.val = simplify(
                res.val)  #Simplify after computing expression...

        if config.LOGGING:  #If logging is enabled...
            if res is not None and type(res.val) == int:
                toDebug = str(exp) + ' --> ' + hex(res.val)
                logging.debug(toDebug)

            elif res is not None:
                toDebug = str(exp) + ' --> ' + str(
                    res.val)  #This takes a lot of time for large symbols
                logging.debug(toDebug)

        self.result = None  #RESET result in case we want to reuse the instance
        return res

    def enter_Var(self, arg):
        if arg.name == "mem":
            return True

        if type(arg.type) != Imm:
            print('TODO - enter_var. type is not Imm')
            print('This should never happen!')
            terminate()

        name = arg.name
        val = self.mem.load(name, size=arg.type.size)
        if type(
                val
        ) != TLSAccess:  #FIXME - maybe isTLSAccess should be a field of adt
            if val.isSym and val.sz < arg.type.size:
                toExtend = arg.type.size - val.sz
                val = val.ZeroExt(toExtend)

        self.result = val.twoComplement(arg.type.size)
        self.lastSize = arg.type.size
        return True

    def enter_Int(self, arg):
        self.result = ADT(twoComplement(arg.value, arg.size))
        self.lastSize = arg.size
        return True

    def enter_Load(self, arg):
        toLoad = arg.idx
        val = self.computeExp(toLoad)

        if type(val) == TLSAccess:
            self.result = ADT(self.mem.tlsLoad(val.addr, arg.size))
        else:
            val = self.mem.load(val.val, size=arg.size)
            self.result = val.twoComplement(arg.size)

        self.lastSize = arg.size
        return True

    def enter_Store(self, arg):
        size = arg.size

        val = self.computeExp(arg.value)
        dest = self.computeExp(arg.idx)

        if type(dest) == TLSAccess:
            self.mem.tlsStore(dest.addr, val)
        else:
            self.mem.store(dest.val, val, size=size)

        self.result = None
        self.lastSize = None
        return True

    def enter_Move(self, arg):
        name = arg.var.name

        if name == "mem":  #We handle memory our own way
            self.computeExp(arg.expr, nullIsFine=True)
            self.result = None
            return True

        size = arg.var.type.size
        val = self.computeExp(arg.expr)

        self.mem.store(name, val, size)

        self.result = None
        self.lastSize = None
        return True

    def enter_Jmp(self, arg):
        val = self.computeExp(arg.arg)

        assert not val.isSym, "Indirect jumps still not completely supported"

        self.mem.setIP(val.val)
        self.mem.jumped = True  #Needed when jumping to same instruction
        self.result = None
        self.lastSize = None
        return True

    def enter_Special(self, arg):
        ''' syscalls go here '''

        if arg.arg == 'Unknown Semantics':
            print(
                "I found something that could not be lifted. Maybe floating point operations"
            )
            self.mem.hlt = True
        elif arg.arg == "int 0x80":
            if 'syscall' in summaries:
                code = summaries['syscall']
                code.execute(self, self.mem)
        elif arg.arg == "lock":
            pass  #No multi threaded programs here
        else:
            self.TODO("Special operation", arg)

        return True

    def enter_If(self, arg):
        cond = self.computeExp(arg.cond)
        assert cond.val == 1 or cond.val == 0 or cond.isSym

        if cond.val == 1:
            if type(arg.true) == tuple:
                for statement in arg.true:
                    self.run(statement)
            else:
                self.run(arg.true)
        elif cond.val == 0:
            if type(arg.false) == tuple:
                for statement in arg.false:
                    self.run(statement)
            else:
                self.run(arg.false)
        else:
            canBeTrue = self.mem.isItPossible(cond.val == True)
            canBeFalse = self.mem.isItPossible(cond.val == False)

            #If condition can be both true and false
            if canBeTrue and canBeFalse:

                self.mem.executedIf = True
                if self.remainingCode is not None:
                    if type(self.remainingCode) != tuple:
                        self.remainingCode = (self.remainingCode, )

                #Make a copy of the memory
                mem1 = self.mem.copy()
                mem1.nextRestr.append(cond.val == True)
                mem1.nextFunc = arg.true

                if type(mem1.nextFunc) != tuple:
                    mem1.nextFunc = (mem1.nextFunc, )

                if self.remainingCode is not None:
                    mem1.nextFunc = mem1.nextFunc + self.remainingCode

                self.new_mems.append(mem1)

                mem2 = self.mem.copy()
                mem2.nextRestr.append(cond.val == False)
                mem2.nextFunc = arg.false

                if type(mem2.nextFunc) != tuple:
                    mem2.nextFunc = (mem2.nextFunc, )
                if self.remainingCode is not None:
                    mem2.nextFunc = mem2.nextFunc + self.remainingCode

                self.new_mems.append(mem2)

            elif canBeTrue:  #If condition can only be true
                self.mem.addRestr(cond.val == True)  #Add restriction to solver
                self.run(arg.true)

            elif canBeFalse:  #If condition can only be false
                self.mem.addRestr(
                    cond.val == False)  #Add restriction to solver
                self.run(arg.false)

        return True

    def enter_CpuExn(self, arg):
        print("CPU Exception occured on one of the memories. Maybe div by 0")
        print(arg)
        self.mem.hlt = True
        self.result = ADT(0x0)
        return True

    #Binary Operations
    def enter_PLUS(self, arg):
        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)
        result = lhs + rhs
        self.result = result.twoComplement(self.lastSize)
        return True

    def enter_MINUS(self, arg):
        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)
        rhs = -rhs
        rhs = rhs.twoComplement(
            self.lastSize)  #Compute 2-complement of negative
        result = lhs + rhs
        self.result = result.twoComplement(
            self.lastSize)  #Add lhs to 2-complement of rhs
        return True

    def enter_TIMES(self, arg):
        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)
        result = lhs * rhs
        self.result = result.twoComplement(self.lastSize)
        return True

    def enter_SDIVIDE(self, arg):
        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)
        rhsSize = self.lastSize
        negative = False

        if not lhs.isSym:
            if bitIsSet(lhs.val, lhsSize -
                        1):  #If MSB bit is set <=> number is negative
                negative = not negative
                lhs = -lhs
                lhs = lhs.twoComplement(lhsSize)

        if not rhs.isSym:
            if bitIsSet(rhs.val, rhsSize -
                        1):  #If 32th bit is set <=> number is negative
                negative = not negative
                rhs = -rhs
                rhs = rhs.twoComplement(rhsSize)

        if lhs.isSym or rhs.isSym:
            val = lhs / rhs  #Z3 bitvec integer division is '/'
        else:
            val = lhs // rhs

        if negative:
            val = -val

        self.result = val.twoComplement(lhsSize)
        self.lastSize = lhsSize
        return True

    def enter_DIVIDE(self, arg):
        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)

        if lhs.isSym or rhs.isSym:
            self.result = lhs.UDiv(rhs)
        else:
            result = lhs // rhs
            self.result = result.twoComplement(lhsSize)

        self.lastSize = lhsSize
        return True

    def enter_MOD(self, arg):
        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)

        if lhs.isSym or rhs.isSym:
            self.result = lhs.URem(rhs)
        else:
            result = lhs % rhs
            self.result = result.twoComplement(lhsSize)

        self.lastSize = lhsSize
        return True

    def trunc_divmod(self, a, b):
        ''' Auxiliary function for C-like remainder 
			https://stackoverflow.com/questions/34291760/how-to-easily-implement-c-like-modulo-remainder-operation-in-python-2-7
		'''
        return abs(a) % abs(b) * (1, -1)[a < 0]

    def enter_SMOD(self, arg):

        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)
        rhsSize = self.lastSize

        if not lhs.isSym:
            if bitIsSet(lhs.val, lhsSize -
                        1):  #If 32th bit is set <=> number is negative
                lhs = -lhs
                lhs = lhs.twoComplement(lhsSize)
                lhs = -lhs  #Get real value from two complement negative

        if not rhs.isSym:
            if bitIsSet(rhs.val, rhsSize -
                        1):  #If 32th bit is set <=> number is negative
                rhs = -rhs
                rhs = rhs.twoComplement(rhsSize)
                rhs = -rhs  #Get real value from two complement negative

        if not lhs.isSym and not rhs.isSym:
            result = ADT(self.trunc_divmod(lhs.val, rhs.val))
        else:
            result = lhs % rhs  #% operator in z3 is signed modulus already

        self.result = result.twoComplement(lhsSize)
        self.lastSize = lhsSize
        return True

    def enter_LSHIFT(self, arg):
        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)

        result = lhs << rhs
        self.result = result.twoComplement(lhsSize)
        self.lastSize = lhsSize
        return True

    def enter_RSHIFT(self, arg):
        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize  #Second argument might be a 2-bit number for all we know :)
        rhs = self.computeExp(arg.rhs)

        result = lhs >> rhs
        self.result = result.twoComplement(lhsSize)
        self.lastSize = lhsSize
        return True

    def enter_ARSHIFT(self, arg):

        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)

        if lhs.isSym or rhs.isSym:
            self.result = lhs.LShR(rhs)
        else:
            self.result = lhs.copy()
            for i in range(rhs.val):
                self.result = (self.result >> ADT(1))
                if bitIsSet(lhs.val, lhsSize - 1):
                    self.result = ADT(pow(2, lhsSize - 1)) + self.result
            self.result = self.result.twoComplement(lhsSize)

        self.lastSize = lhsSize
        return True

    def enter_AND(self, arg):

        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)
        result = lhs & rhs
        self.result = result.twoComplement(self.lastSize)
        return True

    def enter_OR(self, arg):

        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)
        result = lhs | rhs
        self.result = result.twoComplement(self.lastSize)
        return True

    def enter_XOR(self, arg):

        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)
        result = lhs ^ rhs
        self.result = result.twoComplement(self.lastSize)
        return True

    def enter_EQ(self, arg):

        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)
        if lhs.isSym or rhs.isSym:
            self.result = ADT(
                If(lhs.val == rhs.val, BitVecVal(1, 1), BitVecVal(0, 1)))
        else:
            self.result = ADT(lhs.val == rhs.val)

        copyInformation(lhs, self.result)
        copyInformation(rhs, self.result)

        return True

    def enter_NEQ(self, arg):

        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)

        if lhs.isSym or rhs.isSym:
            self.result = ADT(
                If(lhs.val != rhs.val, BitVecVal(1, 1), BitVecVal(0, 1)))
        else:
            self.result = ADT(lhs.val != rhs.val)

        copyInformation(lhs, self.result)
        copyInformation(rhs, self.result)

        return True

    def enter_LT(self, arg):

        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)

        if lhs.isSym or rhs.isSym:
            self.result = ADT(
                If(ULT(lhs.val, rhs.val), BitVecVal(1, 1), BitVecVal(0, 1)))
        else:
            self.result = ADT(lhs.val < rhs.val)

        copyInformation(lhs, self.result)
        copyInformation(rhs, self.result)

        return True

    def enter_LE(self, arg):

        lhs = self.computeExp(arg.lhs)
        rhs = self.computeExp(arg.rhs)

        if lhs.isSym or rhs.isSym:
            self.result = ADT(
                If(ULE(lhs.val, rhs.val), BitVecVal(1, 1), BitVecVal(0, 1)))
        else:
            self.result = ADT(lhs.val <= rhs.val)

        copyInformation(lhs, self.result)
        copyInformation(rhs, self.result)

        return True

    def enter_SLT(self, arg):

        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)
        rhsSize = self.lastSize

        if not lhs.isSym:
            if bitIsSet(lhs.val, lhsSize -
                        1):  #If 32th bit is set <=> number is negative
                lhs = -lhs
                lhs = lhs.twoComplement(lhsSize)
                lhs = -lhs  #Get real value from two complement negative

        if not rhs.isSym:
            if bitIsSet(rhs.val, rhsSize -
                        1):  #If 32th bit is set <=> number is negative
                rhs = -rhs
                rhs = rhs.twoComplement(rhsSize)
                rhs = -rhs  #Get real value from two complement negative

        if lhs.isSym or rhs.isSym:
            self.result = ADT(
                If(lhs.val < rhs.val, BitVecVal(1, 1), BitVecVal(0, 1)))
        else:
            self.result = ADT(lhs.val < rhs.val)

        copyInformation(lhs, self.result)
        copyInformation(rhs, self.result)

        return True

    def enter_SLE(self, arg):

        lhs = self.computeExp(arg.lhs)
        lhsSize = self.lastSize
        rhs = self.computeExp(arg.rhs)
        rhsSize = self.lastSize

        if not lhs.isSym:
            if bitIsSet(lhs.val, lhsSize -
                        1):  #If 32th bit is set <=> number is negative
                lhs = -lhs
                lhs = lhs.twoComplement(lhsSize)
                lhs = -lhs  #Get real value from two complement negative

        if not rhs.isSym:
            if bitIsSet(rhs.val, rhsSize -
                        1):  #If 32th bit is set <=> number is negative
                rhs = -rhs
                rhs = rhs.twoComplement(rhsSize)
                rhs = -rhs  #Get real value from two complement negative

        if lhs.isSym or rhs.isSym:
            self.result = ADT(
                If(lhs.val <= rhs.val, BitVecVal(1, 1), BitVecVal(0, 1)))
        else:
            self.result = ADT(lhs.val <= rhs.val)

        copyInformation(lhs, self.result)
        copyInformation(rhs, self.result)

        return True

    #Unary operations
    def enter_NEG(self, arg):  #2-s complement
        val = self.computeExp(arg.arg)
        result = -val
        self.result = result.twoComplement(self.lastSize)
        return True

    def enter_NOT(self, arg):  #1-s complement
        val = self.computeExp(arg.arg)
        result = ~val
        self.result = result.twoComplement(self.lastSize)
        return True

    def enter_UNSIGNED(self, arg):
        afterSize = arg.size
        val = self.computeExp(arg.expr)
        beforeSize = self.lastSize

        if val.isSym:
            self.result = val.ZeroExt(afterSize - beforeSize)
        else:
            #Extending with zeroes is the same as doing nothing, with python integers...
            self.result = val

        self.lastSize = afterSize
        return True

    def enter_SIGNED(self, arg):
        afterSize = arg.size
        val = self.computeExp(arg.expr)
        beforeSize = self.lastSize

        if val.isSym:
            self.result = val.SignExt(afterSize - beforeSize)
        else:
            val2 = bin(val.val)[2:].zfill(beforeSize)
            if val2[0] == '1':  #If MSB is 1, extend with 1's
                extend = '1' * (afterSize - beforeSize
                                )  #How many bits to extend
            else:
                extend = '0' * (afterSize - beforeSize)

            result = int(extend + val2, 2)
            self.result = ADT(twoComplement(result, afterSize))
            copyInformation(val, self.result)

        self.lastSize = afterSize
        return True

    def enter_HIGH(self, arg):
        val = self.computeExp(arg.expr)
        size = self.lastSize

        if val.isSym:
            self.result = val.Extract(size - 1, size - arg.size)
        else:
            bits = '1' * arg.size
            bits = bits + '0' * (size - arg.size)
            mask = int(bits, 2)
            self.result = ADT(
                twoComplement((val.val & mask) >> (size - arg.size), arg.size))
            copyInformation(val, self.result)

        self.lastSize = arg.size
        return True

    def enter_LOW(self, arg):
        val = self.computeExp(arg.expr)

        if val.isSym:
            self.result = val.Extract(arg.size - 1, 0)
        else:
            bits = '1' * arg.size
            self.result = ADT(twoComplement(val.val & int(bits, 2), arg.size))

        copyInformation(val, self.result)
        self.lastSize = arg.size
        return True

    def enter_Let(self, arg):
        #Let this variable
        var = arg.var.name

        #Have this value
        val = self.computeExp(arg.value)
        sz = self.lastSize
        oldVal = self.mem.load(var, size=sz, noneIsFine=True)
        self.mem.store(var, val, size=sz)

        #In this expression
        res = self.computeExp(arg.expr)

        #And not in the other expressions of course :D
        if oldVal is None:
            self.mem.delete(var)
        else:
            self.mem.store(var, oldVal, size=sz)

        self.result = res
        return True

    def enter_Unknown(self, arg):
        self.result = ADT(0x0)  #UNKNOWN IS 0x0, everyone knows that
        return True

    #These just never appeared... maybe BAP IL doesnt use them
    def TODO(self, msg, arg):
        print('TODO: {}'.format(msg))
        print(arg)
        print(dir(arg))
        terminate()

    def enter_In(self, arg):
        self.TODO('In', arg)

    def enter_Out(self, arg):
        self.TODO('Out', arg)

    def enter_Both(self, arg):
        self.TODO('Both', arg)

    def enter_While(self, arg):
        ''' FIXME: Account for symbolic condition. Probably should modify "code" 
			and unroll one iteration of the loop each time we execute it '''
        while self.computeExp(arg.cond).val:
            for statement in arg.stmts:
                self.run(statement)
        return True

    def enter_Ite(self, arg):
        cond = self.computeExp(arg.cond)
        assert cond.val == 1 or cond.val == 0 or cond.isSym

        if cond.val == 1:
            self.result = self.computeExp(arg.true)
        elif cond.val == 0:
            self.result = self.computeExp(arg.false)
        else:
            canBeTrue = self.mem.isItPossible(cond.val == True)
            canBeFalse = self.mem.isItPossible(cond.val == False)

            assert canBeTrue or canBeFalse  #I mean, it has to be one of them...

            if canBeTrue and canBeFalse:
                name = 'ite_{}'.format(self.mem.genSymName(
                ))  #Generate unique name for symbolic var

                val1 = self.computeExp(arg.true)
                val2 = self.computeExp(arg.false)
                var = BitVec(name, self.lastSize)

                self.mem.addRestr(
                    Or(And(cond.val == True, var == val1.val),
                       And(cond == False, var == val2.val)))
                self.result = ADT(var)
            elif canBeTrue:  #If condition can only be true
                self.mem.addRestr(cond.val == True)
                self.result = self.computeExp(arg.true)
            elif canBeFalse:  #If condition can only be false
                self.mem.addRestr(
                    cond.val == False)  #Add restriction to solver
                self.result = self.computeExp(arg.false)

        return True

    def enter_Extract(self, arg):
        hb = arg.high_bit
        lb = arg.low_bit

        val = self.computeExp(arg.expr)
        size = self.lastSize

        #https://github.com/BinaryAnalysisPlatform/bap/blob/master/lib/bap/bap.mli#L2299
        if hb > size - 1:
            hb = size - 1
        if lb < 0:
            lb = 0

        if val.isSym:
            self.result = val.Extract(hb, lb)
        else:
            val2 = bin(val.val)[2:].zfill(size)
            val2 = val2[::
                        -1]  #Invert bits so its easier to return result (hb - lb converts to lb - hb)

            result = val2[lb:hb + 1]  #Inclusive the last
            result = result[::-1]  #Invert again
            self.result = ADT(twoComplement(int(result, 2), hb - lb + 1))

        copyInformation(val, self.result)
        self.lastSize = hb - lb + 1  #size of result is how many bits we've taken from expression value
        return True

    def enter_Concat(self, arg):
        lhs = self.computeExp(arg.lhs)
        sizeLhs = self.lastSize
        rhs = self.computeExp(arg.rhs)
        sizeRhs = self.lastSize

        if lhs.isSym or rhs.isSym:
            if not lhs.isSym:
                lhs.val = BitVecVal(lhs.val, sizeLhs)
            if not rhs.isSym:
                rhs.val = BitVecVal(rhs.val, sizeRhs)
            self.result = lhs.Concat(rhs)
        else:
            rhs2 = bin(rhs.val)[2:].zfill(sizeRhs)
            lhs2 = bin(lhs.val)[2:].zfill(sizeLhs)
            self.result = ADT(
                int(lhs2 + rhs2,
                    2))  #Join them together and take the integer value
            copyInformation(lhs, self.result)
            copyInformation(rhs, self.result)

        self.lastSize = sizeLhs + sizeRhs
        return True