Exemple #1
0
    def test_ADD_1(self):
        instruction = EVMAsm.disassemble_one(b"\x60\x10")
        self.assertEqual(
            EVMAsm.Instruction(0x60, "PUSH", 1, 0, 1, 3,
                               "Place 1 byte item on stack.", 16, 0),
            instruction)

        instruction = EVMAsm.assemble_one("PUSH1 0x10")
        self.assertEqual(
            instruction,
            EVMAsm.Instruction(0x60, "PUSH", 1, 0, 1, 3,
                               "Place 1 byte item on stack.", 16, 0))

        instructions1 = EVMAsm.disassemble_all(b"\x30\x31")
        instructions2 = EVMAsm.assemble_all("ADDRESS\nBALANCE")
        self.assertTrue(
            all(a == b for a, b in zip(instructions1, instructions2)))

        # High level simple assembler/disassembler

        bytecode = EVMAsm.assemble_hex("""PUSH1 0x80
               BLOCKHASH
               MSTORE
               PUSH1 0x2
               PUSH2 0x100
            """)
        self.assertEqual(bytecode, "0x608040526002610100")

        asmcode = EVMAsm.disassemble_hex("0x608040526002610100")
        self.assertEqual(
            asmcode,
            """PUSH1 0x80\nBLOCKHASH\nMSTORE\nPUSH1 0x2\nPUSH2 0x100""")
Exemple #2
0
    def test_ADD_1(self):
        instruction = EVMAsm.disassemble_one(b'\x60\x10')
        self.assertEqual(
            EVMAsm.Instruction(0x60, 'PUSH', 1, 0, 1, 0,
                               'Place 1 byte item on stack.', 16, 0),
            instruction)

        instruction = EVMAsm.assemble_one('PUSH1 0x10')
        EVMAsm.Instruction(0x60, 'PUSH', 1, 0, 1, 0,
                           'Place 1 byte item on stack.', 16, 0)

        instructions1 = EVMAsm.disassemble_all(b'\x30\x31')
        instructions2 = EVMAsm.assemble_all('ADDRESS\nBALANCE')
        self.assertTrue(
            all(a == b for a, b in zip(instructions1, instructions2)))

        # High level simple assembler/disassembler

        bytecode = EVMAsm.assemble_hex("""PUSH1 0x80
               BLOCKHASH
               MSTORE
               PUSH1 0x2
               PUSH2 0x100
            """)
        self.assertEqual(bytecode, '0x608040526002610100')

        asmcode = EVMAsm.disassemble_hex('0x608040526002610100')
        self.assertEqual(
            asmcode,
            '''PUSH1 0x80\nBLOCKHASH\nMSTORE\nPUSH1 0x2\nPUSH2 0x100''')
    def compute_basic_blocks(self):
        '''
            Split instructions into BasicBlock
        Args:
            self: CFG
        Returns:
            None
        '''
        # Do nothing if basic_blocks already exist
        if self._basic_blocks:
            return

        bb = BasicBlock()

        for instruction in disassemble_all(self.bytecode):
            self._instructions[instruction.pc] = instruction

            if instruction.name == 'JUMPDEST':
                # JUMPDEST indicates a new BasicBlock. Set the end pc
                # of the current block, and switch to a new one.
                if bb._instructions:
                    self._basic_blocks[bb.end.pc] = bb

                bb = BasicBlock()

                self._basic_blocks[instruction.pc] = bb

            bb.add_instruction(instruction)

            if bb.start.pc == instruction.pc:
                self._basic_blocks[instruction.pc] = bb

            if bb.end.name in BASIC_BLOCK_END:
                self._basic_blocks[bb.end.pc] = bb
                bb = BasicBlock()
Exemple #4
0
    def disassemble_all(
            bytecode: Iterable,
            pc: int = 0,
            fork=pyevmasm.DEFAULT_FORK) -> Iterable[EVMInstruction]:
        ''' Decode all instructions in bytecode

            :param bytecode: an evm bytecode (binary)
            :param pc: program counter of the first instruction in the bytecode(optional)
            :type bytecode: iterator/sequence/str
            :return: An generator of Instruction objects

            Example use::

                >>> for inst in EVMAsm.decode_all(bytecode):
                ...    print inst

                ...
                PUSH1 0x60
                PUSH1 0x40
                MSTORE
                PUSH1 0x2
                PUSH2 0x108
                PUSH1 0x0
                POP
                SSTORE
                PUSH1 0x40
                MLOAD


        '''
        instructions = pyevmasm.disassemble_all(bytecode, pc, fork)
        return EVMAsm.convert_multiple_instructions_to_evminstructions(
            instructions)
Exemple #5
0
    def __build_source_map(self, bytecode, srcmap):
        # https://solidity.readthedocs.io/en/develop/miscellaneous.html#source-mappings
        new_srcmap = {}
        bytecode = self._without_metadata(bytecode)
        if self.source_code and srcmap:

            asm_offset = 0
            asm_pos = 0
            md = dict(enumerate(srcmap[asm_pos].split(':')))
            byte_offset = int(md.get(0, 0))  # is the byte-offset to the start of the range in the source file
            source_len = int(md.get(1, 0))  # is the length of the source range in bytes
            file_index = int(md.get(2, 0))  # is the source index over sourceList
            jump_type = md.get(3, None)  # this can be either i, o or - signifying whether a jump instruction goes into a function, returns from a function or is a regular jump as part of e.g. a loop

            pos_to_offset = {}
            for i in EVMAsm.disassemble_all(bytecode):
                pos_to_offset[asm_pos] = asm_offset
                asm_pos += 1
                asm_offset += i.size

            for asm_pos, md in enumerate(srcmap):
                if len(md):
                    d = {p: k for p, k in enumerate(md.split(':')) if k}

                    byte_offset = int(d.get(0, byte_offset))
                    source_len = int(d.get(1, source_len))
                    file_index = int(d.get(2, file_index))
                    jump_type = d.get(3, jump_type)

                new_srcmap[pos_to_offset[asm_pos]] = (byte_offset, source_len, file_index, jump_type)

        return new_srcmap
Exemple #6
0
    def _is_revert_bb(self, state, pc):
        world = state.platform

        def read_code(_pc=None):
            while True:
                yield to_constant(world.current_vm.read_code(_pc)[0])
                _pc += 1

        for inst in EVMAsm.disassemble_all(read_code(pc), pc):
            if inst.name == "REVERT":
                return True
            if inst.is_terminator:
                return False
def generate_evm_code(raw_code, storage):
    contracts = {}
    for contract in raw_code:
        contracts[contract] = list(pyevmasm.disassemble_all(
            raw_code[contract]))

    impls = []
    contract_info = []
    for contract in sorted(contracts):
        if contract not in storage:
            storage[contract] = {}
        impls.append(
            generate_contract_code(
                AVMLabel("contract_entry_" + str(contract)),
                contracts[contract],
                contract,
            ))
        contract_info.append({
            "code_point":
            AVMLabel("contract_entry_" + str(contract)),
            "contractID":
            contract,
            "storage":
            storage[contract],
            "code_size":
            len(contracts[contract]) + sum(op.operand_size
                                           for op in contracts[contract]),
            "code_hash":
            int.from_bytes(eth_utils.crypto.keccak(raw_code[contract]),
                           byteorder="big"),
            "code":
            byterange.frombytes(bytes.fromhex(raw_code[contract].hex())),
        })

    contract_info.append({
        "code_point": value.Tuple([]),
        "contractID": 100,
        "storage": {},
        "code_size": 1,
        "code_hash": 1,
        "code": byterange.frombytes(b""),
    })

    def initialization(vm):
        os.initialize(vm, contract_info)
        vm.jump_direct(AVMLabel("run_loop_start"))

    main_code = []
    main_code.append(compile_block(run_loop_start))
    main_code += impls
    return compile_block(initialization), BlockStatement(main_code)
Exemple #8
0
    print("\twrites to stack:", instruction.writes_to_stack)
    print("\treads from stack:", instruction.reads_from_stack)
    print("\twrites to memory:", instruction.writes_to_memory)
    print("\treads from memory:", instruction.reads_from_memory)
    print("\twrites to storage:", instruction.writes_to_storage)
    print("\treads from storage:", instruction.reads_from_storage)
    print("\tis terminator", instruction.is_terminator)


instruction = ea.disassemble_one("\x60\x10")
printi(instruction)

instruction = ea.assemble_one("PUSH1 0x10")
printi(instruction)

for instruction in ea.disassemble_all("\x30\x31"):
    printi(instruction)

for instruction in ea.assemble_all("ADDRESS\nBALANCE"):
    printi(instruction)

# High level simple assembler/disassembler
print(
    ea.assemble_hex("""PUSH1 0x60
                           BLOCKHASH
                           MSTORE
                           PUSH1 0x2
                           PUSH2 0x100
                        """))

print(ea.disassemble_hex("0x606040526002610100"))
Exemple #9
0
    print('\twrites to stack:', instruction.writes_to_stack)
    print('\treads from stack:', instruction.reads_from_stack)
    print('\twrites to memory:', instruction.writes_to_memory)
    print('\treads from memory:', instruction.reads_from_memory)
    print('\twrites to storage:', instruction.writes_to_storage)
    print('\treads from storage:', instruction.reads_from_storage)
    print('\tis terminator', instruction.is_terminator)


instruction = ea.disassemble_one('\x60\x10')
printi(instruction)

instruction = ea.assemble_one('PUSH1 0x10')
printi(instruction)

for instruction in ea.disassemble_all('\x30\x31'):
    printi(instruction)

for instruction in ea.assemble_all('ADDRESS\nBALANCE'):
    printi(instruction)


#High level simple assembler/disassembler
print(ea.assemble_hex(
                        """PUSH1 0x60
                           BLOCKHASH
                           MSTORE
                           PUSH1 0x2
                           PUSH2 0x100
                        """
                     ))
Exemple #10
0
def generate_evm_code(raw_code, storage):
    contracts = {}
    for contract in raw_code:
        contracts[contract] = list(pyevmasm.disassemble_all(
            raw_code[contract]))

    code_tuples_data = {}
    for contract in raw_code:
        code_tuples_data[contract] = byterange.frombytes(
            bytes.fromhex(raw_code[contract].hex()))
    code_tuples_func = make_bst_lookup(code_tuples_data)

    @modifies_stack([value.IntType()], 1)
    def code_tuples(vm):
        code_tuples_func(vm)

    code_hashes_data = {}
    for contract in raw_code:
        code_hashes_data[contract] = int.from_bytes(eth_utils.crypto.keccak(
            raw_code[contract]),
                                                    byteorder="big")
    code_hashes_func = make_bst_lookup(code_hashes_data)

    @modifies_stack([value.IntType()], [value.ValueType()])
    def code_hashes(vm):
        code_hashes_func(vm)

    contract_dispatch = {}
    for contract in contracts:
        contract_dispatch[contract] = AVMLabel("contract_entry_" +
                                               str(contract))
    contract_dispatch_func = make_bst_lookup(contract_dispatch)

    @modifies_stack([value.IntType()], 1)
    def dispatch_contract(vm):
        contract_dispatch_func(vm)

    code_sizes = {}
    for contract in contracts:
        code_sizes[contract] = len(contracts[contract]) + sum(
            op.operand_size for op in contracts[contract])

    # Give the interrupt contract address a nonzero size
    code_sizes[0x01] = 1
    code_size_func = make_bst_lookup(code_sizes)

    @modifies_stack([value.IntType()], 1)
    def code_size(vm):
        code_size_func(vm)

    impls = []
    contract_info = []
    for contract in sorted(contracts):
        if contract not in storage:
            storage[contract] = {}
        impls.append(
            generate_contract_code(
                AVMLabel("contract_entry_" + str(contract)),
                contracts[contract],
                code_tuples_data[contract],
                contract,
                code_size,
                code_tuples,
                code_hashes,
                dispatch_contract,
            ))
        contract_info.append({
            "contractID": contract,
            "storage": storage[contract]
        })

    def initialization(vm):
        os.initialize(vm, contract_info)
        vm.jump_direct(AVMLabel("run_loop_start"))

    def run_loop_start(vm):
        vm.set_label(AVMLabel("run_loop_start"))
        os.get_next_message(vm)
        execution.setup_initial_call(vm, dispatch_contract)
        vm.push(AVMLabel("run_loop_start"))
        vm.jump()

    main_code = []
    main_code.append(compile_block(run_loop_start))
    main_code += impls
    return compile_block(initialization), BlockStatement(main_code)
Exemple #11
0
def printb(bytecode):
    insns = list(
        disassemble_all(binascii.unhexlify(bytecode), fork=DEFAULT_FORK))
    for i in insns:
        print("%08x: %s" % (i.pc, str(i)))