By Luigi Fragale
Garmin smartwatches have quietly evolved into powerful embedded platforms. Beneath the fitness metrics, navigation features, and custom watch faces lie a proprietary Garmin Virtual Machine which executes third-party applications compiled from Garmin’s Monkey C language. These applications are normally distributed through the Connect IQ Store where .prg binaries are installed directly on the device.
For reverse engineers, those .prg files present several challenges, such as lack of documented format, custom virtual machine, and no native support in mainstream reverse-engineering tools.
In the previous Anvil research project, our Director of Research, Tao Sauvage, identified several vulnerabilities while going through Garmin VM opcodes and internal routines. His research allowed insights into the Garmin VM internal details, opening rooms for further studies.
During a Hammercon Capture The Flag event, a reverse engineering challenge involving a Garmin watch application (PRG) served as the spark that initiated the development of a new tool.
We are introducing a Ghidra processor definition and loader for Garmin watch applications, designed to analyze Garmin PRG binaries inside Ghidra with structured headers, disassembly, decompilation, and meaningful symbols. Check it out!
Put the GhidraGarminApp to Work in the 2025 HammerCon CTF
At Anvil, we like to turn one-off challenges into reusable tooling. To make the above tool release more hands-on, we’re also publishing the original 2025 HammerCon CTF challenge so you can take the GhidraGarminApp for a spin right away.
👉 Download the original 2025 HammerCon Garmin CTF file here: Garmax.zip
Think you’ve found the flag? Send it to ctf@anvilsecure.com and tell us how you got there 😊
Garmin Connect IQ Applications: What Are We Analyzing?
Garmin’s Connect IQ platform allows developers to create applications that run directly on wearable devices and other Garmin hardware. These applications fall into several categories:
- Watch Faces - custom home screens
- Data Fields - additional metrics during activities
- Widgets - glanceable information views
- Watch Apps - full standalone applications
- Device Apps - applications for Edge, Marine, and other devices
All of these are written in Monkey C, compiled using the Connect IQ SDK, and distributed to devices as .prg binaries.
Currently, the Ghidra extension supports only Garmin Watch Applications; other types were not fully tested.
State of Art
In his previous research, Tao Sauvage released a Kaitai structure file allowing parsing and understanding of Garmin PRG binary.
Kaitai Struct is an excellent tool for describing and parsing binary formats, and it does an amazing job understanding the high-level layout of Garmin PRG files. However, format parsing alone does not translate into a usable reverse-engineering workflow.
It lacks reference, context, functions, renaming and annotations, and makes reverse engineering tedious and time-consuming.
This is where Ghidra fundamentally changes the equation. By defining a processor, instruction semantics, and a format-aware loader, Ghidra turns static layout knowledge into executable understanding by outlining:
- Instruction decoding and disassembly
- Control-flow and cross-reference generation
- Decompilation into higher-level logic
- Data types that are directly referenced by code
- A navigable program graph rather than a parsed file
A Garmin VM Processor Definition for Ghidra
To make Ghidra understand Garmin watch applications, this project introduces a new processor definition representing the Garmin virtual machine used by PRG binaries.
Ghidra allows the creation of new processor using the SLEIGH specification language. This makes it possible to describe, instruction encodings, operand formats, registers, calling conventions, memory alignment, and instruction semantics useful during de-compilation.
This processor definition allows Ghidra to correctly disassemble Garmin bytecode, associate opcodes with meaningful operations, and enable decompilation using the SLEIGH-defined semantics. While all opcodes are handled, not all of them are 100% semantically correct in SLEIGH language. However, a decent level of semantics exist to allow real decompilation, even if the output is sometimes imperfect.
<?xml version="1.0" encoding="UTF-8"?>
<!-- See Relax specification: Ghidra/Framework/SoftwareModeling/data/languages/language_definitions.rxg -->
<language_definitions>
<!-- Uncomment the following to make the language available in Ghidra -->
<language processor="skel"
endian="big"
size="32"
variant="default"
version="1.0"
slafile="garminvm.sla"
processorspec="garminvm.pspec"
id="GarminVM:BE:32:default">
<description>Garming Virtual Machine</description>
<compiler name="default" spec="garminvm.cspec" id="default"/>
</language>
</language_definitions>
The SLEIGH definition can be found in the SLASPEC folder
Beyond a Processor: A Custom PRG Loader
A processor alone is not sufficient. PRG binaries have headers, object definitions, fields, and metadata that must be parsed and applied during import to have a good understanding of the binary.
The custom loader was designed and built based on the Kaitai structure and adds the following capabilities:
- Recognizing Garmin
.prgfiles during import - Creating appropriate memory blocks
- Setting the correct image base and entry point
- Parsing known header structures
- Registering data types inside Ghidra’s Data Type Manager
- Labeling known offsets and functions when possible
- Identifying strings and create reference to them
- Attempting to resolve relative offset and symbol values pointers
What You See After Loading a PRG
Once a PRG file is imported, if the file is a valid PRG file, then Ghidra will identify it and load it accordingly:


Well-known functions are already re-named accordingly and presented to the user, as well as string pointers and symbols.

Structured Program Layout
Memory is divided into several regions, data section, code section, symbols, sdk.data, sdk.code and sdk.native.

Object and Class Definitions
PRG binaries contain embedded module definitions. These are extracted and represented as structures inside Ghidra, allowing analysts to explore application logic at a higher level. While symbol value references are not yet fully resolved within the code section, the presence of these definitions improves readability and make browsing through the code much easier. An example is provided below:

Opcode-Level Disassembly and Decompilation
All known opcodes have a SLEIGH definition, enabling Ghidra’s decompiler. Some instructions still lack full semantic detail, so decompiled output may not always be perfect. As shown below, some opcodes do not have a semantic representation yet but they were left as pcode within the decompiler. This is still a work in progress.

Header Interpretation
The PRG header is parsed into multiple structures, primarily ClassDefinition and FieldDefinition. Not all fields are currently highlighted, but the groundwork is in place. While you may not yet see in Ghidra, fields such as symbol_value, sectionLocation or valueType, the information is in there, but just not highlighted as in the Kaitai structure (it will be in the future releases).


Current Limitations and Next Steps
- Highlight more structure fields for better readability
- Mapping symbol values to module functions during operations such as (. GETLOCALV)
- Version-specific handling of PRG binaries
- Improved opcode semantics for better decompilation
- Testing loader against other Garmin applications
Closing Thoughts
Modern wearable devices are no longer simple accessories, they are network-connected computing platforms that process sensitive personal data and execute third-party code. As these systems grow in complexity, understanding how they work at a low level becomes very important.
By bringing native support for Garmin watch applications into Ghidra, this project aims to lower the barrier to meaningful analysis and encourage responsible security research. Providing researchers with better tools leads to better understanding, better disclosures, and ultimately more secure systems.
If you’ve ever wanted to see what really runs on your watch, this is where that journey starts.
References
About the Author
Luigi Fragale is a Senior Security Engineer at Anvil Secure with a strong passion for IoT, reverse engineering, and offensive security research. Throughout his career, he has applied his expertise across various sectors, ranging from the financial industry to Operational Technology (OT).
Always eager to learn new things, Luigi achieved multiple certifications (OSCP, OSEP, OSED, OSWE, OSCE3). When he’s not exploring fault injection techniques or tackling CTF challenges, he enjoys brewing craft beer, playing basketball, and windsurfing.
