Skip to content

Add Windows CE and CAB extraction support - #48

Merged
nmatt0 merged 3 commits into
nmatt0:masterfrom
skmagiik:windows_ce_unpacking
Oct 3, 2026
Merged

nmatt0 merged 3 commits into
nmatt0:masterfrom
skmagiik:windows_ce_unpacking

Conversation

@skmagiik

Copy link
Copy Markdown
Contributor

No description provided.

@skmagiik

skmagiik commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

@nmatt0 updated to handle compressed lzx with a default configuration to only extract if it's the root file passed in or if you add the optional flag

@nmatt0

nmatt0 commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Thanks for the update, this is a big improvement and the LZX fix is spot on.

What I verified locally:

  • LZX now decodes real window-21 cabinets correctly. I extracted a genuine multi-frame LZX folder (from a public D-Link DWL installer) and got output byte-for-byte identical to gcab/libmspack across every member. The missing per-frame 16-bit word alignment was exactly it.
  • The undo_e8 change (translating into a separate buffer so the match window keeps the untranslated bytes) is the right fix.
  • Really appreciate the real LZX compressor added to lzxbuild.py for the tests. That closes the gap where the decoder was only ever fed stored blocks, which is why the original framing bug slipped through.
  • The nesting policy (packaging layers recurse, executables/MSI treated as leaves unless they're the root or --unpack-executables is set) behaves well on a full installer: no explosion, clear footer. Good call.
  • Identification is false-positive clean across a large firmware corpus (cab/cfbf/wince, zero FPs).

One blocker before merge: CFBF extraction can be crashed by crafted input. walk_tree (src/extract/cfbf.cpp:42) recurses over left/child/right with only a cycle guard and no depth bound. A compound file whose directory is laid out as a long linear left-sibling chain drives the recursion roughly N deep (N capped at 262144 entries). I built a ~15 MB CFBF that does this and moria -e segfaults:

moria -e cfbf_poc.bin   ->  Segmentation fault (core dumped)
# ASan: stack-overflow in walk_tree src/extract/cfbf.cpp:42

It's a DoS rather than memory corruption, and the default nesting policy means a nested CFBF inside firmware isn't auto-extracted, but it triggers when moria is pointed at a malicious .msi directly or run with --unpack-executables. Since this parser's whole job is untrusted input, I'd rather not land a known crash on master. The fix is small: bound the walk_tree depth or convert it to an iterative walk with an explicit stack. I have the POC generator and can share it for a regression test.

Minor: src/extract/cab.cpp:218 has a dead mapped variable (one -Wall warning).

Everything else looks ready to merge once walk_tree is bounded. Thanks again, genuinely strong work.

walk_tree recursed over the directory's sibling tree and storage
children with only a cycle guard. A compound file's directory is not
required to be balanced, so a crafted file can lay its entries out as
one long linear left/right chain (entry count bounded only by the
262144 cap). The recursion then overflowed the call stack: moria -e
segfaulted on a ~15 MB MSI built this way.

Rewrite the walk with an explicit heap work stack so any depth up to
the entry cap is safe. Behavior is otherwise unchanged (same paths
recorded, same cycle guard).

tests/cfbfbuild.build_deep_chain builds such a file (120k-entry chain
whose deepest entry carries a payload) and test_cfbf.deep_directory_chain
asserts extraction completes and the deepest stream round-trips
byte-for-byte. The chain length is sized to exhaust a default 8 MiB
stack on the old code, so the test fails if the recursion returns.

Also drop an unused variable in extract_cab (-Wall).
@nmatt0
nmatt0 merged commit 3907ac0 into nmatt0:master Oct 3, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants