# Frinet indexes a Frida trace so IDA can query two billion instructions

> Frinet is a rewritten reverse engineering tool that pairs a Frida tracer with a Rust indexer and query backend, so a 100 GB trace of a large program can be searched and stepped through inside IDA. It handles the scale that the legacy Python version could not, and it drops the call tree view in the process.

**synacktiv/frinet** — Frida-based tracer for easier reverse-engineering on Android, iOS, Linux, Windows and most related architectures.

- Repository: https://github.com/synacktiv/frinet
- Stars: 637 · Forks: 60
- Language: Rust
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/synacktiv-frinet

## A rewrite, not an update

The current repository is a complete rewrite of the earlier synacktiv/frinet, which was itself a fork of gaasedelen/tenet, and the old version still lives on the legacy branch. That distinction matters for anyone arriving from the earlier tool, because the features are not identical. The project was presented at SSTIC 2026, with video, slides and a paper linked from the README, and there is a blog post on the Synacktiv site describing the reverse engineering angle. The stated purpose is combining Frida with an enhanced version of Tenet so that the study of large programs, vulnerability research and root-cause analysis become easier on iOS, Android, Linux, Windows and most related architectures. The tracer itself is described as identical to the legacy version. Everything that changed is what happens after the trace exists, and that is where the interesting engineering sits.

## Four components between the tracer and the disassembler

The new architecture is built from four components, and separating them is the design. The Indexer is a Rust CLI that produces an optimized index from a trace file. The Backend is a Rust crate that implements specialized algorithms to query that optimized index. A third component is the Backend with Python bindings, a Rust crate that exposes a Python interface, and the fourth is an IDA plugin, described as a thin layer of Python code that queries the backend and integrates the data into the IDA interface. The consequence is that the heavy lifting never happens in the disassembler. The indexer does the expensive pass over the trace once, the backend answers queries against the resulting file, and the plugin is thin enough that it does not need to be fast. The workspace manifest shows how the crates are split, with crates/db for the query backend, crates/index for the indexer, crates/cli, crates/fuzz, crates/regex for search, crates/python-bindings and crates/python-bindings-stubgen, and the tracer as a separate directory at the repository root. The backend is also usable on its own as a standalone Rust library under crates/db, which is the part a team embedding this into its own tooling would reach for.

## The scale target is the reason the rewrite happened

The indexer and backend section lists three capabilities, and the first sets the bar for the whole tool. It handles efficient indexing of traces with up to 2 billion instructions, which the documentation puts at roughly 100 GB. The second is that it is independent of the trace format, with the parenthetical caveat that only the Tenet format is supported for now. The third is multi-threaded memory search with full regex support. The dependency list in the Cargo manifest explains how that is done. The indexing side pulls in fast_hilbert for a Hilbert curve spatial index, memmap2 for memory mapped file access, hashbrown and rustc-hash for hash maps, smallvec for compact vectors, and zerocopy for zero copy handling. The search side uses regex-syntax with the regex crate, itertools, and rayon for parallelism, and the trace format parser itself relies on memchr and hex. So the design is a spatial index over the trace rather than a linear scan, which is the difference between a query that returns in a moment and a query that never returns.

## Building the bindings and linking the plugin

The build is three commands, and the first one matters because the Python bindings need Python headers.

```bash
apt install python3-dev
cargo build --release
cp target/release/libfrinet_db.so frontend/frinet_db.so
```

That copies the compiled shared library into the frontend directory where the plugin expects to find it. The plugin itself is then linked into the IDA plugins directory.

```bash
ln -s $PWD/frontend ~/.idapro/plugins/frinet
```

The README notes you can symlink or copy, and the symlink is the right choice while you are iterating, because a rebuilt library is picked up without relinking. The Rust side also brings in pyo3 for the bindings, clap and indicatif for the command line, env_logger for logging, and serde with serde_json for trace metadata. The frontend side is not Rust at all. The plugin is a thin layer of Python, and the frontend views it exposes are a timeline, register and memory view, assembly timeline trails coloured red, green and blue, a memory read and write breakpoint, and jump to first, previous, next or last execution. The UI is described as the weakest part, with UI polishing listed among the missing features.

## A three step workflow from process to disassembler

The usage section is three numbered steps, and they map one to one onto the three components. First you trace a target with Frida, and the example traces /bin/ls with an address argument.

```bash
python tracer/trace.py spawn /bin/ls ls 0x4c00
```

Second you build an optimized index of the resulting trace with the frinet binary, specifying the Tenet format and the input and output files.

```bash
cargo run --bin frinet --release -- index --format tenet tracer/traces/ls_xxxx.tenet ls.db
```

Third you open the trace in IDA through the File menu, using Load File and then Open Frinet DB. The important operational detail is that the index, the ls.db file in that example, is a separate artefact from the trace, and it is what the plugin queries. That separation is what makes the scale possible, and it also means the database file has to travel with the analysis session, or be rebuilt. The trace format is the Tenet one in every command shown, which is consistent with the note that only that format is supported for now, and the tracer is a Python script living in the tracer/ directory at the repository root.

## The call tree is the feature you lose

The missing features and TODOs section is short and honest. The first item is reaching frontend feature parity with Frinet v1, and under it the call tree view is not yet implemented. The second is UI polishing. That single missing view is the one a reverse engineer will feel first, because the call tree is how you navigate an unfamiliar binary, and the trace views in the current frontend are flat by comparison, a timeline, registers and memory. The second limitation is the format constraint, and it is narrower than the first bullet in the feature list suggests. The backend is described as independent of the trace format, which is the right architecture, but the parenthetical says only the Tenet format is supported for now, so the independence is a design intention rather than a shipped capability. The third is the maturity of the supporting tooling. The project does test the indexer, with cargo test, fuzzes the register indexing target with cargo-fuzz, and benchmarks with cargo criterion against a database named by the BENCH_DB environment variable, and the fuzzing and benchmarking targets are separate crates in the workspace. That is a real engineering setup, but the project has no GitHub releases, and the last push was on 2026-06-08, so the code is moving more slowly than the paper's reception might suggest.

## Conclusion

Adopt Frinet if you are analysing large binaries with IDA and need to search a hundred gigabyte trace rather than scroll through one, since the Rust indexer and the memory-mapped query backend are the reason it exists. Skip it if you depend on the call tree view from the previous version, because the documentation lists that as a feature still to come, and skip it if your team cannot work with a plugin and a separate database file. Before your first session, decide which trace format you will produce, since only the Tenet format is supported for now, and read the feature list for the current version rather than the one the legacy branch offered.

## FAQ

### What are the main components of the Frinet architecture?

Four: an Indexer, a Rust CLI that produces an optimized index from a trace file, a Backend crate that queries that index, a Backend with Python bindings exposing a Python interface, and an IDA plugin that is a thin Python layer integrating the data into IDA.

### How do I build Frinet and install the IDA plugin?

Install python3-dev, run cargo build --release, copy target/release/libfrinet_db.so into frontend/frinet_db.so, and symlink the frontend directory into ~/.idapro/plugins/frinet. The README notes you can symlink or copy the plugin.

### How large a trace can Frinet index?

The indexer handles traces with up to 2 billion instructions, about 100 GB, and the backend provides multi-threaded memory search with full regex support. The backend is usable on its own as a standalone Rust library at crates/db.

### What does Frinet still not support compared to the previous version?

The call tree view is not yet implemented, so the frontend has not reached feature parity with Frinet v1, and UI polishing is still listed as a TODO. Only the Tenet trace format is supported for now.

## Sources

- [Issues](https://github.com/synacktiv/frinet/issues)
- [License: MIT](https://github.com/synacktiv/frinet/blob/main/LICENSE)
- [README](https://github.com/synacktiv/frinet/blob/main/README.md)
- [synacktiv/frinet on GitHub](https://github.com/synacktiv/frinet)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/synacktiv-frinet
