Welcome to the Fortify Labs blog

May 25, 2026 / by Dave L - Fortify Labs / In teardown, technical, Hino, Freightliner, Bosch, Telematics, NAND Flash, NXP i.MX6, GPMI, BCH ECC, UBI, UBIFS, nandsim, Reverse Engineering, Transport & Logistics, Heavy Equipment

Teardown: Hino & Freightliner
Telematics Module - Part 2

Thanks for re-joining me where I try and find out if telematics modules (Tboxes) from heavy transport trucks operate in the same was as passenger cars.

In Part 1, I took apart the Tboxes and saw that although they were from different manufacturers, they were nearly identical. After trying (and failing) to talk to the chips on the boards, or finding any other ways of connecting to it (WiFi/Bluetooth), I resorted to performing a chip off of the Freightliner’s flash memory and reading it.

This post continues the journey of trying to find out more about how these Tboxes work by trying to analyse what’s on the memory chip.

However, as we’ll see in this post, getting the memory into a clean, easily readable state was more challenging than I expected.

This post shows issues I found with the memory that prevented existing tools from working, what I discovered out about NAND memory along the way, and how I processed the memory and was eventually able to mount 5 of the Tbox firmware’s internal partitions on my Linux workstation.

Hino & Freightliner Blog Series

  • Part 1: Initial Examination
    • Teardown
    • PCB Characterization
    • Searching for UART, JTAG, and WiFi
    • Chip-Off Data Extraction
  • Part 2: Obtaining a Useable Image - This Post
    • Confirming NAND Controller Encoding
    • Removing NAND Controller Encoding
    • Mounting UBIFS Volumes in Linux
  • Part 3: Data Analysis

Where I left off - NAND Flash Memory Image

At the end of Part 1 I had a memory image of the Freighliner’s Tbox. Having a quick look at it, we see that it’s just over 1 GB in size.


  $ ls -al
  total 1081356
  drwxrwxr-x 2 user user       4096 May 24 09:22 .
  drwxrwxr-x 4 user user       4096 May 24 09:20 ..
  -rw-rw-r-- 1 user user 1107296256 May 24 09:22 MX60LF8G18AC@BGA63-FRLNR_FSH.BIN

  $ ls -alh
  total 1.1G
  drwxrwxr-x 2 user user 4.0K May 24 09:22 .
  drwxrwxr-x 4 user user 4.0K May 24 09:20 ..
  -rw-rw-r-- 1 user user 1.1G May 24 09:22 MX60LF8G18AC@BGA63-FRLNR_FSH.BIN

The first step from here was to see if we could determine what the image contained. Using binwalk on the image file, I found the most interesting part to be an apparent UBI volume:


  $ binwalk MX60LF8G18AC@BGA63-FRLNR_FSH.BIN

  DECIMAL       HEXADECIMAL     DESCRIPTION
  --------------------------------------------------------------------------------
  547783        0x85BC7         LZO compressed data
  ...
  ...
  8650762       0x84000A        UBI erase count header, version: 1, EC: 0x2FE, VID header offset: 0x800, data offset: 0x1000  ...
  ...
  ...

Verification Attempt with ubireader

I started with ubireader, an open-source Python tool that can read and process UBI/UBIFS images. You can find a version of the tool here: ubireader.

I ran the ubireader_display_info command (using -s to tell the tool the offset of where the UBI volume exists in the image) and tried and display the UBI Volume’s information. However, I received an error:


  $ ubireader_display_info -s 8650762 MX60LF8G18AC@BGA63-FRLNR_FSH.BIN 
  UBI_File Warning: end_offset - start_offset length is not block aligned, could mean missing data.
  UBI Fatal: Less than 2 layout blocks found.

Sometimes binwalk gives you wrong information, so my next step was to try and verify that we actually had a UBI image in the image file and that we didn’t just hit a false positive.

I searched the NAND image for UBI magic headers (the UBI# and UBI! signatures that mark erase counter blocks and volume identifier headers) to verify the volume structure.

I found some, which made it look like a legitimate UBI volume, but at this point I noticed that the UBI# header was consistently offset by 10 bytes from the start of the memory block.


  $ xxd MX60LF8G18AC@BGA63-FRLNR_FSH.BIN | grep "5542 4923" | head
  00840000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  00861000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  00882000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  008a3000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  008c4000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  008e5000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  00906000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  00927000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  00948000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..
  00969000: 00ff ffff ffff ffff ffff 5542 4923 0100  ..........UBI#..

  $ grep -abo $'\x55\x42\x49\x23' MX60LF8G18AC@BGA63-FRLNR_FSH.BIN | head
  ...
  8650762:UBI#
  8785930:UBI#
  8921098:UBI#
  9056266:UBI#
  9191434:UBI#
  9326602:UBI#
  9461770:UBI#
  9596938:UBI#

This wasn’t right. UBI uses UBI# to mark the start of an erase block header, so there appeared to be something I was missing here.


Flash Memory - Confirm the Encoding

I needed to understand how the data was being written to the NAND Flash memory. That lead me to read more about how NAND flash memory works.

I read through the main processor’s datasheet and found that the processor itself has a NAND controller embedded within it. The NAND controller is essentially a middleman between the raw flash and the CPU, it manages reading and writing to the chip and handles the low-level housekeeping of managing the raw memory. Part of that housekeeping is error correction - as data is written, the controller splits each page into smaller chunks (in our case 512 bytes each) and inserts bytes after every chunk so it can detect and repair errors as it reads it from the chip.

Normally, the NAND controller would seamlessly use the additional error correcting data, but in a raw chip-off dump those ECC bytes sit intertwined or “interleaved” between the data chunks exactly as they were written, so reconstructing the original filesystem image meant I had to strip them back out.

Building a De-Interleaving tool

I needed to replicate the behaviour of the controller with a script that removes this data.

There is a downside to simply removing these bytes. Because this additional data is used by the NAND controller for error correction, by simply removing this data we run the risk of losing some data. But, as a first pass, I decided to push on and see if we could get the majority of the data back.

Rather than try and build my own script, I used an AI assistant (Claude from Anthropic) to speed things up and provided it with all the information it would need to create a “de-interleaving” script to work with my memory image.

Using the datasheets and reference manuals, I gathered the information I needed to understand how this data was organised on the chip.

Chip Information Obtained Reference Section Link to Document
Main SoC (NXP MCIMX6U6AVM08AD) datasheet NAND Controller, ECC Engine Section 4.10 HINO_NXP_Processor_IMX6SDLAEC.pdf
Main SoC (NXP MCIMX6U6AVM08AD) reference manual Page Layout, Block-Mark Swap Sections 8.5.2.7.1 & 8.5.2.7.2 HINO_NXP_Processor_Reference-Manual.pdf
NAND Flash Memory (MXIC MX60LF8G18AC) Page (main + spare), Erase Block, Total Chip Sizes Sections 1 & 2 HINO_Flash_MX60LF8G18AC_3V_8Gb_v1-1.pdf

Note: I don’t expand on reasoning behind all of the info below as it sits outside the scope of this blog post. But, if you’re reading along and have any questions, feel free to get in touch and we’d be happy to help.

De-Interleaving - What We Needed to Know

I gathered up all of the following information to build my Claude prompt:

NAND Flash Chip

The NAND flash chip information we need is:


  Make: Macronix
  Model: MX60LF8G18AC
  Page Size - Main: 2048 bytes
  Page Size - Spare: 64 bytes
  Total Page Size: 2112 bytes
  Total Memory: 8 Gbit ÷ 8 bits/byte = 1 GiB (1,073,741,824 bytes)
  Total Pages: 1,073,741,824 bytes / 2048 = 524,288 pages
NAND - Datasheet
NAND - Datasheet
Flash Page Size
Flash Page Size
SoC Chip (Datasheet Information)

The main SoC information we require is:


  - Make: NXP
  - Model: MCIMX6U6AVM08AD
  - NAND Controller: GPMI, 8-Bit NAND Flash, BCH ECC
SoC - Datasheet
SoC - Datasheet
SoC - Datasheet
SoC - Datasheet
SoC Chip (Reference Manual Information)

The main SoC information we require is:

  • Page Layout:

    Note: How each 2112-byte physical page is broken up between actual data, the controller’s metadata, and error-correction bytes.

  
  - 10 bytes metadata
  - 4 × (512 B data + 13 B BCH ECC)
  - 2 bytes padding
  - Total: 2112 bytes per page
  • Block-Mark Swap (Sections 8.5.2.7.2 & 8.5.2.5):

    Note: The NXP controller shuffles one byte aside (during a write) to avoid overwriting the manufacturer’s bad-block marker. This byte needs to be put back when the memory is read.


  - The Macronix datasheet places the factory bad-block marker at OOB byte 0 (column address 2048).
  - The controller's page layout (8.5.2.7.1) maps logical data byte 1999 to physical byte 2048 — the same location as the bad-block marker.
  - On write, the controller stashes the data byte that would have landed at logical offset 1999 into metadata byte 0, and writes the manufacturer's marker byte at physical 2048 instead.
  - On read (or de-interleave), the byte stored in metadata[0] must be restored to logical offset 1999.  
  • ECC Strength:

    Note: How much error-correction is added after every 512 bytes of data, and how many bytes it takes to do it.

  
  - BCH 8-bit per 512-byte chunk (13 ECC bytes per chunk)
SoC - Reference Manual
SoC - Reference Manual
SoC - Reference Manual
SoC - Reference Manual

Building the Script

WIth the information gathered above, I was ready to see if Claude could create a script that would remove the additional information in the memory image so we could work with it.

The prompt I used was:


  I have a chip-off NAND dump from an NXP MX60LF8G18AC SoC that uses a GPMI controller. Write 
  `gpmi_deinterleave.py` that converts the dump into a clean logical image.

  NAND FLASH CHIP
    Make: Macronix
    Model: MX60LF8G18AC
    Page Size - Main: 2048 bytes
    Page Size - Spare: 64 bytes
    Total Page Size: 2112 bytes
    Total Memory: 8 Gb / 8 bits = 1 GiB (1,073,741,824 bytes)
    Total Pages: 1,073,741,824 bytes / 2048 = 524,288 pages

  SoC CONTROLLER 
    Make: NXP
    Model: MCIMX6U6AVM08AD
    NAND Controller: GPMI, 8-Bit NAND Flash, BCH ECC

  SoC CONTROLLER - PAGE LAYOUT
    bytes 0..9       metadata        (drop, but keep byte 0 for the swap)
    bytes 10..521    data chunk 0    (keep — 512 B)
    bytes 522..534   ECC chunk 0     (drop — 13 B)
    bytes 535..1046  data chunk 1    (keep)
    bytes 1047..1059 ECC chunk 1     (drop)
    bytes 1060..1571 data chunk 2    (keep)
    bytes 1572..1584 ECC chunk 2     (drop)
    bytes 1585..2096 data chunk 3    (keep)
    bytes 2097..2109 ECC chunk 3     (drop)
    bytes 2110..2111 padding         (drop)

  BLOCK-MARK SWAP (from RM §8.5.2.7.2)
    After de-interleaving each page to 2048 B, overwrite logical byte 1999
    with the original metadata byte 0. (The controller hid the real data
    byte there on write, leaving 0xFF in its place.)

  REQUIREMENTS
    - Stream the 1 GiB input; don't load it all at once
    - Output size must be exactly 1,073,741,824 bytes
    - Clear and detailed comments 
    - One-line progress indicator
    - If you require more information or need clarification, ask and do not assume anything

When Claude finished, I ran the gpmi_deinterleave.py script it created and checked the size of the output:


  $ python3 gpmi_deinterleave.py MX60LF8G18AC@BGA63-FRLNR_FSH.BIN MX60LF8G18AC-deinterleaved.BIN
  [100.00%] page  524288/524288   in:  1056.00 MiB   out:  1024.00 MiB
  done. 1,073,741,824 B written to MX60LF8G18AC-deinterleaved.BIN
  
  $ ls -al
  total 3180240
  drwxrwxr-x  2 user user       4096 May 20 17:58  ./
  drwxrwxr-x 13 user user       4096 May 19 19:44  ../
  -rw-rw-r--  1 user user      11659 May 19 19:48  gpmi_deinterleave.py
  -rw-rw-r--  1 user user 1107296256 May 19 19:48 'MX60LF8G18AC@BGA63-FRLNR_FSH.BIN'
  -rw-rw-r--  1 user user 1073741824 May 19 19:50  MX60LF8G18AC-deinterleaved.BIN

  $ ls -alh
  total 2.1G
  drwxrwxr-x 2 user user 4.0K May 20 17:58  ./
  drwxrwxr-x 4 user user 4.0K May 19 19:44  ../
  -rw-rw-r-- 1 user user  12K May 19 19:48  gpmi_deinterleave.py
  -rw-rw-r-- 1 user user 1.1G May 19 19:48 'MX60LF8G18AC@BGA63-FRLNR_FSH.BIN'
  -rw-rw-r-- 1 user user 1.0G May 19 19:50  MX60LF8G18AC-deinterleaved.BIN

I saw that the size changed from 1.1G to the expected 1.0G so this was a good sign. This appeared to make sense.

With the additional bytes used by the controller (or OOB data) the total size should be:


  (2,048 + 64) bytes/page × 64 pages/block × 8,192 blocks (as per the datasheet)
  2,112 × 64 × 8,192 = 1,107,296,256 bytes

And after (only keeping the actual data), the size should be:


  2,048 bytes/page × 64 pages/block × 8,192 blocks
  2,048 × 64 × 8,192 = 1,073,741,824 bytes

Those figures matched what we saw above. So far so good… I re-ran binwalk and also looked to see if the UBI# header was now aligned to the start of the memory block.


  $ binwalk MX60LF8G18AC-deinterleaved.BIN 

  DECIMAL       HEXADECIMAL     DESCRIPTION
  --------------------------------------------------------------------------------
  531184        0x81AF0         LZO compressed data
  ...
  ...
  8388608       0x800000        UBI erase count header, version: 1, EC: 0x2FE, VID header offset: 0x800, data offset: 0x1000
  ...

  $ xxd MX60LF8G18AC-deinterleaved.BIN | grep "5542 4923" | head
  ...
  00800000: 5542 4923 0100 0000 0000 0000 0000 02fe  UBI#............
  00820000: 5542 4923 0100 0000 0000 0000 0000 02fd  UBI#............
  00840000: 5542 4923 0100 0000 0000 0000 0000 02fe  UBI#............
  00860000: 5542 4923 0100 0000 0000 0000 0000 02fe  UBI#............
  00880000: 5542 4923 0100 0000 0000 0000 0000 02fe  UBI#............
  008a0000: 5542 4923 0100 0000 0000 0000 0000 02fe  UBI#............
  008c0000: 5542 4923 0100 0000 0000 0000 0000 02fe  UBI#............
  008e0000: 5542 4923 0100 0000 0000 0000 0000 02fe  UBI#............

Again, this was looking good. Next was to re-try the ubireader tool and see if it could display UBIFS volumes information. Command used:

  • $ ubireader_display_info -s 8388608 MX60LF8G18AC-deinterleaved.BIN
NAND Flash Datasheet - ID Codes
ubireader - success!

Success! Being able to display the UBIFS volumes was a great sign and we can clearly see now that there are 5 UBI partitions in the image; system0, system1, data, data_unsigned, and log.

Now, I could move on and try to mount these UBIFS volumes on my Ubuntu host for analysis.

Mounting UBIFS Volumes in Ubuntu

Note: Ubuntu 24.04.3 LTS was installed on my workstation.

  1. My first step was to load the Linux nandsim kernel module. This emulates a NAND flash chip in RAM as an MTD device (e.g. /dev/mtd0).

    Note: I obtained the id_byte values from the NAND Flash datasheet (Section 6-8).

    NAND Flash Datasheet - ID Codes
    NAND Flash Datasheet - ID Codes

    The linux command I ran was:

    Note: The datasheet shows a 5-byte ID (C2, D3, D1, 95, 5A) but nandsim only accepts the first 4 bytes, so the 5th byte (5Ah) is not passed.

    
         $ sudo modprobe nandsim \
             first_id_byte=0xC2 second_id_byte=0xD3 \
             third_id_byte=0xD1 fourth_id_byte=0x95
     
  2. Next, I prepped /dev/mtd0/ by ensuring the contents were zeroed out. Ensuring I had a clean slate, I copied the clean, de-interleaved image into it.

         $ sudo flash_erase /dev/mtd0 0 0
         Erasing 1048576 Kibyte @ 0 -- 100 % complete 
            
         $ sudo nandwrite -p /dev/mtd0 MX60LF8G18AC-deinterleaved.BIN
         Writing data to block 0 at offset 0x0
         Writing data to block 1 at offset 0x20000
         Writing data to block 2 at offset 0x40000
         ...
         Writing data to block 8188 at offset 0x3ff80000
         Writing data to block 8189 at offset 0x3ffa0000
         Writing data to block 8190 at offset 0x3ffc0000
         Writing data to block 8191 at offset 0x3ffe0000
         Written 286629 blocks containing only 0xff bytes
     
  3. Then, I loaded the ubi kernel module (the driver that knows how to read a UBI volume) and pointed it to the simulated NAND at /dev/mtd0. The -O 2048 flag tells it that the Volume ID header lives 2048 bytes into each erase block, which lines up with binwalk’s reported VID header offset of 0x800 (UBI puts the EC header in the first page and the VID header in the second). If everything is healthy, the system will recognize the image as a real UBI volume.

    
       $ sudo modprobe ubi
          
       $ sudo ubiattach -O 2048 -p /dev/mtd0 
       UBI device number 0, total 8192 LEBs (1040187392 bytes, 992.0 MiB), available 69 LEBs (8761344 bytes, 8.3 MiB), LEB size 126976 bytes (124.0 KiB)
     

    Another success! The kernel attached to the volume cleanly.

  4. From here I could verify the ubi volumes loaded into /dev/mtd0 using ubinfo. Below we can see that it successfully detected the UBIFS volumes we saw above, this was looking good.

    
       $ ubinfo -a
       UBI version:                    1
       Count of UBI devices:           1
       UBI control device major/minor: 10:268
       Present UBI devices:            ubi0
    
       ubi0
       Volumes count:                           5
       Logical eraseblock size:                 126976 bytes, 124.0 KiB
       Total amount of logical eraseblocks:     8192 (1040187392 bytes, 992.0 MiB)
       Amount of available logical eraseblocks: 69 (8761344 bytes, 8.3 MiB)
       Maximum count of volumes                 128
       Count of bad physical eraseblocks:       0
       Count of reserved physical eraseblocks:  160
       Current maximum erase counter value:     766
       Minimum input/output unit size:          2048 bytes
       Character device major/minor:            235:0
       Present volumes:                         0, 1, 2, 3, 4
    
       Volume ID:   0 (on ubi0)
       Type:        dynamic
       Alignment:   1
       Size:        1652 LEBs (209764352 bytes, 200.0 MiB)
       State:       OK
       Name:        system0
       Character device major/minor: 235:1
       -----------------------------------
       Volume ID:   1 (on ubi0)
       Type:        dynamic
       Alignment:   1
       Size:        1652 LEBs (209764352 bytes, 200.0 MiB)
       State:       OK
       Name:        system1
       Character device major/minor: 235:2
       -----------------------------------
       Volume ID:   2 (on ubi0)
       Type:        dynamic
       Alignment:   1
       Size:        3304 LEBs (419528704 bytes, 400.0 MiB)
       State:       OK
       Name:        data
       Character device major/minor: 235:3
       -----------------------------------
       Volume ID:   3 (on ubi0)
       Type:        dynamic
       Alignment:   1
       Size:        826 LEBs (104882176 bytes, 100.0 MiB)
       State:       OK
       Name:        data_unsigned
       Character device major/minor: 235:4
       -----------------------------------
       Volume ID:   4 (on ubi0)
       Type:        dynamic
       Alignment:   1
       Size:        520 LEBs (66027520 bytes, 62.9 MiB)
       State:       OK
       Name:        log
       Character device major/minor: 235:5
     
  5. I next created mount points for each of the UBIFS volumes, then mounted them.

    
       $ sudo mkdir -p /tmp/system1
       $ sudo mkdir -p /tmp/system0
       $ sudo mkdir -p /tmp/data
       $ sudo mkdir -p /tmp/data_unsigned
       $ sudo mkdir -p /tmp/log
    
       $ sudo mount -t ubifs -o ro ubi0:system0 /tmp/system0/
       $ sudo mount -t ubifs -o ro ubi0:system1 /tmp/system1/
       $ sudo mount -t ubifs -o ro ubi0:data    /tmp/data/
       $ sudo mount -t ubifs -o ro ubi0:data_unsigned /tmp/data_unsigned/
       $ sudo mount -t ubifs -o ro ubi0:log     /tmp/log/
     
  6. As a check, I wanted to make sure I saw what I’d expect so I performed a tree command on the ./system1/etc directory and when that looked promising, displayed the contents of a test file.

    
       $ tree /tmp/system1/etc
       /tmp/system1/etc
       ...
       ├── etc
       │   ├── busybox.conf
       │   ├── chatscripts
       │   │   └── dial_in.sh
       │   ├── ctp
       │   ├── dhclient.conf
       │   ├── dhclient-script
       │   ├── dtsi.conf
       │   ├── exported_gpios
       │   ├── fstab
       │   ├── group
       │   ├── hostname
       │   ├── hosts
       │   ├── inetd.conf
       │   ├── inetd.conf.d
       │   │   └── rsync
       │   ├── ipkg.conf
       │   ├── iproute2
       │   │   ├── ematch_map
       │   │   ├── group
       │   │   ├── rt_dsfield
       │   │   ├── rt_protos
       │   │   ├── rt_realms
       │   │   ├── rt_scopes
       │   │   └── rt_tables
       │   ├── issue
       │   ├── logging.conf
       │   ├── logrotate.conf
       │   ├── machine-id
       │   ├── minirc.dfl
       │   ├── modprobe.d
       │   │   └── w8887.conf
       │   ├── mtab -> /proc/self/mounts
       │   ├── network
       │   │   ├── if-down.d
       │   │   ├── if-post-up.d
       │   │   ├── if-pre-down.d
       │   │   ├── if-pre-up.d
       │   │   ├── if-up.d
       │   │   └── interfaces
       │   ├── nsswitch.conf
       │   ├── os-release -> ?
       │   ├── passwd
       │   ├── ppp -> /data/unsigned/ppp
       │   ├── ppp2
       │   │   └── ip-up
       │   ├── profile
       │   ├── profile.d
       │   │   └── systemd.sh
       │   ├── profile.environment
       │   ├── protocols
       │   ├── rc.once.d
       │   │   └── machine-id
       │   ├── reader.conf.d
       │   │   └── reader.conf
       │   ├── request-key.conf
       │   ├── resolv.conf -> /run/resolv.conf
       │   ├── rsyncd.conf
       │   ├── rsyncd.secrets
       │   ├── services
       │   ├── shadow
       │   ├── ssh
       │   │   └── ssh_config
       │   ├── sysctl.d
       │   ├── systemd
       │   │   ├── journald.conf
    
     
    • Displaying the contents (redacted) of the ./system1/etc/shadow file:
       $ sudo cat /tmp/system1/etc/shadow 
       [sudo] password for user: 
       root:$6$REDACTED:16602:0:99999:7:::
       daemon:*:16602:0:99999:7:::
       bin:*:16602:0:99999:7:::
       sys:*:16602:0:99999:7:::
       man:*:16602:0:99999:7:::
       lp:*:16602:0:99999:7:::
       mail:*:16602:0:99999:7:::
       www-data:*:16602:0:99999:7:::
    
       messagebus:*:16602:0:99999:7:::
       statd:*:16602:0:99999:7:::
       sshd:*:16602:0:99999:7:::
    
       systemd-timesync:*:16602:0:99999:7:::
       systemd-network:*:16602:0:99999:7:::
       systemd-resolve:*:16602:0:99999:7:::
       systemd-bus-proxy:*:16602:0:99999:7:::
    
       nobody:*:16602:0:99999:7:::
    
       logonly:*:16602:0:99999:7:::
       user:*:16602:0:99999:7:::
     

Conclusion

With the partitions now mounted and accessible, I had a clean view of the Tbox’s operating system, configuration files, and stored data, everything I needed to start digging into what these telematics modules really do.

Please follow along in Part 3: Data Analysis, where we dig into the data we recovered.

In case you missed it, see Part 1: Initial Examination that covers how I got the memory image off the Freightliner Tbox.


Disclaimer

This analysis is based on our professional experience and reflects our best interpretation at the time of examination.

Anyone choosing to replicate these procedures does so at their own risk.

Disassembling a vehicle (or equipment) and interacting directly with its electronic components carries an inherent risk of damage to the equipment. Fortify Labs does not guarantee that any procedure described will be free of risk, nor do we accept responsibility for any resulting damage.