Debugging EVM bytecode with radare2

EVM debugging alchemy

Let’s continue our journey into the internals of EVM bytecode. In the last post we’ve taken a look at a simple contract and how to reverse engineer it with radare2. Today we will take a look at the EVM ecosystem, how contracts are deployed, how transactions are executed.

A few notes on installing radare2 and its extras

There have been questions in the previous post about installing radare2 properly and its extensions, where the EVM plugins can be found. Well, now you can simply install these extra plugins by running

r2pm install evm

Anything else should be done the way official radare2 documentation describes.

Deploying a simple contract to test VM

Ethereum contracts may run in the different environments: in the mainnet, in testnets like Rinkeby, in private nets or in blockchain emulators like ganache-cli (former TestRPC). We will be using the latter .

Nodes and users of the ethereum blockchain talk to each other via RPC calls, ganache-cli is not an exception. As soon as we start it with -v flag, it creates some test accounts and starts listening on a local port:

Now, navigate your browser to http://remix.ethereum.org (note that http is important, if you connect with https your browser will refuse to load uprotected content from http://localhost) and let’s deploy our test contract from the previous post there. You have to select Run->Web3 Provider to connect to our RPC on http://localhost:8545. Create the contract and call the setA() function with some value. You will be able to see the details of the transaction including its hash in the remix’s console window:

Using radare2 to trace the transaction

Ethereum VM has no way to hook the transaction in the usual way a normal debugger does. What it allows you to do is to request a trace for a transaction that has already happened. The radare2 EVM io plugin uses several RPC methods to download transaction traces, download the code of the contract and such. The complete list of RPC methods one can find is here. Namely, the io plugin uses debug_traceTransaction, eth_getTransactionByHash and eth_getCode.

The syntax of the URL for radare2 to connect to a local node and ask for a transaction trace is as follows: evm://HOST:PORT@TXHASH.

For example, for our transaction we would do the following:

r2 -a evm -D evm "evm://localhost:8545@0x6424891e4810f3df62a67a7b08eb167569cceafd17b80876efba8789f"

Run a simple EVM transaction debugging session in radare2

Medium fails to properly embed asciinema player, so you will have to follow the link to see the example debugging session.

Here we open a transaction and analyse all the code by entering aa. Then, we enter the visual mode by pressing V and switch to the tiled view by pressing !. We close unnecessary tiles and open a custom one by pressing M. We will use this tile for memory, which due to implementation peculiarities of the debugger is mapped at the address 0x10000. Our tile will simply hexdump some bytes at that addr so we tell it to run the command px 512 @ 0x10000. And we single-step through the code by pressing the s key.

Here, you have your simple debugging session for EVM transaction with radare2.

Loading function tables from JSON files

There exist tables of mappings from function hashes to function names. radare2 EVM plugin can read such mappings in JSON format and apply them to your disassembly:

You can load them into the EVM analysis plugin with a!l filename :

You can list all the functions found in the disassembly:

Function names tables happen to be very handy when reversing big contracts, for example take a look at the CFG for a ERC20 token:

You may find the a big JSON signatures mapping file in our repo https://github.com/montekki/r2evm

Setting breakpoints

One might set breakpoints and continue execution, let’s take a look at this example:

Here we again load our transaction, load the signatures table and decide to set a breakpoint to address 0x09 with command db 0x9. As soon as we do it this address becomes marked with a b letter in the disassembly. Now we just have to press dc to continue execution after which the pc register moves to the address of our breakpoint and the execution is paused. This obviously works in all visual modes, for more details please read the official radare2 documentation.

Conclusion

We have developed opensource plugins for radare2 to reverse and debug EVM contracts. So what’s next? There are many ideas for the future development of these tools for example integrating them with tools like mythril or adding support for EVM bytecode to the awesome opensource RetDec decompiler by avast. In any case we will likely see the further development of all kinds of security tools for Ethereum blockchain. Thank you for reading and happy holidays!


Debugging EVM bytecode with radare2 was originally published in ICO Security on Medium, where people are continuing the conversation by highlighting and responding to this story.

*** This is a Security Bloggers Network syndicated blog from ICO Security - Medium authored by Fedor Sakharov. Read the original post at: https://blog.positive.com/debugging-evm-bytecode-with-radare2-9e0e13cbd936?source=rss----820ff037acec---4