Skip to content

Instantly share code, notes, and snippets.

@theY4Kman
Created February 9, 2026 03:14
Show Gist options
  • Select an option

  • Save theY4Kman/2528393ec5b3b862699ea5fae78ab741 to your computer and use it in GitHub Desktop.

Select an option

Save theY4Kman/2528393ec5b3b862699ea5fae78ab741 to your computer and use it in GitHub Desktop.

BCM Firmware Reverse Engineering Report

2008 Chevy Colorado - Body Control Module (BCM)

Chip: TMS370C16 (F16E88PJA11)

Firmware: "2004 BCM OS.bin" — 57,344 bytes loaded in Ghidra at 0x10000-0x1DFFF

Architecture: 16-bit CPU, 17-bit address space (128KB), big endian, variable-length instructions (2-6 bytes, always even)


Table of Contents

  1. TMS370C16 Architecture Notes
  2. Operating System Structure
  3. Mode $27 Security Access — Complete Architecture
  4. The Seed-Key Algorithm
  5. Mode $23 Read Memory By Address
  6. Practical Attack Vectors
  7. RAM Variable Map
  8. ROM Constants
  9. Function Table
  10. Subsystem Handler Table
  11. SLEIGH Spec Bugs
  12. Open Questions

TMS370C16 Architecture Notes

Address Space

  • Registers: 0x0000-0x000F (R0-R15, memory-mapped). R15 = ZR (zero register, always reads 0).
  • Peripheral I/O: 0x0010-0x00FF
  • RAM: 0x0100+ (chip-variant dependent)
  • Internal ROM: 0x8000-0xFFFF range in data address space (chip-specific routines, NOT in firmware dump)
  • External ROM (firmware): 0x10000-0x1DFFF in program address space

Key Encoding Details

  • Word vs byte addressing: The PC holds word addresses. Byte address = word address x 2.
  • CALL/JMP encoding: EC 00 XX YY (4 bytes). Target byte address = 0xXXYY x 2.
  • Branch formula (ALL branch types): target = inst_start + 4 + sdisp8 * 2. The "+4" accounts for the TMS370C16 pipeline (PC points 2 words ahead during execution).
  • BRBIT encoding: 4 bytes total: opcode(1) + disp8(1) + addr16(2). Tests a bit in memory and branches conditionally.
  • 6-byte MOV: 28 FF src16 dst16 = MOV *src16, *dst16 (absolute memory-to-memory copy).
  • Code overlap pattern: Branches into the middle of multi-byte instructions to execute the trailing bytes as a different instruction. Intentional ROM size optimization / anti-RE technique.

Complete Opcode Map (extracted from SLEIGH spec)

MOV family: 0x02-0x2B (even=word, odd=byte)
  0x02/03 = MOV/MOVB Rs,Rd
  0x04/05 = MOV/MOVB Rs,*Rd (indirect store; when rs=15: CLR *Rd)
  0x06/07 = MOV/MOVB *Rs,Rd (indirect load)
  0x08/09 = MOV/MOVB Rs,*sdisp16[Rd] (4-byte indexed store)
  0x1A/1B = MOV/MOVB #imm16/#imm8,Rd (4-byte load immediate)
  0x20/21 = MOV/MOVB #imm16/#imm8,*sdisp16[Rd] (6-byte store immediate)
  0x22/23 = MOV/MOVB *sdisp16[Rs],Rd (4-byte indexed load)
  0x28/29 = MOV/MOVB *sdisp16[Rs],*sdisp16[Rd] (6-byte mem-to-mem)
ALU:    0x30-0x3F (ADD/ADDB/SUB/SUBB and carry variants)
Logic:  0x40-0x57 (AND/OR/XOR and variants)
CMP:    0x60-0x67 (CMP/CMPB variants)
Quick:  0x80=MOVQ, 0x82/83=ADQ/ADQB, 0x86/87=SUBQ/SUBQB
Carry:  0x8A=ADC, 0x8C=SBB, 0x8E/8F=CMPC
Bit:    0x90-0x97 (SBIT1/SBIT0/LDBIT/STBIT), 0x98=TBIT (missing from SLEIGH spec)
Shifts: 0xB0-0xBF (SHL/SHLL/ASR/ASRL/LSR/LSRL)
Branch: 0xC0=BR, C1=BNC, C2=BC, C3=BEQ, C4=BNE, C5=BHI, C6=BLS,
        C7=BGT, C8=BLE, C9=BGE, CA=BLT, CB=BV, CC=BNV, CD=BP, CE=BPZ, CF=BN
BRBIT:  0xD0-D7=BRBIT0 #0-7, 0xD8-DF=BRBIT1 #0-7 (4 bytes each)
Ctrl:   0xE8=JMP Rd, 0xE9=JMP addr, 0xEA=JMP *sdisp16[Rd], 0xEC=CALL addr
        0xF8=RTDU, 0xF9=PUSH, 0xFA=POP, 0xFB 00=RTS, 0xFC=RTI
Other:  0x7A=SHL4, 0x7B=SHL8, 0x7C=SHR8, 0xA6=MPYSB, 0xA7=MPYS, 0xA8=DBNZ,
        0xFD=SWAPB, 0xFE=IDLE, 0xFF=TRAP
Extended bit: 0xE0-E7 (SBIT1/SBIT0/LDBIT/STBIT with register/memory variants)

Operating System Structure

Main Scheduler Loop — FUN_016a08

The BCM's main loop is at 0x16A08. It sequentially CALLs every subsystem handler, then dispatches via a computed jump table. This runs continuously while the BCM is powered.

0x16A08: CALL turn_signal_handler        (0x1263E)
0x16A0C: CALL theft_deterrent_handler    (0x164C2)
0x16A10: CALL nop_placeholder            (0x145BC)
0x16A14: CALL retained_accessory_power   (0x13372)
0x16A18: CALL battery_saver              (0x14496)
0x16A1C: CALL headlight_output_driver    (0x1635C)
0x16A20: CALL wiper_washer_handler       (0x13922)
0x16A24: CALL horn_handler               (0x12558)
  ... test flags, conditional dispatch ...
0x16A2C: CALL chime_buzzer_handler       (0x15DBE)
  ... jump table dispatch via *0xB436[R12] ...
0x16A5C: CALL internal_rom_D9B4          (0x0D9B4)  ** INTERNAL ROM **
0x16A60: CALL firmware_11BCE             (0x11BCE)
0x16A64: CALL internal_rom_D1DE          (0x0D1DE)  ** INTERNAL ROM **
0x16A68: CALL firmware_14366             (0x14366)
0x16A6C: CALL internal_rom_F508          (0x0F508)  ** INTERNAL ROM **
  ... more handlers ...
0x16A82: CALL convergence_step           (0x161E6)  (entry into verification function)
0x16A86: CALL internal_rom_F00A          (0x0F00A)  ** INTERNAL ROM **
0x16A8A: CALL internal_rom_B800          (0x0B800)  ** INTERNAL ROM **
0x16A8E: CALL internal_rom_BF66          (0x0BF66)  ** INTERNAL ROM **
  ... more handlers, then loop ...

Five handlers run in internal chip ROM (addresses below 0x10000) and are invisible to us. These handle chip-level security, timers, and other silicon-specific functions.


Mode $27 Security Access

Overview

Mode $27 implements UDS Security Access for the BCM. The architecture is more complex than a simple seed-key comparison — it uses an ISR-driven convergence algorithm operating on three 32-bit values.

Complete Architecture

                     FIRMWARE (visible)                    INTERNAL ROM (hidden)
               ┌──────────────────────────────┐       ┌──────────────────────────┐
 Mode $27 ────>│ Handler 0x1A5BC              │       │                          │
 Sub $01/$02   │ Routes via bits in 0x288C    │       │                          │
               │           |                  │       │                          │
               │           v                  │       │                          │
               │ State Machine 0x16566        │       │                          │
               │ (timers, counters,           │       │                          │
               │  status codes at 0x2D9C)     │       │                          │
               │           |                  │       │                          │
               │           v                  │       │                          │
               │ Security Dispatch 0x15458    │       │                          │
               │ Checks sub-function vs       │       │                          │
               │ config table at R0+n:        │       │                          │
               │  R0+1 → convergence check    │       │                          │
               │  R0+2 → Send Key path        │       │                          │
               │  R0+3 → ROM algorithm call ──┼─CALL─>│ ROM Routine 0xF782       │
               │                              │       │ - Reads seed (0x275C)    │
               │                              │<─RET──│ - Reads received key     │
               │                              │       │ - Computes A, B, C       │
               │ Source Table 0x20E0-0x20EC   │       │ - Writes to 0x20E0-20EC  │
               │ A (32-bit), B, C, flags      │       │                          │
               │           |                  │       └──────────────────────────┘
               │     ISR 0x1608C (periodic)   │
               │     Copies source table to   │
               │     verify area 0x267A-2684  │
               │     Loads threshold from     │
               │     ROM 0x9816-0x9818        │
               │           |                  │
               │     Convergence 0x161AE      │
               │     Euclidean subtraction    │
               │     loop on A, B, C          │
               │           |                  │
               │     ┌─────┴──────┐           │
               │   A==B==C?    A!=B!=C?       │
               │     |            |           │
               │  0x1549C      0x15562        │
               │  UNLOCK       DENY           │
               │                              │
               │ Write-back 0x1B562           │
               │ (converged result -> source) │
               │                              │
               │ Init/Reset 0x1825E           │
               │ (clears buffers, calls       │
               │  ROM 0xF782, sets flags)     │
               └──────────────────────────────┘

Handler Flow (0x1A5BC)

The Mode $27 handler at 0x1A5BC routes based on bits in RAM 0x288C:

  • Bit 7: Skip to end (already processed)
  • Bit 6: Send Key path (sub-function $02)
  • Bit 2: Fast exit

For Request Seed (sub $01): generates a 16-bit seed at 0x275C-0x275D using code at 0x1A160 (calls bit manipulation utility at 0x13160 and helpers at 0x16904, 0x16718).

For Send Key (sub $02): routes through the state machine at 0x16566 to the security dispatch at 0x15458, which conditionally calls internal ROM at 0xF782.

0-Key Bypass Vulnerability

When the seed equals 0x0000, the handler increments a counter at 0x288D. After 26 consecutive calls with seed == 0, the BCM sends a positive response ($67) and grants security access without any key verification.

State Machine — Lockout Logic (0x16566)

The state machine manages a dual-timer lockout system:

Status 1 ("Ready"):
  - New seed generated
  - Seed validity timer loaded from ROM 0x9AAB -> RAM 0x2800

Status 2-3 ("Challenge active"):
  - Seed is valid, accepting key attempts
  - Attempt counter at 0x2807 decrements per failed attempt

Status 4 ("Attempts exhausted"):
  - Counter reached 0

Status 5 ("Lockout"):
  - Lockout timer = ROM(0x9AAD) * 2 -> RAM 0x2804
  - All attempts rejected with $7F $27 $37
  - Processing flags cleared

  When lockout timer expires:
    -> Back to Status 1 (NEW seed generated)

Critical for brute force: the seed changes after every lockout cycle.

ISR Verification Driver (0x1608C)

This interrupt service routine runs periodically and:

  1. Copies the source table (0x20E0-0x20EC) to the verification area (0x267A-0x2684):

    • 0x20E0:0x20E2 -> 0x267A:0x267C (A, 32-bit hi:lo)
    • 0x20E4:0x20E6 -> 0x267E:0x2680 (B, 32-bit hi:lo)
    • 0x20E8:0x20EA -> 0x2682:0x2684 (C, 32-bit hi:lo)
    • 0x20EC -> 0x266E (flags)
  2. Loads convergence threshold from internal ROM 0x9816:0x9818 (32-bit, values unknown)

  3. Runs multi-step comparison:

    • Quick check: if A==B==C trivially, jump to quick exit
    • If B != C: enter convergence subtraction loop at 0x161BC
    • Otherwise: threshold-based comparisons
  4. Falls through to FUN_016174 (convergence pre-check) then to the verification function at 0x161AE.

  5. Ends with RTI (Return from Interrupt) — confirming it's an ISR.

Verification Function (0x161AE)

Operates on three 32-bit values in the verification area:

  • A at 0x267A:0x267C
  • B at 0x267E:0x2680
  • C at 0x2682:0x2684
  • Temp at 0x2672:0x2674
  • Output at 0x2686:0x2688
  • Convergence flag: bit 7 of 0x266C

Contains a Euclidean-style subtraction loop at 0x161BC that iteratively converges the three values. If A==B==C after convergence:

  • Calls 0x1549C (security UNLOCK)

If mismatch:

  • Calls 0x15562 (denial handler)
  • Calls 0x16726 (send negative response)
  • Sets bit 7 of 0x2786

Convergence Write-back (0x1B562)

When convergence is NOT yet complete (bit 7 of 0x266C clear):

  • Copies temp value to ALL source table entries: A = B = C = temp
  • Copies temp to output (0x2686:0x2688)
  • Sets bit 7 of 0x2784

This feeds the converged intermediate result back to the source table for the next ISR cycle.


The Seed-Key Algorithm

Finding: Algorithm Lives in Internal Chip ROM

After exhaustive searching of the firmware binary for any code that writes to the source table at 0x20E0-0x20EC, we found:

  • 3 firmware-level references: ISR reads (0x1608C), init passthrough (0x1825E), convergence write-back (0x1B562)
  • 0 firmware-level WRITE origins: No code in the firmware computes initial A, B, C values

The seed-key derivation is performed by internal ROM routine at byte address 0xF782 (word address 0x7BC1). This routine is called from:

  • 0x154B8 — conditionally, when the diagnostic sub-function matches config[R0+3]
  • 0x18342 — during init/reset (0x1825E function)
  • 0x1A66A — near the Mode $27 handler (cleanup/reset path)

The internal ROM is baked into the TMS370C16 silicon and cannot be read from the external EPROM dump. This is a deliberate GM/TI security measure.

Algorithm Classification

Per the pcmhacking.net community, this BCM likely uses GM algorithm $12 (0x12). GM uses ~256 numbered algorithms across their modules. The algorithm number determines the mathematical transformation from seed to key.

Documented GM algorithms (like $0B) use simple operations:

temp = (seed << 2) | (seed >> 14)    // rotate left 2
key  = byte_swap(temp + 0xB6B6) - 0xFDDA

Algorithm $12 specifically is not publicly documented. The convergence architecture (Euclidean subtraction on three 32-bit values) suggests a more sophisticated scheme than typical GM algorithms.


Mode $23 Read Memory By Address

Handler at 0x177AA

Mode $23 IS implemented in the firmware (contrary to the "error 0x00" observed over OBD — that error is because security access is required).

The handler's entry sequence:

  1. SID/mode check against configuration byte at R0+9
  2. CALL 0x14226 — security/configuration gate
  3. If gate returns 0 -> reject with negative response
  4. If gate passes -> proceed with memory read

Security Gate — FUN_014226

  1. Tests bit 5 of ROM config byte at 0x9AC2
    • If not set: sends negative response and returns (service disabled)
    • If set: continues
  2. Additional checks against 0x27EC and ROM values
  3. Returns non-zero if access is granted

Conclusion: Mode $23 requires Mode $27 security access. You must authenticate first.


Practical Attack Vectors

1. 0-Key Bypass (easiest, try first)

If the seed is ever 0x0000 (possible after cold start or specific conditions):

  • Send 26 consecutive $27 $01 requests
  • BCM grants security access without key verification
  • Then use Mode $23 freely

2. Brute Force (feasible if key is 16-bit)

Setup: ELM327 + Python script over J1850 VPW

Procedure:

  1. Request seed ($27 $01) -> get 2-byte seed
  2. Send candidate key ($27 $02 KK KK)
  3. Repeat until success or lockout

Complications:

  • Attempt counter (0x2807) limits tries per seed — count from ROM 0x9AAE
  • Lockout timer (0x2804) blocks attempts — duration from ROM 0x9AAD * 2
  • Seed changes after each lockout cycle (Status 5 -> Status 1)
  • Each cycle is probabilistic: N/65536 chance of hitting the right key

Estimated times (seed changes each cycle, so it's probabilistic):

Attempts/seed (N) Lockout (L) Expected time
3 10 sec ~61 hours
5 10 sec ~36 hours
3 30 sec ~7.6 days
10 10 sec ~18 hours

Step 1: Probe lockout parameters empirically — send wrong keys until $7F $27 $36, count N, time L.

Step 2: If 4-byte key instead of 2-byte, brute force is infeasible (4 billion combinations).

3. JTAG / MPSD (most powerful, hardest access)

The TMS370C16 has an MPSD (Multi-Pin Serial Debug) port. The FT2232H adapter supports JTAG.

Capabilities:

  • Direct RAM read/write (bypasses all software security)
  • Read internal ROM (including the algorithm at 0xF782!)
  • Read ROM configuration constants (0x9AAA-0x9AAE, 0x9816-0x9818, 0x9AC2)
  • Full chip debug

Drawback: Requires physical access to the BCM board (JTAG pins), and the BCM is difficult to reach in the truck.

4. Known Algorithm Research

Search automotive security communities for GM algorithm $12 implementations. Key resources:


RAM Variable Map

Address Label Purpose
0x0060-0x0063 OUTPUT_PORTS_1_4 Output/control ports
0x0064-0x0067 INPUT_PORTS_1_4 Input/status ports
0x0068-0x006F IO_PORTS_A_D Bidirectional I/O
0x20A0-0x20B1 KEY_INPUT_BUFFER Input buffer for security algorithm (cleared after use)
0x20D0-0x20D2 SECURITY_ROM_PARAMS ROM constants copied during init
0x20E0:0x20E2 SOURCE_A Source table: value A (32-bit, hi:lo)
0x20E4:0x20E6 SOURCE_B Source table: value B (32-bit, hi:lo)
0x20E8:0x20EA SOURCE_C Source table: value C (32-bit, hi:lo)
0x20EC SOURCE_FLAGS Source table: flags
0x21BA INIT_STATE_FLAG Set during init, cleared during convergence write-back
0x23B4 DIAG_SUCCESS_FLAGS Diagnostic handler success flags
0x23DB SID_GROUP_TRACKER SID group tracker
0x23DC SID_LOW_NIBBLE SID low nibble storage
0x23E0 SID_COPY SID copy storage
0x2484 DIAG_MSG_BUFFER Diagnostic message buffer (85 bytes)
0x2508-0x2511 SEED_WORK_BUF Working buffer for seed bit manipulation
0x25F8 DIAG_CURRENT_SID Current SID being processed
0x25FA DIAG_SUBFUNC Sub-function byte from diagnostic message
0x2613 DIAG_SESSION_STATE Session state
0x266C CONVERGENCE_FLAG Bit 7 = convergence complete
0x266E VERIFY_FLAGS Verification flags (from 0x20EC)
0x2672:0x2674 VERIFY_TEMP Temp 32-bit value for convergence
0x267A:0x267C VERIFY_A Verification copy of A (32-bit)
0x267E:0x2680 VERIFY_B Verification copy of B (32-bit)
0x2682:0x2684 VERIFY_C Verification copy of C (32-bit)
0x2686:0x2688 VERIFY_OUTPUT Verification output (32-bit)
0x26AC-0x26CA SECURITY_PARAM_BLOCK Security algorithm parameter block
0x275C-0x275D SEED_VALUE 16-bit seed for Mode $27
0x2781-0x2788 SECURITY_COMPLETION_FLAGS Bit 7 of each = completion/status flags
0x2800 SEED_TIMER Seed validity countdown timer
0x2804 LOCKOUT_TIMER Security lockout countdown timer
0x2807 ATTEMPT_COUNTER Remaining key attempts before lockout
0x2808 SECURITY_STATUS_FLAGS Security status flags (BRBIT tested)
0x288C SECURITY_SUBFUNC_FLAGS Sub-function routing bits (bit 6=SendKey, bit 7=skip)
0x288D ZERO_KEY_BYPASS_CTR Counter for 0-key bypass (triggers at 26)
0x2CE0-0x2CE3 SECURITY_STATE Security access state
0x2D9C-0x2D9E SECURITY_STATUS_CODES Status codes (1=ready, 4=exhausted, 5=lockout)
0x27FD-0x27FE SECURITY_PROC_FLAGS Processing flags

ROM Constants (Internal Chip ROM — not in firmware dump)

Address Purpose
0x9816-0x9818 Convergence threshold (32-bit)
0x9867-0x9868 Bit test constants for seed generation (0x13160)
0x9AAA Security config (referenced by state machine)
0x9AAB Seed validity timer initial value -> 0x2800
0x9AAD Lockout timer base value (doubled) -> 0x2804
0x9AAE Max attempt count (shifted) -> 0x2807
0x9AC2 Mode $23 service enable flag (bit 5)
0x9BED-0x9BEE ROM constants copied to 0x20D0-0x20D1 during init
0x9AD9 ROM constant copied to 0x20D2 during init
0x9D14 Constant used by denial handler (0x15562)

Function Table

Address Name Size Purpose
0x1608C (ISR) ~488B Key verification ISR driver. Copies source table, runs convergence, ends with RTI
0x13160 (unnamed) 80B Bit manipulation utility for seed generation
0x14226 FUN_014226 42B Security/config gate for diagnostic services
0x15458 FUN_015458 ~150B+ Security dispatch — routes sub-functions, calls ROM 0xF782
0x1549C (unnamed) ? Security UNLOCK function (called when A==B==C)
0x15562 (unnamed) ? Security denial / iteration handler (XOR/AND ops)
0x161AE FUN_0161ae 200B Seed-key verification: convergence loop + A==B==C check
0x16174 FUN_016174 58B Convergence pre-check, falls through to 0x161AE
0x164C2 FUN_0164c2 208B Theft deterrent handler
0x16566 (state machine) 210B Mode $27 state machine (timers, counters, status)
0x16718 util_called_32 ? Utility called from seed generation (Ghidra body=4B, actually much larger)
0x16726 (unnamed) ? Send negative diagnostic response
0x16734 (unnamed) ? Send diagnostic response
0x16904 (unnamed) ? Read/process field from diagnostic message
0x1692C (unnamed) ? Complex security data processing, operates on 0x26AC-0x26CA
0x177AA (unnamed) ? Mode $23 handler (security-gated)
0x1825E (unnamed) 268B Security init/reset. Clears buffers, calls ROM 0xF782, sets flags
0x1A160 (unnamed) ? Seed generation code
0x1A5BC mode27_security_handler ? Mode $27 handler entry point
0x1A620 FUN_01A620 ? Diagnostic state cleanup
0x1B562 (unnamed) ? Convergence write-back (temp -> source table when not yet converged)
0x16A08 FUN_016a08 large Main OS scheduler loop — calls all subsystem handlers

Subsystem Handler Table

Called sequentially by the main loop at 0x16A08:

# Address Name Confidence
1 0x154DE timer_scheduler Medium
2 0x10CF2 io_port_init High
3 0x10276 calibration_table_loader Medium
4 0x13D92 class2_serial_data_handler High
5 0x11002 pwm_timer_setup Medium
6 0x169B6 task_dispatcher_body High
7 0x11598 output_driver_update High
8 0x11A9E state_machine_dispatch Low
9 0x107F8 sys_config_init Low
10 0x128E0 door_lock_handler High
11 0x12FF2 exterior_lighting_control High
12 0x1263E turn_signal_handler Medium
13 0x164C2 theft_deterrent_handler High
14 0x145BC nop_placeholder High
15 0x13372 retained_accessory_power High
16 0x14496 battery_saver High
17 0x1635C headlight_output_driver High
18 0x13922 wiper_washer_handler High
19 0x12558 horn_handler Medium
20 0x15DBE chime_buzzer_handler High

SLEIGH Spec Bugs

The Ghidra SLEIGH specification at ghidra-tms370c16/data/languages/TMS370C16/TMS370C16.slaspec has several bugs that cause garbled disassembly:

  1. Branch offset formula (line 313): inst_next + (sdisp8 * 2) should be inst_start + 4 + (sdisp8 * 2).

  2. BRBIT size (lines 2563-2644): Defined as 6 bytes (3 tokens). Should be 4 bytes (2 tokens: opcode+disp8, addr16).

  3. Missing opcode 0x98: TBIT #imm4, Rd (Test Bit) is not defined.

  4. brword token definition (line 106): Incorrect.

  5. 0x28/0x29 opcode (MOV/MOVB mem-to-mem): Defined as 4-byte but should be 6-byte (3 x 16-bit tokens). This causes cascading misalignment in Ghidra's disassembly.

  6. Overlapping token fields: AND #imm16, *sdisp16[Rd] has conflicting field definitions.

These bugs cause Ghidra to produce incorrect disassembly for much of the firmware. Manual decoding from raw bytes (using the opcode map above) is necessary for accurate analysis.


Open Questions

  1. Algorithm $12 implementation: The actual seed-to-key transformation is in internal ROM at 0xF782. Can it be extracted via JTAG, or found in community documentation?

  2. ROM constant values: All security-critical constants (0x9AAA-0x9AAE, 0x9816-0x9818, 0x9AC2) are in internal ROM. Exact values unknown.

  3. Lockout parameters: Attempt count (N) and lockout duration (L) are from internal ROM. Must be measured empirically.

  4. Key length: Almost certainly 2 bytes (seed is 16-bit at 0x275C-0x275D), but should be confirmed by observing the Mode $27 exchange.

  5. 0-key bypass conditions: Under what conditions does the seed equal 0x0000? Cold start? Timer expiry? Always-zero initial state?

  6. Mode $23 capability: Once security is bypassed, what address ranges can Mode $23 read? Can it access internal ROM?

  7. Source table population: Confirmed that internal ROM routine writes to 0x20E0-0x20EC, but the exact algorithm remains unknown.

  8. Function at 0x15562: The denial/iteration handler contains XOR/AND operations on RAM 0x27C6-0x27CF. Role in the verification pipeline unclear.


Report generated from multi-session Ghidra analysis of "2004 BCM OS.bin" firmware dump. Last updated: 2026-02-08

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment