Rooting a VMC2040 security camera part 2: Extract the firmware

Posted by Marcus Folkesson on Thursday, May 7, 2026

Rooting a VMC2040 security camera part 2: Extract the firmware

Brief

As there were no exposed vulnerabilities via UART (no TX, only RX) or network (no open ports that could be exploited), I decided to extract the firmware from the SPINAND flash.

This part of the series is about the process of extracting the firmware and analyzing it.

The other parts of the series are:

  • Part1: Basic examination
  • Part2: Extract the firmware
  • Part3: Analyse boot sequence
  • Part4: Deeper analysis
  • Part5: What didn't work
  • Part6: What did work
  • Part7: Conclusion and summary

Extract the firmware

I have a XGECU-T48 programmer for such tasks. it supports a wide range of flash chips, including SPI NOR and SPI NAND.

/media/arlo-11.jpg

I usually use minipro [1] with XGECU-48 as that is what's available for Linux. I realize that this is the first time I use it with a NAND flash and, unfortunately, specifically NAND flashes is not supported :-( [2]:

/media/arlo-12.jpg

Anyway. I installed the XGECU software on my daughters PC with Windows (nope, I do not own a single Windows machine) for this purpose.

The package is a WSON8, so it's a pretty small (6x8mm, 1.27mm pitch) one. I have no clip for WSON8, so I soldered some wires to the flash chip and connected it to the programmer.

/media/arlo-3.jpg

Honestly, I wasn't too optimistic about this, it just looks terrible. My only hope was that If I could go down in clockspeed, I might be able to read the flash. But nope.

/media/arlo-2.jpg

Instead I applied some low melting point soldering alloy to the legs of the flash to easier remove it. Then I used a hot air gun to removed the IC.

/media/arlo-4.jpg

Removed. The damaged PCB is not because of the desoldering, I was a bit harshly when I removed the shielding.

/media/arlo-8.jpg

Resolder the IC on an adapter card. I found the Miniware MHP30 hot plate fantastic for this task.

/media/arlo-10.jpg

And read out the firmware:

/media/arlo-9.jpg

Extract the data

binwalk [3] is a fantastic tool to analyze and extract firmware images out from a flash dump. I've used it many times before and it has never failed me, however, this time I couldn't get any useful data out of it. It found all signatures for the images so the data couldn't be encrypted, but it couldn't extract anything and complained about invalid data. Also, the signatures weren't on the expected offsets (Hint #1)

I managed to successfully extract and write back modified content for the U-Boot environment by manually use dd. (Hint #2) But more about this in the next part.

When I started to analyze the hexdump more carefully, I soon discovered that there were repeating chunks of size 0x40 with only 0xff (Hint #3). Wait... I checked the size of the dump and it was 135168 bytes (Hint #4)...

I felt a little stupid. I should have realized this before; The dump contained the OOB data. Of course binwalk failed to extract anything. For those unfamiliar with NAND flash, please read this post [4] about the topic.

The OOB also explains:

  • Why everything weren't on the expected offsets.
  • Why I could extract and modify the U-Boot environment - as it only occupy 2048 bytes (one page), I didn't cross any OOB boundary.

So I wrote a small Python script to remove the OOB data:

 1#!/usr/bin/env python3
 2"""Strip 64-byte OOB from each 2048+64 byte NAND page.
 3Usage: remove_oob.py <input> [output]"""
 4
 5import sys
 6from pathlib import Path
 7
 8PAGE, OOB = 2048, 64
 9
10inp = Path(sys.argv[1])
11out = Path(sys.argv[2]) if len(sys.argv) > 2 else inp.with_stem(inp.stem + "_no_oob")
12
13with inp.open("rb") as f, out.open("wb") as g:
14    while chunk := f.read(PAGE + OOB):
15        g.write(chunk[:PAGE])

Resulting in that binwalk were much happier:

 1$ binwalk -e ./nand_no_oob.bin
 2
 3---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4DECIMAL                            HEXADECIMAL                        DESCRIPTION
 5---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 62111108                            0x203684                           CRC32 polynomial table, little endian
 72242180                            0x223684                           CRC32 polynomial table, little endian
 82373252                            0x243684                           CRC32 polynomial table, little endian
 92883648                            0x2C0040                           XZ compressed data, total size: 177512 bytes
103670080                            0x380040                           XZ compressed data, total size: 177512 bytes
117864320                            0x780000                           uImage firmware image, header size: 64 bytes, data size: 1736476 bytes, compression: lzma, CPU: ARM, OS: Linux, image type: OS Kernel Image, load address: 0x20008000,
12                                                                      entry point: 0x20008000, creation time: 2025-08-11 19:03:16, image name: ""
1313893632                           0xD40000                           uImage firmware image, header size: 64 bytes, data size: 1736332 bytes, compression: lzma, CPU: ARM, OS: Linux, image type: OS Kernel Image, load address: 0x20008000,
14                                                                      entry point: 0x20008000, creation time: 2023-09-26 05:37:58, image name: ""
1519922944                           0x1300000                          SquashFS file system, little endian, version: 4.0, compression: xz, inode count: 998, block size: 131072, image size: 16209796 bytes, created: 2025-08-11 19:05:31
1651380224                           0x3100000                          SquashFS file system, little endian, version: 4.0, compression: xz, inode count: 994, block size: 131072, image size: 16162340 bytes, created: 2023-09-26 05:40:12
1782837504                           0x4F00000                          UBI image, version: 1, image size: 4194304 bytes
18---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
19[+] Extraction of xz data at offset 0x2C0040 completed successfully
20[+] Extraction of xz data at offset 0x380040 completed successfully
21[+] Extraction of uimage data at offset 0x780000 completed successfully
22[+] Extraction of uimage data at offset 0xD40000 completed successfully
23[+] Extraction of squashfs data at offset 0x1300000 completed successfully
24[+] Extraction of squashfs data at offset 0x3100000 completed successfully
25[+] Extraction of ubi data at offset 0x4F00000 completed successfully
26---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
27
28Analyzed 1 file for 85 file signatures (187 magic patterns) in 1.0 seconds

Summary

We now have the firmware dumped and the next step (Part3) is to analyse it.