TFFS Filesystem Mounter
Project Description
This project contains code to parse and mount (read only) the TFFS filesystem found in certain Automotive systems. Earlier we created a similar tool: qnxmount for other filesystems found in Automotive applications running the QNX OS.
Most of the initial research and reverse engineering of TFFS was done by the Digital Analysis Division of the National Forensic Service (NFS) of the Republic of Korea. This research is documented in their paper published at DFRWS 2023 and their code can be found here.
The information in the paper was augmented with some additional reverse engineering efforts of our own based on executable files found in Automotive systems.
All of this filesystem structure information combined was put in the parser.ksy file, which is written in the declarative binary structure language: kaitai, enabling the automatic generation of parser code.
The filesystem can then be mounted using FUSE with some python glue code between the FUSE python bindings and the generated parser.
This project is only tested on Linux machines.
Getting started
tffsmount needs Python 3.9.2 or later and FUSE. The fusepy bindings load
libfuse 2; libfuse 3 alone is not enough:
sudo apt install libfuse2t64 # libfuse2 on releases before Ubuntu 24.04
libfuse 2 also needs a fusermount on your PATH. The fuse3 package provides
one; older releases ship it in the fuse package.
Install tffsmount from PyPI in a virtual environment:
python3 -m venv venv
source ./venv/bin/activate
pip install tffsmount
To install from source instead, run pip install . in a clone of this repository.
Usage
~ tffsmount -h
usage: tffsmount [-h] [-o OFFSET] [-k KEYS] image mount_point
positional arguments:
image Path to image containing tffs file system
mount_point Path to mount point
options:
-h, --help show this help message and exit
-o, --offset OFFSET Offset of tffs partition in image
-k, --keys KEYS Path to a JSON file holding one object that maps each
fscrypt key descriptor (8 bytes) to its master key (up
to 64 bytes), both as hex strings, e.g.
{"a1b2c3d4e5f60708": "00112233..."}.
The offset can be given in decimal, octal, binary or hexadecimal and does not need to be page-aligned. For example, to mount a tffs filesystem at offset 0x1000 in an image:
tffsmount -o 0x1000 /image /mountpoint
-o 4096 gives the same result.
tffsmount logs Mounting image /image on mount point /mountpoint and then stays
in the foreground while the filesystem is mounted. Browse the mount point from
another terminal or a file browser, and unmount it with:
fusermount -u /mountpoint
tffsmount then logs that the image was unmounted and exits.
Contributing and Testing
If you want to develop the tool and run tests, first fork the repository. Contributions can be submitted as a merge request.
To get started clone the forked repository and install it with the test dependencies. The project is managed with pdm, which creates the virtual environment and installs the versions pinned in pdm.lock:
pdm install -G test
Without pdm, pip install .[test] in a virtual environment of your own works as well.
The folder tests contains functional tests to test the parser against known input data. To run these tests you need a file system image and an accompanying tar archive. The tests run are functional tests that check whether the parsed data from the test image is equal to the data stored in the archive. Default test_images are located in the folders test_data. If you want to test your own image replace the files test_image.bin and test_image.tar.gz with your own.
A test image can be created by running the script make_test_fs.sh inside an environment where you have access to mktffs and the Tuxera kernel module (tffs.ko) loaded.
The script will create the desired files and directories which you will then need to tar as well as use dd to create a physical image.
To run the tests in this repo navigate to the main directory of the repo and run:
pdm run pytest
or plain pytest inside the virtual environment.
Regenerating the parser
tffsmount/parser.py is generated from tffsmount/parser.ksy and must not be
edited by hand. After changing the .ksy, rebuild it with
kaitai-struct-compiler 0.11, the version matching the
kaitaistruct runtime:
cd tffsmount && ksc --target python --outdir . parser.ksy
Metadata
Release files for tffsmount 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tffsmount-0.1.0.tar.gz | 206.6 kB | Without provenance | Details for tffsmount-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tffsmount-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for tffsmount-0.1.0-py3-none-any.whl |
Total release size: 248.6 kB
Release files / tffsmount-0.1.0.tar.gz
| Download URL | tffsmount-0.1.0.tar.gz |
|---|---|
| Size | 206.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6c18fb3fa1049267c0e624a3c702cb231661d755ffd8473bdc4506401affa72f
|
|
BLAKE2b-256 checksum How to use checksums |
c791cb3fdf742f0104b3c6b2bee9441be931330ad29e3f2b89d5f6cfe247c349
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
pdm/2.29.0 CPython/3.13.7 Linux/6.17.0-41-generic
|
Release files / tffsmount-0.1.0-py3-none-any.whl
| Download URL | tffsmount-0.1.0-py3-none-any.whl |
|---|---|
| Size | 42.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c7524d2055c956410f925ceed379988c419bef97174083a4cbe61a31eb5f382
|
|
BLAKE2b-256 checksum How to use checksums |
ee645f8cd4ce8410b17f3301368b653e9aedfb460a183f787bf93c6498dd4534
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
pdm/2.29.0 CPython/3.13.7 Linux/6.17.0-41-generic
|
Security for tffsmount 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.