Files
simtrace-analyser/README.md
T
catarrh dbaa23b3da Add Russian README (README_RUS.md) + language links
- Full Russian translation of README.md
- Cross-link English/Russian versions
- Note Windows sniff-start.bat in startup section (no longer Linux-only)
2026-09-11 08:03:34 +03:00

283 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# simtrace2-pysniff
English | [Русский](README_RUS.md)
Python-based replacement for `simtrace2-sniff` — SIM card communication sniffer
for Osmocom SIMtrace2 hardware (firmware in **trace** mode). It bundles the
**simtrace-analyser** PWA (in [`frontend/`](frontend/)) and an analysis server
that both captures APDU traffic and serves that PWA.
**Single dependency**: PyUSB (libusb wrapper). No libosmocore, no libosmosim.
![simtrace-analyser PWA](frontend.png)
## Features
**APDU decoder** (server-side, rendered by the PWA):
- Full APDU decode — CLA per ISO 7816-4 / ETSI coding (logical channel,
secure messaging, command chaining), INS names from a spec table,
SFI-aware P1/P2 for READ/UPDATE BINARY and record commands
- Status words — full ISO 7816-4 set plus UICC-specific values:
`91XX` (proactive command pending), `62F1/F2/F3`, `63F1/F2` (more data),
`9300` (SAT busy), `9850`, `9862–64`
- SIM Toolkit — SAT (GSM 11.14), CAT (TS 102 223) and USAT (TS 31.111)
proactive commands with decoded qualifiers, TERMINAL RESPONSE, ENVELOPE
(Menu Selection, Call Control, SMS-PP download…); tolerates known
non-compliant legacy-card quirks and preserves unrecognized TLVs
- SMS TPDU — SMS-DELIVER/SUBMIT, SCTS timestamps, UDH information elements
- SCP80 OTA secured packets — SPI bits (ciphering, PoR requirement/mode,
RC/CC/DS, counter), KIc/KID algorithm + key set, TAR, CNTR/PCNTR;
Response Packet (PoR) decode on GET RESPONSE; **optional client-side
decryption** of ciphered packets — paste the card's 3DES/AES key in the
detail view to reveal the real CNTR and secured application data (the
key stays in the browser, in-memory only; ciphered on-wire CNTR/PCNTR/RC
are ciphertext and labeled as such); the secured application message is
decoded as a stream of **C-APDUs** (SELECT, UPDATE BINARY, …) with
full CLA/INS/P1/P2/Lc/Le breakdown — plaintext immediately, or after
decryption for ciphered packets
- ATR parse (clock-rate conversion, Fi/Di, T-bitmask) and FCP/FCI TLV
**simtrace-analyser PWA** ([`frontend/`](frontend/)):
- Trace view with Map/List modes — proactive, TERMINAL RESPONSE, ENVELOPE
and AUTH commands get distinctive styling in map view
- Sessions with deep links (`#session=N`), PCAP import (`.pcap/.pcapng/.cap`),
search and type filtering
- Installable PWA, dark theme, English/Russian UI
## Prerequisites
- **Python 3.9+**
- **PyUSB** — `pip install pyusb`
- **libusb** — system library, present by default on Linux; on Windows the
SIMtrace2 driver must be swapped (see [USB Device Access](#usb-device-access))
- **SIMtrace2 hardware** running firmware in *trace* mode
(VID `1d50`, PID `60e3`, USB class `ff`, subclass `01`). For building and
flashing trace firmware, see the [upstream SIMtrace2 project](https://gitea.osmocom.org/sim-card/simtrace2).
No other dependencies. PCAP, GSMTAP, and hex dump output use only Python stdlib.
## Install
```sh
git clone https://github.com/anttro/simtrace2-pysniff.git
cd simtrace2-pysniff
pip install pyusb
```
Or install the package into your environment:
```sh
pip install -e .
# then run: simtrace2-pysniff [opts]
```
## Running
Two tools are provided:
### Sniffer CLI (`simtrace2-pysniff`)
Captures SIMtrace2 traffic and writes it to stdout, GSMTAP (Wireshark), or PCAP files.
### Startup script
`./sniff-start.sh` performs a pre-flight USB permission check (prints udev
install instructions if the SIMtrace2 device is not writable) and then
launches the Python module. On Windows, use `sniff-start.bat` with the same
options (no permission check needed).
```sh
./sniff-start.sh
./sniff-start.sh --format timestamp
./sniff-start.sh --gsmtap 127.0.0.1:4729
./sniff-start.sh --pcap trace.pcap --format atr-time
```
OPTIONS can also be set via environment variables:
```sh
FORMAT=timestamp GSMTAP=127.0.0.1 ./sniff-start.sh
```
### Analysis server + PWA (`simtrace2-pysniff-server`)
Stores captured APDU traffic in SQLite and serves it over HTTP, together with
the bundled **simtrace-analyser** PWA (`frontend/`) on the same origin. Three
capture modes:
```sh
# Listen for GSMTAP from simtrace2-pysniff (or original simtrace2-sniff):
simtrace2-pysniff-server --capture gsmtap
# Capture directly from SIMtrace2 hardware (no external tool needed):
simtrace2-pysniff-server --capture direct
# Browse/analyse existing captures without a capture backend:
simtrace2-pysniff-server --capture disabled
```
The server logs its capture liveness to stderr (each line timestamped
with the local time): `Capture started` on begin, a periodic
`Capture alive: session=N messages=M bytes=B dropped=D` heartbeat, and
`Capture stopped` (or `ERROR: capture thread stopped on error …` if the
capture thread died unexpectedly). A mis-framed or non-SIM GSMTAP
datagram is dropped and counted (`dropped`) rather than silently
killing the capture. The heartbeat interval defaults to 60 s and is
tunable via `--log-interval SECONDS`.
The GSMTAP listener also accepts the **sigrok-iso7816-stream** decoder
(https://github.com/anttro/sigrok_iso7816_stream) — an FX2-logic-analyzer
passive SIM sniffer that emits the same GSMTAP-SIM format on UDP 4729. Its
custom sub-types for RST/VCC line events (`0x10`/`0x11`, added for
compatibility with that project) are decoded as `RESET ASSERTED/DE-ASSERTED`
and `VCC ON/OFF` timeline markers, and a reset-assert or power-removal
correctly invalidates the file-selection tracking. GSMTAP packets carrying
the `GSMTAP_FLAG_BAD_FCS` desync flag (set by that decoder on mis-framed
exchanges) are surfaced as a flagged/desynced entry in the capture timeline,
so such artefacts are easy to spot when reviewing a capture rather than
silently altering the decode.
Server options:
```
--host ADDR HTTP bind address (default: 127.0.0.1)
--port PORT HTTP server port (default: 8081)
--db FILE SQLite database path (default: ~/.simtrace-analyser/sessions.db)
--capture MODE gsmtap | direct | disabled (default: gsmtap)
--gsmtap-port PORT UDP port for the GSMTAP listener (default: 4729)
--web-dir PATH PWA static files directory (default: <repo>/frontend)
```
Then open **http://127.0.0.1:8081/** in a browser — the PWA is served by the
server, so the UI and the API share an origin and no CORS/Private-Network-Access
setup is involved. Use `--web-dir PATH` to serve a different PWA directory
(default: `<repo>/frontend`).
### Hosted PWA (landing page)
A standalone copy of the PWA is hosted at **https://simtrace.atroshin.ru**.
It is a pure frontend: point it (Settings → Server URL) at a locally running
`simtrace2-pysniff-server`.
> **Browser restriction:** when the PWA is served from a public HTTPS host,
> reaching a local server (`http://127.0.0.1:8081`) requires two things: the
> server must send `Access-Control-Allow-Private-Network: true` (this server
> does), and the browser must be allowed to access the local network — in
> Chrome/Edge/Vivaldi: Site settings → Local network access → allow the site
> (or accept the permission prompt). Without the browser permission, the
> request to `127.0.0.1` is blocked before any preflight is sent.
### Python module (cross-platform)
```sh
python -m simtrace2_pysniff
python -m simtrace2_pysniff --format timestamp --gsmtap 127.0.0.1:4729
python -m simtrace2_pysniff --pcap trace.pcap
```
If installed via `pip install -e .`, use the console script directly:
```sh
simtrace2-pysniff --format atr-time
```
## USB Device Access
### Linux
A udev rule is required for non-root USB access to the SIMtrace2 device.
```sh
sudo cp 70-simtrace2-pysniff.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger
```
Then reconnect the SIMtrace2 USB cable. The rule uses `TAG+="uaccess"`
(systemd-logind ACL) — no group membership or world-writable permissions needed.
### Windows
Windows does not ship a libusb-compatible driver for SIMtrace2. Use
[Zadig](https://zadig.akeo.ie/) to replace the default driver:
1. Download and run **Zadig**
2. Plug in the SIMtrace2 device
3. Select it in the dropdown (VID `1D50`, PID `60E3` — "Osmocom SIMtrace 2")
4. Choose **WinUSB** (or libusbK) as the replacement driver
5. Click **Replace Driver** (one-time operation)
After that, `python -m simtrace2_pysniff` works identically to Linux.
## CLI Options
```
python -m simtrace2_pysniff [OPTIONS]
--format, -f FORMAT Output format (default: hex)
hex — plain hex dump
timestamp — TPDU lines prefixed with [HH:MM:SS.mmm]
atr-time — TPDU lines prefixed with [SSSS.mmm] from last ATR
--gsmtap HOST[:PORT] Send ATR/TPDU as GSMTAP over UDP (default port 4729)
--pcap FILE Write sniffed data to PCAP file for Wireshark
--output, -o FILE Write hex dump to file
--no-stdout Suppress hex dump to stdout
--vendor HEX USB vendor ID (default: 0x1d50)
--product HEX USB product ID (default: auto-detect)
Recovery options:
--no-reconnect Exit on USB disconnect instead of reconnecting
--reconnect-delay-min SEC Minimum reconnect delay (default: 1.0)
--reconnect-delay-max SEC Maximum reconnect delay cap (default: 30.0)
--backoff-factor N Exponential backoff multiplier (default: 1.5)
--inactivity-timeout SEC Reconnect after N seconds of silence (default: disabled)
```
## Output Formats
- **`hex`** (default): plain hex dump — `ATR: 3b 9e ...`, `TPDU: a0 a4 00 00 02 3f 00`
- **`timestamp`**: TPDU lines prefixed with local time — `[14:32:05.123] TPDU: a0 a4 00 00 02 3f 00`
- **`atr-time`**: TPDU lines prefixed with seconds since last ATR — `[0001.234] TPDU: a0 a4 00 00 02 3f 00`
Non-TPDU messages (ATR, PPS, card state changes, Fi/Di) print identically in all formats.
- **GSMTAP**: ATR and APDU messages over UDP (port 4729) to Wireshark
- **PCAP**: ATR/TPDU messages as Ethernet/IP/UDP/GSMTAP packets, openable in Wireshark
## Background / Daemon
SIGHUP is automatically ignored when stdin is not a terminal (i.e. run in
background or via a pipe). Foreground terminal sessions still respond to
SIGHUP normally.
To run persistently in the background with output to files:
```sh
nohup ./sniff-start.sh --output /tmp/sniff.log &> /tmp/sniff-err.log &
# or
FORMAT=timestamp nohup python -m simtrace2_pysniff --output /tmp/sniff.log &> /tmp/sniff-err.log &
```
## Library Usage
```python
from simtrace2_pysniff import SniffSession
session = SniffSession(inactivity_timeout=30.0)
for msg in session.iter_messages():
print(f"{msg.type}: {msg.data.hex()}")
```
## Recovery
The tool survives hardware resets, cable disconnects, and firmware hangs
by default — it reconnects with exponential backoff (1s → 30s cap).
Use `--inactivity-timeout` to also trigger reconnect on silent firmware hangs.
## Related
- **[simtrace2](https://gitea.osmocom.org/sim-card/simtrace2)** — the upstream
SIMtrace2 hardware/firmware project that this tool sniffs from.