Reverse Engineering MicroPython Frozen Modules
This talk demonstrates techniques for reverse engineering MicroPython frozen modules, which are pre-compiled bytecode modules embedded directly into firmware. The speaker explains how to extract, reconstruct, and disassemble these modules from firmware images, even when symbols are stripped. The presentation provides a practical methodology for analyzing embedded systems that utilize MicroPython for custom logic or security-sensitive operations. The speaker also discusses the limitations of using frozen modules as a security mechanism for obfuscation.
Why Your Firmware "Frozen Modules" Are Not A Security Feature
TLDR: Developers often use MicroPython frozen modules to bake code directly into firmware, mistakenly believing this provides a layer of security through obfuscation. This research demonstrates that these modules are easily extracted, reconstructed, and disassembled using standard tools like picotool and mpy-tool. If you are relying on frozen modules to hide secrets or proprietary logic, you are effectively leaving your credentials in plain sight for anyone with physical access to the device.
Embedded security often falls into the trap of assuming that if code isn't sitting in a standard file system, it’s effectively hidden. MicroPython’s "frozen modules" feature is a prime example of this misconception. By compiling Python scripts into bytecode and linking them directly into the firmware binary at build time, developers gain performance and memory efficiency. However, many treat this as a way to "hide" sensitive logic or hardcoded credentials from prying eyes.
During a recent deep dive into firmware analysis, it became clear that this is not a security boundary. If you can dump the flash, you can reconstruct the source. For anyone performing hardware penetration testing or analyzing IoT devices, this is a critical path to finding hardcoded API keys, backdoors, or proprietary algorithms that developers assumed were safe.
The Mechanics of Extraction
When you encounter a device running MicroPython, your first step is obtaining the firmware image. On a platform like the Raspberry Pi Pico, this is trivial if the debug interface isn't locked down. Using picotool, you can pull the entire flash memory. Once you have that binary, the "frozen" nature of the modules doesn't stop you; it just changes the tools you need.
The mpy-tool is the Swiss Army knife for this work. It handles the heavy lifting of parsing the MicroPython bytecode format. The challenge is that these modules aren't stored as contiguous, labeled files. Instead, they are scattered throughout the binary as a series of C structures. You have to locate the mp_frozen_names and mp_frozen_content structures within the binary.
If you have access to a debug build or can find symbols, this is straightforward. In a stripped production binary, you have to hunt for the data structures manually. I typically load the binary into Ghidra at the base address 0x10000000 and look for references to known strings or standard library function calls. Once you locate the mp_find_frozen_module function, you can trace the references back to the content structures.
Reconstructing the Bytecode
Once you have the raw data, you need to turn it back into something you can analyze. The MicroPython bytecode format is not identical to standard CPython. It is a stack-based language, and the opcodes are specific to the MicroPython virtual machine.
The header of an .mpy file is simple:
4D 06 00 1F
0x4Dis the magic byte 'M'.0x06indicates the major version.0x00signifies non-native bytecode.0x1Fdefines the number of bits in a small int.
The real complexity lies in the vuint (variably encoded unsigned integer) format used throughout the bytecode. It uses 7 bits per byte, with the 8th bit acting as a continuation flag. If you try to parse this manually without understanding the vuint encoding, you will quickly lose your place.
When you successfully reconstruct the .mpy file, you can use the -d flag in mpy-tool to disassemble it. This gives you a clear view of the logic, including constant strings and function calls. If the code is doing something interesting—like interacting with hardware pins or communicating with a cloud service—you will see the exact opcodes for those operations.
Real-World Impact
For a pentester, this is a goldmine. I have seen developers store AWS credentials, hardcoded Wi-Fi passwords, and even proprietary encryption keys inside these modules. They assume that because the code isn't a .py file on a FAT filesystem, it’s safe.
If you are auditing a device, don't stop at the filesystem. If you see a main.py that imports a module you can't find, that module is almost certainly a frozen one. Extract the firmware, find the mp_frozen_content structures, and rebuild the .mpy files. You will often find that the "hidden" logic is just as readable as the original Python, provided you have the right disassembler.
Defensive Reality
There is no way to make this truly secure if the attacker has physical access to the device. If you are using frozen modules, you are doing it for performance, not security. If you have secrets that must remain hidden, you need to move them out of the firmware entirely. Use a secure element, a TPM, or a hardware-backed keystore to handle sensitive operations.
If you are a developer, stop treating your firmware as a black box. Assume that any code you ship on a device will eventually be read, disassembled, and analyzed. If you can't afford for your logic to be public, don't put it on the device in the first place. For those of us on the offensive side, keep digging into these structures; the developers are still making it far too easy for us to find what they thought was hidden.
Vulnerability Classes
Target Technologies
Attack Techniques
Up Next From This Conference

Breaking Secure Web Gateways for Fun and Profit

Listen to the Whispers: Web Timing Attacks That Actually Work

Abusing Windows Hello Without a Severed Hand
Similar Talks

Hacking Apple's USB-C Port Controller

Unmasking the Snitch Puck: The Creepy IoT Surveillance Tech in the School Bathroom

