Ghidra and ARM Thumb workflow¶
This walkthrough creates a bounded Ghidra analysis for the extracted main component. It does not turn a raw binary into original source code, and auto-analysis output is not automatically correct.
Install Ghidra safely¶
Use the official NSA Ghidra repository and releases. The official installation notes require a compatible 64-bit JDK, extraction of the release archive, and launching ghidraRun.bat on Windows or ghidraRun on Linux. Read current security advisories before opening untrusted files.
Prepare the input¶
- Extract component 0 with
firmware_pkg.py. - Verify its hash against the extraction report.
- Copy it into a private working directory.
- Record repository commit, package hash, component hash, size, model, and version.
For the documented build, the component size is 3,600,374 bytes and begins with an SFU1 header.
Create a project¶
- Start Ghidra.
- Choose File → New Project.
- Select Non-Shared Project unless you have deliberately configured a secure team server.
- Store the project outside this public Git repository.
- Use a name that contains model and version, not a generic
firmwarename.
Example: M2116W1_1.4.174_main_analysis.
Import as a raw binary¶
- Choose File → Import File.
- Select the extracted component.
- When Ghidra reports raw binary, choose an ARM little-endian language compatible with Thumb analysis.
- Do not guess a compiler specification as a fact; record the selection as an analysis setting.
- Open Options or the memory map and establish the documented image base
0x08000000.
The crucial mapping is:
Do not strip 0x2000 from file offsets when using this mapping.
Treat the SFU1 header as data¶
The first 0x2000 bytes contain the observed SFU1 header, digests, and signature candidate. Mark this region as data rather than disassembling it as Thumb instructions.
Suggested region note:
The payload begins after that header in the documented component, but code and non-code data can still be mixed inside the payload.
Run conservative auto-analysis¶
Enable basic reference, function, and ARM analysis, but expect false positives. Raw firmware lacks standard executable metadata, so Ghidra may:
- create functions in tables;
- miss Thumb entry points;
- apply the wrong function boundary;
- interpret UTF-16 or packed assets as instructions;
- propagate an incorrect type through many callers.
Do not bulk-rename hundreds of functions based on decompiler guesses.
Use the repository locator first¶
Find a UTF-8 string and candidate cross-references:
python tools/thumb_xrefs.py \
../generated/stock-components/component-00-type-00.bin \
--text "listening"
Or disassemble a verified window:
python tools/thumb_xrefs.py \
../generated/stock-components/component-00-type-00.bin \
--disasm-offset 0x130240 \
--bytes 0x100
The script uses Capstone in ARM Thumb little-endian mode. Capstone's official Python tutorial explains architecture/mode selection and why detailed operand information must be enabled explicitly.
Navigate to an offset in Ghidra¶
Convert file offset to runtime address, then use Go To:
At the candidate address:
- inspect bytes and instruction widths;
- verify that branch targets land on plausible boundaries;
- inspect incoming and outgoing references;
- locate prologue and return behavior;
- compare the same region in stock and modified components;
- check whether the decompiler agrees with assembly, not the reverse.
Follow a literal reference¶
Thumb code often loads a nearby literal using a PC-relative ldr. The effective literal address depends on the aligned program counter. The repository script calculates this and limits its search window to the reachable region.
Other addresses may be constructed with movw and movt. A textual search for a four-byte pointer alone will miss those pairs, so thumb_xrefs.py checks both strategies.
Name evidence, not wishes¶
Good labels:
candidate_utf8_to_utf16_wrapper;assistant_text_handler_observed_0813024c;field_2b82_length_inferred.
Weak labels:
send_to_screenwhen only a string reference is known;bluetooth_receivewithout transport evidence;alexa_mainfor a function merely located near one Alexa string.
Add comments containing the evidence source and date.
Verify the native assistant capacity region¶
The documented patch expects this context at file offset 0x130344:
The four bytes at 0x130350 decode as mov.w r2, #300. The guarded patch replaces them with the encoding for mov.w r2, #400; exactly one byte differs because of Thumb immediate encoding.
Before accepting the explanation, verify:
- the preceding call clears 800 bytes at the inline buffer;
- the destination object and field offsets remain consistent;
- the converter reserves a terminator;
- only the intended instruction changes;
- the context matches the documented build exactly.
Export a reviewable finding¶
Include:
## Location
- file offset:
- runtime address:
- component hash:
## Bytes
- context before:
- instruction before:
- instruction after:
## Cross-references
- callers:
- literals/strings:
## Interpretation
- observed:
- inferred:
- alternative explanation:
## Reproduction
- command:
- Ghidra language/base settings:
Do not upload a Ghidra project containing imported proprietary firmware. Share scripts, offsets, screenshots limited to necessary context, and synthetic fixtures.