Metadata-Version: 2.4
Name: tffsmount
Version: 0.1.0
Summary: Read-only mounter for tffs filesystem
Keywords: tffs,filesystem,fuse,forensics,fscrypt,kaitai,automotive
Author-Email: Francis Hoogendijk <f.hoogendijk@nfi.nl>
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: Legal Industry
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Filesystems
Classifier: Topic :: System :: Recovery Tools
Project-URL: Repository, https://github.com/NetherlandsForensicInstitute/tffsmount
Requires-Python: >=3.9.2
Requires-Dist: fusepy>=3.0.1
Requires-Dist: kaitaistruct<0.12,>=0.11
Requires-Dist: crcengine>=0.4
Requires-Dist: cryptography>=50.0
Provides-Extra: test
Requires-Dist: pytest>=8.4; extra == "test"
Description-Content-Type: text/markdown

# 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](https://github.com/NetherlandsForensicInstitute/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](https://doi.org/10.1016/j.fsidi.2023.301500) published at DFRWS 2023 and their code can be found [here](https://github.com/NFSDigital/hkmc_dvrs_filesystem_parser).

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](https://kaitai.io/), 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:
```shell
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:
```shell
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
```shell
~ 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:
```shell
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:
```shell
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](https://pdm-project.org), which creates the virtual environment and installs the versions pinned in `pdm.lock`:
```shell
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:
```shell
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](https://kaitai.io/) 0.11, the version matching the
`kaitaistruct` runtime:
```shell
cd tffsmount && ksc --target python --outdir . parser.ksy
```
