# Firmware Analysis Firmware-specific analysis patterns for embedded system images. Load this when the binary is a firmware image (flat binary, bootloader, RTOS-based), when `binary metadata` reports `format: "RAW"` and the context suggests firmware, or when the user mentions IoT, embedded, bootloader, or memory dump analysis. ## What Makes Firmware Different Firmware images differ from standard executables in key ways: | Characteristic | Standard Executable | Firmware | |---------------|-------------------|----------| | Format | PE, ELF, Mach-O | Often flat binary (RAW) with custom layout | | Load address | OS loader determines | Fixed flash address (e.g., 0x08000000) | | Entry point | Defined in header | Vector table at offset 0 (ARM Cortex-M) or fixed address | | Sections | Named, with permissions | Memory-mapped regions without metadata | | Dependencies | Dynamic libraries | Self-contained or hardware-specific | | Strings | OS API references | Hardware register names, RTOS symbols, custom protocols | | Relocation | OS handles ASLR | None — fixed addresses | ## Detecting Firmware ### Primary Indicators 1. **RAW format** with no PE/ELF/Mach-O magic: ```bash binary metadata --project --json # data.format: "RAW" ``` 2. **Recognizable strings** for embedded platforms: ```bash binary strings --project --min-length 8 --json ``` Look for: - RTOS names: "FreeRTOS", "ThreadX", "Zephyr", "uC/OS", "RT-Thread", "embOS", "VxWorks" - MCU families: "STM32", "ESP32", "nRF52", "MSP430", "PIC32", "LPC", "Kinetis" - Bootloader strings: "U-Boot", "Das U-Boot", "barebox", "MCUboot", "Little Kernel" - Hardware registers: "GPIO", "UART", "SPI", "I2C", "NVIC", "SCB" - Build toolchains: "arm-none-eabi-gcc", "IAR", "Keil", "STM32CubeIDE" - File systems: "LittleFS", "FATFS", "SPIFFS", "JFFS2", "UBIFS" - Network stacks: "lwIP", "uIP", "MQTT", "CoAP" 3. **Size characteristics**: Firmware is typically: - Power-of-2 aligned (e.g., exactly 256KB, 512KB, 1MB). - Smaller than desktop executables (mostly under 10MB). - Filled with `0xFF` padding (flash erase state). ### ARM Cortex-M Vector Table Detection ARM Cortex-M firmware starts with a vector table at offset 0: | Offset | Content | Expected Pattern | |--------|---------|-----------------| | 0x00 | Initial stack pointer | Should point to RAM range (e.g., 0x20000000+ for SRAM) | | 0x04 | Reset vector (entry point) | Should point to flash range (e.g., 0x08000000+) with bit 0 set (Thumb mode) | | 0x08 | NMI handler | Thumb-mode address | | 0x0C | HardFault handler | Thumb-mode address | | 0x10+ | Other exception handlers | Thumb-mode addresses | **Detection check:** ```bash binary bytes --project 0x0 128 --json ``` Look at the first 4 words: - Word[0] should be a RAM address (typical: 0x20000000-0x20020000 range). - Word[1] should be a flash address with bit 0 set (LSB = 1 = Thumb). - Words[2-15] should also be flash-range addresses with bit 0 set. ### ARM Exception Vector Table IDs | Vector Number | IRQ | Handler | |---------------|-----|---------| | 0 | — | Initial SP | | 1 | — | Reset | | 2 | -14 | NMI | | 3 | -13 | HardFault | | 4 | -12 | MemManage | | 5 | -11 | BusFault | | 6 | -10 | UsageFault | | 11 | -5 | SVCall | | 14 | -2 | PendSV | | 15 | -1 | SysTick | | 16+ | 0+ | Device-specific IRQs | ## Firmware Analysis Workflow ### Step 1: Determine Architecture and Base Address Without format headers, you need to determine: 1. **Architecture**: Usually evident from build toolchain strings. You can also try to guess from the binary structure: - ARM Thumb: Instructions are 2 or 4 bytes, bit 0 of addresses = 1. - ARM (A32): Instructions are 4 bytes, addresses are 4-byte aligned. - AArch64: Instructions are 4 bytes, addresses are 4-byte aligned. - RISC-V: Instructions are 2 or 4 bytes (compressed extension). - MIPS: Instructions are 4 bytes. 2. **Base address**: Where in memory the firmware is loaded. This is critical for correct disassembly. Signs: - Vector table addresses (ARM Cortex-M: initial SP and reset vector). - Absolute addresses in strings or data structures. - Bootloader configuration headers. ### Step 2: Use String Analysis as Primary Tool For formatless firmware, strings are your most valuable source: ```bash binary strings --project --min-length 6 --json ``` Categorize strings: | Category | Example Strings | What They Reveal | |----------|----------------|-------------------| | RTOS identification | "FreeRTOS", "vTaskDelay", "xQueueSend" | Operating system and version | | Hardware identification | "STM32F407", "nRF52840", "bcm2835" | Target chip — determines architecture and peripherals | | Pin/peripheral names | "UART1_TX", "SPI2_MOSI", "PA5" | Hardware interfaces in use | | Error messages | "WiFi connection failed", "Sensor timeout" | Functionality and failure modes | | AT commands | "AT+CIPSTART", "AT+HTTPGET" | Modem/communication interface | | Protocol strings | "MQTT", "HTTP/1.1", "/api/v1/" | Communication protocols and endpoints | | File paths | "/cfg/wifi.cfg", "/data/log.txt" | File system layout | | TLS certificates | "-----BEGIN CERTIFICATE-----" | Embedded certificates — note these | | Credentials | "admin:password", hardcoded keys | **Flag as security concern** | | Build identifiers | "v2.4.1-0-g3a7b", build dates | Firmware version and build info | ### Step 3: Identify Memory Regions Firmware images often contain multiple concatenated regions: - **Bootloader** (typically first 16-64KB): Minimal code to load the application. - **Application** (majority of the image): The main firmware. - **Filesystem** (trailing region): LittleFS, FATFS, or custom format. - **Configuration** (fixed offset): Calibration data, MAC addresses, serial numbers. - **OTA partitions**: Duplicate application and filesystem regions for over-the-air updates. Look for region boundaries: - String content changes (code-like strings → file-system-like strings). - Data pattern changes (compressed code → repeated structures → 0xFF padding). - Magic bytes for filesystems at aligned offsets. ### Step 4: Extract Filesystem (If Present) If you identify a filesystem region, note its offset and size. Common embedded filesystems and their magic bytes: | Filesystem | Magic / Signature | |-----------|-------------------| | LittleFS | `littlefs` at superblock offset | | FATFS | `MSDOS5.0` or `FAT12/16/32` in boot sector | | SPIFFS | `SPIFFS` in magic bytes | | JFFS2 | `0x1984` or `0x1985` at node headers | | UBIFS | `UBI#` at UBI eraseblock headers | Extract the filesystem for offline analysis using external tools — this is beyond the scope of the CLI, but identifying the presence and type of filesystem is within scope. ### Step 5: Look for Bootloader Patterns If the image contains a bootloader: ```bash # U-Boot specific binary strings --project --contains "U-Boot" --json # Bootloader version strings binary strings --project --contains "bootloader" --json ``` Common bootloader characteristics: - U-Boot: Has environment variables, device tree, boot commands. - MCUboot: SWAP/SCRATCH regions, image headers with TLV (type-length-value) structures. - Little Kernel (LK): "lk" or "Little Kernel" strings, app entry marker. ### Step 6: Look for Security Concerns Firmware-specific security concerns: 1. **Hardcoded credentials**: Passwords, API keys, tokens in strings. ```bash binary strings --project --contains "password" --json binary strings --project --contains "secret" --json binary strings --project --contains "key" --json ``` 2. **Debug interfaces left enabled**: JTAG/SWD/UART strings. ```bash binary strings --project --contains "debug" --json binary strings --project --contains "JTAG" --json ``` 3. **Insecure update mechanisms**: No signature verification, HTTP (not HTTPS) updates. ```bash binary strings --project --contains "http://" --json ``` 4. **Exposed UART/serial consoles**: Shell access strings. ```bash binary strings --project --contains "login" --json binary strings --project --contains "shell" --json ``` ## Architecture-Specific Patterns ### ARM Cortex-M - Vector table at 0x00000000 (or remapped). - Thumb/Thumb-2 instruction set. - Memory-mapped I/O: Peripheral registers at fixed addresses. - No MMU — flat memory model. - NVIC at 0xE000E100 for interrupt control. ### ARM Cortex-A - Typically runs Linux or an RTOS. - May have U-Boot headers. - Device tree blob (DTB) present: magic `0xD00DFEED`. - ELF or RAW kernel image. ### ESP32 / Xtensa - ESP32 uses Xtensa LX6 or LX7 cores. - ESP-IDF framework: "esp_image_header" magic. - Partition table at offset 0x8000. - NVS (Non-Volatile Storage) with "NVS" magic. ### RISC-V - Vector table optional (depends on implementation). - May have Device Tree Blob. - Compressed (RVC) and standard instructions coexist. ### MIPS - Firmware often starts at 0x9FC00000 (kseg0 boot) or 0xBFC00000. - Interrupt vector at 0x80000180. ## Reporting Firmware Findings Structure your firmware analysis report: ``` ## Firmware Analysis ### Identity - Format: RAW - Size: 524,288 bytes (512 KB — matches typical STM32F4 flash size) - Architecture: ARM Cortex-M (Thumb), likely STM32F4 - Build ID: "v2.4.1-0-g3a7b" (from strings) ### Components Identified - RTOS: FreeRTOS v10.4.3 (from task names and API strings) - Network stack: lwIP 2.1.2 (from init strings) - TLS: mbedTLS 2.28 (from certificate parsing strings) - File system: LittleFS (from LFS magic) ### Memory Layout (Determined from Strings and Structure) - 0x08000000-0x0800FFFF: Bootloader (64KB) - 0x08010000-0x0805FFFF: Application (320KB) - 0x08060000-0x0807FFFF: LittleFS filesystem (128KB) ### Security Observations - TLS certificates found — expected for IoT device - HTTP endpoint: http://api.device.example.com/firmware — update over HTTP, not HTTPS - Hardcoded string: "debugpass123" — possible debug backdoor - No secure boot indicators (no MCUboot or signature verification strings) ### Unknowns - SPI Flash configuration parameters not identified - Custom AT command parser at 0x08032000 — proprietary protocol ```