Ethernaut Lvl 19 MagicNumber Walkthrough: How to deploy contracts using raw assembly opcodes

This is a in-depth series around Zeppelin team’s smart contract security puzzles. We learn key Solidity concepts to solve the puzzles 100% on your own.

Nicole Zhu
Sep 10, 2018 · 5 min read

This level requires some assembly programming to deploy a tiny contract to the EVM.

Let’s break this down :)

What happens during contract creation

Recall that during contract initialization, the following happens:

1. First, a user or contract sends a transaction to the Ethereum network. This transaction contains data, but no recipient address. This format indicates to the EVM that is a contract creation, not a regular send/call transaction.

2. Second, the EVM compiles the contract code in Solidity (a high level, human readable language) into bytecode (a low level, machine readable language). This bytecode directly translates into opcodes, which are executed in a single call stack.

Important to note: contract creation bytecode contains both 1)initialization code and 2) the contract’s actual runtime code, concatenated in sequential order.

3. During contract creation, the EVM only executes the initialization code until it reaches the first STOP or RETURN instruction in the stack. During this stage, the contract’s constructor() function is run, and the contract has an address.

3.1. After this initialization code is run, only the runtime code remains on the stack. These opcodes are then copied into memory and returned to the EVM.

5. Finally, the EVM stores this returned, surplus code in the state storage, in association with the new contract address. This is the runtime code that will be executed by the stack in all future calls to the new contract.

To solve this level, you need 2 sets of opcodes:

  • Initialization opcodes: to be run immediately by the EVM to create your contract and store your future runtime opcodes, and
  • Runtime opcodes: to contain the actual execution logic you want. This is the main part of your code that should return 0x 0x42 and be under 10 opcodes.

At this point, to independently solve this level, you can read in depth about opcodes and smart contract deconstruction (from the author of this Ethernaut level).

For a bit more guidance, let’s press on…

Detailed Walkthrough

0. Power up truffle console with Ropsten (or your preferred setup) to be able to directly deploy bytecode to the EVM. And open up this bytecode <> opcode conversion chart for easy reference.

Runtime Opcodes — Part 1

First, let’s figure out the runtime code logic. The level constrains you to only 10 opcodes. Luckily, it doesn’t take more than that to return a simple 0x42.

Returning values is handled by the RETURN opcode, which takes in two arguments:

  • p: the position where your value is stored in memory, i.e. 0x0, 0x40, 0x50 (see figure). Let’s arbitrarily pick the 0x80 slot.
  • s: the size of your stored data. Recall your value is 32 bytes long (or 0x20 in hex).

Recall that Ethereum memory looks like this, with 0x0, 0x10, 0x20… as the official position references:

Every Ethereum transaction has 2²⁵⁶ bytes of (temporary) memory space to work with

But… this means before you can return a value, first you have to store it in memory.

  1. First, store your 0x42 value in memory with mstore(p, v), where p is position and v is the value in hexadecimal:

2. Then, you can return this the 0x42 value:

This resulting opcode sequence should be 604260805260206080f3. Your runtime opcode is exactly 10 opcodes and 10 bytes long.

Initialization Opcodes — Part 2

Now let’s create the contract initialization opcodes. These opcodes need to replicate your runtime opcodes to memory, before returning them to the EVM. Recall that the EVM will then automatically save the runtime sequence 604260805260206080f3 to the blockchain — you won’t have to handle this last part.

Copying code from one place to another is handled by the opcode codecopy, which takes in 3 arguments:

  • t: the destination position of the code, in memory. Let’s arbitrarily save the code to the 0x00 position.
  • f: the current position of the runtime opcodes, in reference to the entire bytecode. Remember that f starts after initialization opcodes end. What a chicken and egg problem! This value is currently unknown to you.
  • s: size of the code, in bytes. Recall that 604260805260206080f3 is 10 bytes long (or 0x0a in hex).

3. First copy your runtime opcodes into memory. Add a placeholder for f, as it is currently unknown:

4. Then, return your in-memory runtime opcodes to the EVM:

5. Notice that in total, your initialization opcodes take up 12 bytes, or 0x0c spaces. This means your runtime opcodes will start at index 0x0c, where f is now known to be 0x0c:

6. The final sequence is thus:

Where the first 12 bytes are initialization opcodes and the subsequent 10 bytes are your runtime opcodes.

7. In Truffle console, create your contract with the following commands:

8. Look up the newly created contract address from the returned transaction hash. You can do this via Etherscan or via getTransactionReceipt(hash).

9. In the Ethernaut web console, simply input the following to pass the level:

To learn more Solidity

Check out Solidity Koans to learn more Solidity through test driven development. The plan is to open-source this soon, so all user feedback are welcome!

Recommended Readings

  • For all previous levels, start here.
  • To dive deeper into the wonderful world of Solidity assembly, I recommend the following articles:

Get Best Software Deals Directly In Your Inbox

Coinmonks

Coinmonks is a non-profit Crypto educational publication.

Sign up for Coinmonks

By Coinmonks

A newsletter that brings you week's best crypto and blockchain stories and trending news directly in your inbox, by CoinCodeCap.com Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Coinmonks

Coinmonks is a non-profit Crypto educational publication. Follow us on Twitter @coinmonks Our other project — https://coincodecap.com

Nicole Zhu

Written by

Engineer @Google Cloud. I tweet @nczhu

Coinmonks

Coinmonks is a non-profit Crypto educational publication. Follow us on Twitter @coinmonks Our other project — https://coincodecap.com

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store