def test_serialize_basic_types_int8(self): self.assertEqual(ABI.serialize('int8', 0x10), b'\0' * 31 + b'\x10') self.assertEqual(ABI.deserialize('int8', b'\0' * 31 + b'\x10'), 0x10) self.assertEqual(ABI.serialize('int8', -0x10), b'\x00' * 31 + b'\xf0') self.assertEqual(ABI.deserialize('int8', b'\x00' * 31 + b'\xf0'), -0x10)
def test_serialize_basic_types_int(self): self.assertEqual(ABI.serialize('int256', 0x10), '\0' * 31 + '\x10') self.assertEqual(ABI.deserialize('int256', '\0' * 31 + '\x10'), 0x10) self.assertEqual(ABI.serialize('int256', -0x10), '\xff' * 31 + '\xf0') self.assertEqual(ABI.deserialize('int256', '\xff' * 31 + '\xf0'), -0x10)
def test_serialize_basic_types_int16(self): self.assertEqual(ABI.serialize('int16', 0x100), '\0' * 30 + '\x01\x00') self.assertEqual(ABI.deserialize('int16', '\0' * 30 + '\x01\x00'), 0x100) self.assertEqual(ABI.serialize('int16', -0x10), '\x00' * 30 + '\xff\xf0') self.assertEqual(ABI.deserialize('int16', '\x00' * 30 + '\xff\xf0'), -0x10)
def test_valid_uint(self): data = b"\xFF" * 32 parsed = ABI.deserialize('uint', data) self.assertEqual(parsed, 2**256 - 1) for i in range(8, 257, 8): parsed = ABI.deserialize('uint{}'.format(i), data) self.assertEqual(parsed, 2**i - 1)
def test_serialize_basic_types_uint(self): self.assertEqual(ABI.serialize('uint256', 0x10), b'\0' * 31 + b'\x10') self.assertEqual(ABI.deserialize('uint256', b'\0' * 31 + b'\x10'), 0x10) self.assertEqual(ABI.serialize('uint256', -0x10), b'\xff' * 31 + b'\xf0') self.assertEqual(ABI.deserialize('uint256', b'\xff' * 31 + b'\xf0'), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0) self.assertEqual(ABI.deserialize('uint256', b'\xff' * 31 + b'\xf0'), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0) self.assertNotEqual(ABI.deserialize('uint256', b'\xff' * 31 + b'\xf0'), -0x10)
def test_self_make_and_parse_multi_dyn(self): d = ABI.function_call('func(bytes,address[])', b'h' * 50, [1, 1, 2, 2, 3, 3]) funcid, dynargs = ABI.deserialize(type_spec='func(bytes,address[])', data=d) self.assertEqual(funcid, b'\x83}9\xe8') self.assertEqual(dynargs, (b'h' * 50, [1, 1, 2, 2, 3, 3]))
def test_simple_types_ints_symbolic(self): cs = ConstraintSet() x = cs.new_bitvec(256, name="x") y = cs.new_bitvec(256, name="y") # Something is terribly wrong x,y = 10,20 my_ser = ABI.serialize('(uint,uint)', x, y) x_, y_ = ABI.deserialize('(uint,uint)', my_ser) self.assertTrue(solver.must_be_true(cs, x == x_)) self.assertTrue(solver.must_be_true(cs, y == y_))
def test_simple_types0(self): d = [ b'AAAA', # function hash self._pack_int_to_32(32), b'\xff' * 32, ] d = b''.join(d) funcname, dynargs = ABI.deserialize(type_spec='func(uint256,uint256)', data=d) #self.assertEqual(funcname, 'AAAA') self.assertEqual(dynargs, (32, 2**256 - 1 ))
def test_simple_types_ints(self): d = [ b'AAAA', # function hash b'\x7f' + b'\xff' *31, # int256 max b'\x80'.ljust(32, b'\0'), # int256 min ] d = b''.join(d) func_id, dynargs = ABI.deserialize(type_spec='func(int256,int256)', data=d) self.assertEqual(func_id, b"AAAA") self.assertEqual(dynargs, ( 2**255 - 1, -(2**255) ))
def make_transaction_human_readable(conc_tx, mevm, state, stream): metadata = mevm.get_metadata(conc_tx.address) if conc_tx.sort == "CREATE": stream.write("owner: Constructor(") if metadata is not None: conc_args_data = conc_tx.data[len(metadata._init_bytecode):] arguments = ABI.deserialize(metadata.get_constructor_arguments(), conc_args_data) stream.write( ",".join(map(repr, map(state.solve_one, arguments))) ) # is this redundant since arguments are all concrete? stream.write(") with initial balance %s -> %s \n" % (conc_tx.value, conc_tx.result)) if conc_tx.sort == "CALL": if metadata is not None: calldata = conc_tx.data function_id = bytes(calldata[:4]) # hope there is enough data signature = metadata.get_func_signature(function_id) function_name = metadata.get_func_name(function_id) if signature: _, arguments = ABI.deserialize(signature, calldata) else: arguments = (calldata,) return_data = None return_values = None if conc_tx.result == "RETURN": ret_types = metadata.get_func_return_types(function_id) return_data = conc_tx.return_data return_values = ABI.deserialize(ret_types, return_data) # function return stream.write("%s: %s(" % (mevm.account_name(conc_tx.caller), function_name)) stream.write(",".join(map(repr, arguments))) if conc_tx.value != 0: stream.write(") with %d wei -> %s\n" % (conc_tx.value, conc_tx.result)) else: stream.write(") -> %s\n" % (conc_tx.result)) if return_data is not None: if len(return_values) == 1: return_values = return_values[0] stream.write(f"return: {return_values}\n")
def test_simple_types1(self): d = [ b'AAAA', # function hash self._pack_int_to_32(32), b'\xff' * 32, b'\xff'.rjust(32, b'\0'), self._pack_int_to_32(0x424242), ] d = b''.join(d) funcname, dynargs = ABI.deserialize(type_spec='func(uint256,uint256,bool,address)', data=d) #self.assertEqual(funcname, 'AAAA') self.assertEqual(dynargs, (32, 2**256 - 1, 0xff, 0x424242 ))
def test_dyn_bytes(self): d = [ b'AAAA', # function hash self._pack_int_to_32(32), # offset to data start self._pack_int_to_32(30), # data start; # of elements b'Z'*30, b'\x00'*2 ] d = b''.join(d) funcname, dynargs = ABI.deserialize(type_spec='func(bytes)', data=d) self.assertEqual(funcname, b'AAAA') self.assertEqual(dynargs, (b'Z'*30,))
def test_dyn_address(self): d = [ b'AAAA', # function hash self._pack_int_to_32(32), # offset to data start self._pack_int_to_32(2), # data start; # of elements self._pack_int_to_32(42), # element 1 self._pack_int_to_32(43), # element 2 ] d = b''.join(d) func_id, dynargs = ABI.deserialize(type_spec='func(address[])', data=d) self.assertEqual(func_id, b'AAAA') self.assertEqual(dynargs, ([42, 43], ))
def test_function_type(self): # setup ABI for function with one function param spec = 'func(function)' func_id = ABI.function_selector(spec) # build bytes24 data for function value (address+selector) # calls member id lookup on 'Ethereum Foundation Tip Box' (see https://www.ethereum.org/donate) address = ABI._serialize_uint(0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359, 20, padding=0) selector = ABI.function_selector('memberId(address)') function_ref_data = address + selector + b'\0'*8 # build tx call data call_data = func_id + function_ref_data parsed_func_id, args = ABI.deserialize(spec, call_data) self.assertEqual(parsed_func_id, func_id) self.assertEqual(((0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359, selector),), args)
def test_mult_dyn_types(self): d = [ b'AAAA', # function hash self._pack_int_to_32(0x40), # offset to data 1 start self._pack_int_to_32(0x80), # offset to data 2 start self._pack_int_to_32(10), # data 1 size b'helloworld'.ljust(32, b'\x00'), # data 1 self._pack_int_to_32(3), # data 2 size self._pack_int_to_32(3), # data 2 self._pack_int_to_32(4), self._pack_int_to_32(5), ] d = b''.join(d) func_id, dynargs = ABI.deserialize(type_spec='func(bytes,address[])', data=d) self.assertEqual(func_id, b'AAAA') self.assertEqual(dynargs, (b'helloworld', [3, 4, 5]))
def test_function_name_with_signature(self): source_code = ''' contract Test{ function ret(uint) returns(uint){ return 1; } function ret(uint,uint) returns(uint){ return 2; } } ''' user_account = self.mevm.create_account(balance=1000) contract_account = self.mevm.solidity_create_contract(source_code, owner=user_account) contract_account.ret(self.mevm.make_symbolic_value(), self.mevm.make_symbolic_value(), signature='(uint256,uint256)') z = list(self.mevm.all_states)[0].solve_one(self.mevm.transactions()[1].return_data) self.assertEqual(ABI.deserialize('(uint256)', z)[0], 2)
def will_decode_instruction_callback(self, state, pc): TRUE = bytearray((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)) FALSE = bytearray((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) #print pc, state.platform.current_vm.instruction #Once this address is reached the challenge is won if pc == 0x4141414141414141414141414141414141414141: func_id = to_constant(state.platform.current_transaction.data[:4]) if func_id == function_selector("print(string)"): func_name, args = ABI.deserialize("print(string)", state.platform.current_transaction.data) raise Return() elif func_id == function_selector("terminate(string)"): func_name, args = ABI.deserialize("terminate(string)", state.platform.current_transaction.data) self.manticore.shutdown() raise Return(TRUE) elif func_id == function_selector("assume(bool)"): func_name, args = ABI.deserialize("assume(bool)", state.platform.current_transaction.data) state.add(args[0]) raise Return(TRUE) elif func_id == function_selector("is_symbolic(bytes)"): func_name, args = ABI.deserialize("is_symbolic(bytes)", state.platform.current_transaction.data) try: arg = to_constant(args[0]) except: raise Return(TRUE) raise Return(FALSE) elif func_id == function_selector("is_symbolic(uint256)"): func_name, args = ABI.deserialize("is_symbolic(uint256)", state.platform.current_transaction.data) try: arg = to_constant(args[0]) except Exception as e: raise Return(TRUE) raise Return(FALSE) elif func_id == function_selector("shutdown(string)"): func_name, args = ABI.deserialize("shutdown(string)", state.platform.current_transaction.data) print("Shutdown", to_constant(args[0])) self.manticore.shutdown() elif func_id == function_selector("can_be_true(bool)"): func_name, args = ABI.deserialize("can_be_true(bool)", state.platform.current_transaction.data) result = solver.can_be_true(state.constraints, args[0] != 0) if result: raise Return(TRUE) raise Return(FALSE) raise Stop()
def test_selfdestruct_decoupled_account_delete(self): source_code = ''' contract C{ function d( ){ selfdestruct(0); } function g() returns(uint) { return 42 ; } } contract D{ C c; constructor () { c = new C(); } function t () returns(uint){ c.d(); return c.g(); } } ''' user_account = self.mevm.create_account(balance=1000) contract_account = self.mevm.solidity_create_contract( source_code, owner=user_account, contract_name='D', gas=9000000) contract_account.t( gas=9000000 ) #this does not return nothing as it may create several states # nothing reverted and we end up with a single state self.assertEqual(self.mevm.count_states(), 1) # Check that calling t() returned a 42 # That is that calling a selfdestructed contract works as the account # is actually deleted at the end of the human tx self.assertEqual( ABI.deserialize( 'uint', to_constant(self.mevm.world.transactions[-1].return_data)), 42)
def test_empty_types(self): name, args = ABI.deserialize('func()', '\0' * 32) self.assertEqual(name, b'\x00\x00\x00\x00') self.assertEqual(args, tuple())
def test_parse_valid_int2(self): ret = ABI.deserialize("int40", "\x40\x00\x00\x00\x00".rjust(32, '\0')) self.assertEqual(ret, 1 << 38)
def test_parse_valid_int1(self): ret = ABI.deserialize("int", "\x10".ljust(32, '\0')) self.assertEqual(ret, 1 << 252)
def test_parse_valid_int0(self): ret = ABI.deserialize("int8", "\x10" * 32) self.assertEqual(ret, 0x10)
with open('AP2.sol') as f: source_code = f.read() user_account = m.create_account(balance=1000) spender_account = m.make_symbolic_value() m.constrain(spender_account != user_account) contract_account = m.solidity_create_contract(source_code, owner=user_account, balance=0, args=None) #contract_account.balanceOf(spender_account, caller=user_account) contract_account.balanceOf(user_account, caller=user_account) for state in m.ready_states: val = state.platform.transactions[-1].return_data val = ABI.deserialize("uint", val) symbolic_val = m.make_symbolic_value() m.constrain(symbolic_val > val) contract_account.allowance(user_account, spender_account) contract_account.approve(spender_account, symbolic_val, caller=user_account) contract_account.allowance(user_account, spender_account) for state in m.all_states: print("AP2! see {}".format(m.workspace)) m.generate_testcase(state, name="AP2")
def test_parse_invalid_int_too_big(self): with self.assertRaises(EthereumError): ABI.deserialize("int3000", "\xFF") ABI.deserialize("uint3000", "\xFF")
def test_address0(self): data = '{}\x01\x55{}'.format('\0' * 11, '\0' * 19) parsed = ABI.deserialize('address', data) self.assertEqual(parsed, 0x55 << (8 * 19))
m = ManticoreEVM() # initiate the blockchain with open('overflow.sol') as f: source_code = f.read() # Generate the accounts user_account = m.create_account(balance=1000) contract_account = m.solidity_create_contract(source_code, owner=user_account, balance=0) # First add won't overflow uint256 representation value_0 = m.make_symbolic_value() contract_account.add(value_0) # Potential overflow value_1 = m.make_symbolic_value() contract_account.add(value_1) contract_account.sellerBalance() for state in m.running_states: # Check if input0 > sellerBalance # last_return is the data returned last_return = state.platform.transactions[-1].return_data last_return = ABI.deserialize("uint", last_return) state.constrain(Operators.UGT(value_0, last_return)) if state.is_feasible(): print("Overflow found! see {}".format(m.workspace)) m.generate_testcase(state, 'OverflowFound')
# symbolic_data = m.make_symbolic_buffer(320) # m.transaction( # caller=hacker_account, # address=contract_account, # data=symbolic_data, # value=0) # b2fa1c9e = isComplete() m.transaction(caller=hacker_account, address=contract_account, data=bytes.fromhex("b2fa1c9e"), value=0) bug_found = False # Explore all the forks for state in m.running_states: complete = state.platform.transactions[-1].return_data complete = ABI.deserialize("uint256", complete) print(complete) # Set constraint state.constrain(Operators.UGT(complete, 0)) if state.is_feasible(): print("Bug found! see {}".format(m.workspace)) m.generate_testcase(state, 'Bug') bug_found = True if not bug_found: print('No bug were found')
contract_account.transfer(symbolic_to, symbolic_val) contract_account.balances(user_account) # Check of properties ###### bug_found = False # Explore all the forks for state in m.running_states: # state.plateform.transactions returns the list of transactions # state.plateform.transactions[0] is the contract creation # state.plateform.transactions[1] is the first transaction # state.plateform.transactions[-1] is the last transaction balance_before = state.platform.transactions[1].return_data balance_before = ABI.deserialize("uint", balance_before) balance_after = state.platform.transactions[-1].return_data balance_after = ABI.deserialize("uint", balance_after) # Check if it is possible to have balance_after > balance_before state.constrain(Operators.UGT(balance_after, balance_before)) if state.is_feasible(): print("Bug found! see {}".format(m.workspace)) m.generate_testcase(state, 'Bug') bug_found = True if not bug_found: print('No bug were found')
user_account = m.create_account(balance=1000 * ETHER) with open(CONTRACT_PATH) as f: contract = m.solidity_create_contract(f, owner=user_account) ## explore all functions ### symbolic_value = m.make_symbolic_value() symbolic_data = m.make_symbolic_buffer(320) m.transaction(caller=user_account, address=contract.address, data=symbolic_data, value=symbolic_value) bug_found = False # only return "RETURN" states for state in m.ready_states: last_tx = state.platform.transactions[-1] # print(last_tx.result) x = state.platform.transactions[-1].return_data x = ABI.deserialize("uint", x) # Check if x != 123 condition = x != 123 if m.generate_testcase(state, name="BugFound", only_if=condition): print("Bug found! see {}".format(m.workspace)) bug_found = True if not bug_found: print("No bug found")
def test_parse_invalid_int_negative(self): with self.assertRaises(EthereumError): ABI.deserialize("int-8", "\xFF") ABI.deserialize("uint-8", "\xFF")
contract_account = m.solidity_create_contract(source_code, owner=user_account, balance=0) contract_account.balanceOf(to_account, caller=user_account) contract_account.balanceOf(from_account, caller=user_account) contract_account.balanceOf(user_account, caller=user_account) symbolic_val1 = m.make_symbolic_value() #m.constrain(symbolic_val1 > 100) contract_account.transfer(to_account, symbolic_val1, caller=from_account) contract_account.balanceOf(user_account, caller=user_account) contract_account.balanceOf(from_account, caller=user_account) contract_account.balanceOf(to_account, caller=user_account) for state in m.ready_states: #for tx in state.platform.transactions: # print("From address: (0x%x) \n" % (tx.caller)) #print("********\n") balance_before = state.platform.transactions[1].return_data balance_before = ABI.deserialize("uint", balance_before) balance_after = state.platform.transactions[-1].return_data balance_after = ABI.deserialize("uint", balance_after) state.constrain(Operators.ULT(balance_before, balance_after)) if solver.check(state.constraints): print("Found! see {}".format(m.workspace)) m.generate_testcase(state, "Found")
def test_parse_invalid_int_not_pow_of_two(self): with self.assertRaises(EthereumError): ABI.deserialize("int31", "\xFF") ABI.deserialize("uint31", "\xFF")