You know how when you’re working on a project, other side quests pop up left and right? You can choose to handle them briefly and summarily, or you can dive into them as projects in their own right. Well, Uri Shaked is the author of Wokwi, an online Arduino simulator that allows you to test our your code on emulated hardware. (It’s very, very cool.) Back in the day, Arduino meant AVR, and he put in some awesome effort on reverse engineering that chip in order to emulate it successfully. But then “Arduino” means so much more than just AVR these days, so Uri had to tackle the STM32 ARM chips and even the recent RP2040.
Arduino runs on the ESP32, too, so Uri put on his reverse engineering hat (literally) and took aim at that chip as well. But the ESP32 is a ton more complicated than any of these other microcontrollers, being based not only on the slightly niche Xtensa chip, but also having onboard WiFi and its associated binary firmware. Reverse engineering the ESP32’s WiFi is the side-quest that Uri embarks on, totally crushes, and documents for us in this standout Remoticon 2021 talk.
Peeking and Poking
The ESP32 treats the WiFi as a memory-mapped peripheral, like you’re probably used to on microcontrollers. For GPIO pins, for instance, memory mapping means that you can write a 1 or 0 into a particular bit of memory, and it will turn an external LED on or off. Read from that memory location, and you can tell if someone is pushing a button. For WiFi, it’s basically the same thing, only it’s mostly completely undocumented where the memory addresses are and what they’re for. Uri’s approach uses a debugger to the JTAG on the physical hardware, a Ghidra plugin to help him work on the binaries, and his own ESP32 simulator to ferret all of this out.
First off, he flashed one of the simple ESP-IDF WiFi “hello world” programs into his simulator, turned logging verbosity up to eleven, and ran it until it crashed. Which it did quickly, because his simulator didn’t have any of the WiFi hardware emulated yet. With GDB, the debugger, he could figure out which function in particular crashed. Then he took that function apart.
Straight off the bat, he got lucky. A function, helpfully called
hal_mac_deinit() didn’t seem to do much except write particular values to a fixed memory address, and wait for a particular response. He then programmed his simulator to give that response, which made the program crash a little bit further downstream. Success! What does the memory address in question map to? The datasheet says “Reserved” but it didn’t take too large a leap of faith to assume that it’s some kind of WiFi control register.
The rest of the talk has Uri explaining this repeated ping-ponging between a crashed program on his simulator, using Ghidra and GDB to figure out what the crashed code does, and then to integrating the desired behavior into his simulator until that bit of code worked. What’s truly amazing is that this ends up with a simulation of how the ESP32’s WiFi works on the inside that’s so good that he can run Python MQTT libraries on the simulated device, and it works exactly as if it were running on the native hardware. Amazing!
This is a great talk, providing a high-level overview of reverse engineering using emulation as a key tool. It’s a great technique, and we’re stoked to have been able to look over Uri’s metaphorical shoulders. Check it out!