Debugging EVM bytecode with radare2
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
The syntax of the URL for
radare2 to connect to a local node and ask for a transaction trace is as follows:
For example, for our transaction we would do the following:
r2 -a evm -D evm "evm://localhost:8545@0x6424891e4810f3df62a67a7b08eb167569cceafd17b80876efba8789f"
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
Here, you have your simple debugging session for EVM transaction with
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
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.
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!