Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a7768e6a9 | ||
|
|
7801c62ca3 | ||
|
|
f18a11edaf | ||
|
|
6fbe57052f | ||
|
|
9872913965 | ||
|
|
a863f66860 | ||
|
|
6ed3a7b7d6 | ||
|
|
903ead9791 | ||
|
|
c810ff50cf |
No files matched your search
@@ -13,7 +13,7 @@ The source archive is the same tree a clone would have: unzip it and run
|
||||
`./start.sh` (Linux/macOS) or `start.bat` (Windows). Direct SIMtrace2 capture
|
||||
on Linux additionally needs the attached `70-simtrace2-pysniff.rules` udev rule.
|
||||
|
||||
**Runtime zip (Windows-friendly, no installer)** — `simtrace-analyser-*.zip`
|
||||
**Runtime zip (no installer)** — `simtrace-analyser-*.zip`
|
||||
is the runtime tree only (packages, PWA, launchers, docs — no tests, no git):
|
||||
extract it anywhere and run `start.bat` (Windows) or `./start.sh`
|
||||
(Linux/macOS). Python 3 has to be on `PATH`; `pip install pyusb` is only
|
||||
|
||||
@@ -9,105 +9,42 @@ also bundles **simtrace2-pysniff**, a Python replacement for
|
||||
`simtrace2-sniff` that captures from Osmocom SIMtrace2 hardware and can feed
|
||||
GSMTAP into this analyser.
|
||||
|
||||

|
||||
📢 Project news and updates: [atroshin.ru](https://atroshin.ru) | [Telegram channel](https://t.me/youeyeseesee)
|
||||
|
||||
## Components
|
||||
|
||||
- **Analysis server + PWA** (`simtrace-analyser-server`) — stores captured
|
||||
traffic in SQLite, decodes it, and serves the PWA ([`frontend/`](frontend/))
|
||||
plus the HTTP API on a single origin. Three capture modes: a GSMTAP
|
||||
listener, direct SIMtrace2 hardware capture, or disabled (browse existing
|
||||
captures only).
|
||||
- **Capture utility** (`simtrace2-pysniff`) — captures SIMtrace2 hardware
|
||||
traffic and writes it to stdout, GSMTAP (Wireshark), or PCAP files. It is
|
||||
one GSMTAP source of several that the analyser accepts (see also
|
||||
[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)).
|
||||
- **PWA** ([`frontend/`](frontend/)) — trace browser with decoded APDU,
|
||||
SIM Toolkit, SMS and SCP80 OTA detail; sessions, PCAP and COMPRION trace
|
||||
import, EN/RU UI.
|
||||
|
||||
## Features
|
||||
|
||||
**APDU decoder** (server-side, rendered by the PWA):
|
||||
|
||||
- Full APDU decode — CLA per ISO 7816-4 / ETSI coding with the **logical
|
||||
channel 0-19** (standard channels from b2-b1, the extended channels 4-19
|
||||
from b4-b1 per TS 102 221 §10.3), secure messaging and command chaining,
|
||||
INS names from a spec table, SFI-aware P1/P2 for READ/UPDATE BINARY and
|
||||
record commands; MANAGE CHANNEL replies show the channel the card
|
||||
assigned
|
||||
- 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
|
||||
- TERMINAL CAPABILITY (TS 102 221 §11.1.19) — terminal power supply
|
||||
(voltage class, maximum current, clock), extended logical channels,
|
||||
additional interfaces (UICC-CLF) and eUICC device capabilities
|
||||
(SGP.22/SGP.32)
|
||||
- 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, truncated-ATR safe)
|
||||
and FCP/FCI TLV; the historical bytes are decoded as the UICC's
|
||||
COMPACT-TLV objects (TS 102 221 §6.3.1) — card service data, the **card
|
||||
capabilities** (ISO 7816-4 §8.1.1.2.7 Table 88: the assignment methods
|
||||
and the announced maximum number of logical channels, `8 or more` for the
|
||||
extended-capable cards) and the trailing status indicator (LCS/SW)
|
||||
|
||||
**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`),
|
||||
COMPRION trace import (the Device Manager *ISO Protocol Layer* text export),
|
||||
search and a **multi-select command filter** — pick any number of commands
|
||||
and/or the conversation presets (*Proactive sessions*: FETCH, TERMINAL
|
||||
PROFILE and every command answered with SW 91xx; *File operations*: SELECT,
|
||||
READ/UPDATE BINARY and READ/UPDATE RECORD, with the GET RESPONSE carrying a
|
||||
selected command's data)
|
||||
- Installable PWA, dark theme, English/Russian UI
|
||||

|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Python 3.9+**
|
||||
- **PyUSB** — `pip install pyusb` (needed only for capture from SIMtrace2
|
||||
hardware; GSMTAP/UDP capture and PCAP import work without it)
|
||||
**Required**
|
||||
|
||||
- **Python 3.9+** — GSMTAP capture, PCAP import and browsing use only the
|
||||
standard library.
|
||||
|
||||
**Only for capturing from Osmocom SIMtrace2 hardware** (`--capture direct`, and
|
||||
the bundled `simtrace2-pysniff` capture utility):
|
||||
|
||||
- **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 (only for direct
|
||||
capture; VID `1d50`, PID `60e3`, USB class `ff`, subclass `01`). For
|
||||
building and flashing trace firmware, see the
|
||||
- **SIMtrace2 hardware** running firmware in *trace* mode (VID `1d50`, PID
|
||||
`60e3`, USB class `ff`, subclass `01`); building and flashing trace firmware
|
||||
is described in the
|
||||
[upstream SIMtrace2 project](https://gitea.osmocom.org/sim-card/simtrace2).
|
||||
|
||||
No other dependencies. PCAP, GSMTAP, and hex dump output use only Python stdlib.
|
||||
The analyser needs none of this for `--capture gsmtap` (the GSMTAP source may
|
||||
even run on another machine), `--capture disabled`, or PCAP imports.
|
||||
|
||||
## Install
|
||||
## Quick start
|
||||
|
||||
There are two ways to get the analyser: install a release artifact (no git
|
||||
history), or clone the repository for development. Both bundle the same PWA.
|
||||
Three ways to get it running; all of them serve the same web UI at
|
||||
http://127.0.0.1:8081/.
|
||||
|
||||
### From a release (no git history)
|
||||
### 1. Wheel (pip)
|
||||
|
||||
Everything is on the
|
||||
[latest release](https://github.com/anttro/simtrace-analyser/releases/latest).
|
||||
|
||||
**Wheel** (the PWA is inside the package):
|
||||
The wheel includes the UI, so the server serves it by itself:
|
||||
|
||||
```sh
|
||||
pip install ./simtrace_analyser-2.7.13-py3-none-any.whl
|
||||
|
||||
# then run (the UI is served at http://127.0.0.1:8081/):
|
||||
simtrace-analyser-server --capture gsmtap
|
||||
```
|
||||
|
||||
@@ -115,31 +52,43 @@ If your system Python is externally managed (PEP 668 — common on Arch and
|
||||
Fedora), install into a virtual environment first:
|
||||
`python3 -m venv .venv && . .venv/bin/activate`.
|
||||
|
||||
`pip` can also fetch the wheel straight from the release page (use the version
|
||||
shown there):
|
||||
Every artifact is on the
|
||||
[latest release](https://github.com/anttro/simtrace-analyser/releases/latest).
|
||||
`pip` can fetch the wheel directly (use the version shown there), or the GitHub
|
||||
CLI can pick the latest one:
|
||||
|
||||
```sh
|
||||
pip install https://github.com/anttro/simtrace-analyser/releases/download/v2.7.13/simtrace_analyser-2.7.13-py3-none-any.whl
|
||||
```
|
||||
|
||||
With the GitHub CLI, download the latest wheel without knowing the version:
|
||||
|
||||
```sh
|
||||
# or:
|
||||
gh release download --pattern '*.whl'
|
||||
pip install ./simtrace_analyser-*.whl
|
||||
```
|
||||
|
||||
**Source archive** — the *Source code (zip / tar.gz)* assets are the full tree
|
||||
without the git history: unzip, `cd` into it and use the launchers below
|
||||
(`./start.sh` on Linux/macOS, `start.bat` on Windows).
|
||||
### 2. Zip (no installer)
|
||||
|
||||
**Zip (Windows-friendly, no installer)** — `simtrace-analyser-2.7.13.zip` is
|
||||
the runtime tree only (packages, PWA, launchers, docs; no tests, no git):
|
||||
download it, extract it anywhere and run `start.bat` (Windows) or
|
||||
`./start.sh` (Linux/macOS). Python 3 has to be on `PATH`; `pip install pyusb`
|
||||
is only needed for direct SIMtrace2 capture.
|
||||
Download `simtrace-analyser-2.7.13.zip` from the release page and extract it
|
||||
anywhere: it is the runtime tree (the Python packages, the web UI, the launchers
|
||||
and the docs — no tests, no git). The archive works on any OS; then run:
|
||||
|
||||
### From a git clone (development)
|
||||
Windows:
|
||||
|
||||
```bat
|
||||
start.bat
|
||||
```
|
||||
|
||||
Linux/macOS:
|
||||
|
||||
```sh
|
||||
./start.sh
|
||||
```
|
||||
|
||||
Python 3 has to be on `PATH`; `pip install pyusb` is only needed for direct
|
||||
SIMtrace2 capture. The launchers accept the server's options
|
||||
(`start.bat --capture direct`, `./start.sh --capture direct --port 8080`).
|
||||
(The release's *Source code (zip / tar.gz)* archives are the full tree
|
||||
including tests; they work like a clone below.)
|
||||
|
||||
### 3. Git clone (development)
|
||||
|
||||
```sh
|
||||
git clone https://github.com/anttro/simtrace-analyser.git
|
||||
@@ -147,31 +96,39 @@ cd simtrace-analyser
|
||||
./start.sh # Linux/macOS; on Windows: start.bat
|
||||
```
|
||||
|
||||
The launchers add the checkout to `PYTHONPATH` and run
|
||||
`python -m simtrace_analyser`, so no install step is needed for browsing and
|
||||
GSMTAP capture; they accept the server's options (`./start.sh --capture direct
|
||||
--port 8080`). Direct hardware capture needs **PyUSB** (`pip install pyusb`).
|
||||
|
||||
To get the console scripts (`simtrace-analyser-server`, `simtrace2-pysniff`)
|
||||
install the package instead:
|
||||
The launchers put the checkout on `PYTHONPATH` and run
|
||||
`python -m simtrace_analyser`, so nothing has to be installed for browsing and
|
||||
GSMTAP capture; their options are the server's
|
||||
(`./start.sh --capture direct --port 8080`). Direct hardware capture needs
|
||||
**PyUSB** (`pip install pyusb`). To get the console scripts
|
||||
(`simtrace-analyser-server`, `simtrace2-pysniff`) install the package:
|
||||
|
||||
```sh
|
||||
pip install -e .
|
||||
simtrace-analyser-server --capture gsmtap
|
||||
```
|
||||
|
||||
On Windows the `.bat` launchers run the `python` command, so Python 3 has to be
|
||||
on `PATH` (check with `python --version`); direct USB capture additionally
|
||||
needs the driver swap described in [USB Device Access](#usb-device-access).
|
||||
### First run
|
||||
|
||||
## Running
|
||||
Open **http://127.0.0.1:8081/** in a browser. `Ctrl+C` stops the server.
|
||||
|
||||
### Analysis server + PWA (`simtrace-analyser-server`)
|
||||
- `--capture gsmtap` (default) — listen for GSMTAP-SIM on UDP 4729, e.g. from
|
||||
`simtrace2-pysniff` or `sigrok_iso7816_stream`;
|
||||
- `--capture direct` — read SIMtrace2 hardware directly (needs PyUSB; Windows
|
||||
also needs the driver swap, see [USB Device Access](#usb-device-access));
|
||||
- `--capture disabled` — only browse stored captures.
|
||||
|
||||
The full runtime guide (server options, the UI views, the capture utility) is
|
||||
in [Usage](#usage) below.
|
||||
|
||||
## Usage
|
||||
|
||||
### Analysis server + UI (`simtrace-analyser-server`)
|
||||
|
||||
Stores captured APDU traffic in SQLite and serves it over HTTP, together with
|
||||
the bundled **SIMtrace Analyser** PWA (`frontend/` in a source checkout,
|
||||
bundled into the package on install) on the same origin. Three
|
||||
capture modes:
|
||||
the bundled **SIMtrace Analyser** frontend (`frontend/` in a source checkout,
|
||||
bundled into the package on install) on the same origin. Three capture
|
||||
modes:
|
||||
|
||||
```sh
|
||||
# Listen for GSMTAP from simtrace2-pysniff (or original simtrace2-sniff):
|
||||
@@ -184,6 +141,27 @@ simtrace-analyser-server --capture direct
|
||||
simtrace-analyser-server --capture disabled
|
||||
```
|
||||
|
||||
From a source checkout or the runtime zip, the launchers run the same server
|
||||
with the same options.
|
||||
|
||||
Linux/macOS:
|
||||
|
||||
```sh
|
||||
./start.sh --capture gsmtap
|
||||
./start.sh --capture direct
|
||||
./start.sh --capture disabled
|
||||
```
|
||||
|
||||
Windows:
|
||||
|
||||
```bat
|
||||
start.bat --capture gsmtap
|
||||
start.bat --capture direct
|
||||
start.bat --capture disabled
|
||||
```
|
||||
|
||||
Options pass through unchanged (`./start.sh --capture direct --port 8080`).
|
||||
|
||||
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
|
||||
@@ -221,7 +199,7 @@ The **Import COMPRION trace** button accepts the tab-separated **ISO Protocol
|
||||
Layer** export of COMPRION's Device Manager — the byte-accurate protocol view
|
||||
(ATR, PPS, APDUs with their return codes). The *ISO Application Layer* export
|
||||
carries no raw response bytes and is not needed; selecting it answers with a
|
||||
pointer to the Protocol Layer file (the same check runs in the PWA before the
|
||||
pointer to the Protocol Layer file (the same check runs in the UI before the
|
||||
upload and on the server for API callers).
|
||||
|
||||
Exchanges are re-encoded into the same wire-shaped TPDUs a GSMTAP capture
|
||||
@@ -340,28 +318,32 @@ Server options:
|
||||
--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: the PWA bundled in
|
||||
the installed package, or <repo>/frontend from source)
|
||||
--gsmtap-bind ADDR UDP bind address for the GSMTAP listener (default: 127.0.0.1;
|
||||
use 0.0.0.0 to receive from a Docker bridge or another host)
|
||||
--web-dir PATH static files directory for the web UI (default: the
|
||||
frontend bundled in the installed package, or
|
||||
<repo>/frontend from source)
|
||||
```
|
||||
|
||||
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: the bundled PWA, or `<repo>/frontend` in a source checkout).
|
||||
Then open **http://127.0.0.1:8081/** in a browser. Use `--web-dir PATH` to
|
||||
serve a different UI directory (default: the bundled frontend, or
|
||||
`<repo>/frontend` in a source checkout).
|
||||
|
||||
### Hosted PWA (landing page)
|
||||
### Hosted UI (landing page)
|
||||
|
||||
A standalone copy of the PWA is hosted at **https://simtrace.atroshin.ru**.
|
||||
A standalone copy of the UI is hosted at **https://simtrace.atroshin.ru**.
|
||||
It is a pure frontend: point it (Settings → Server URL) at a locally running
|
||||
`simtrace-analyser-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.
|
||||
> **Browser restriction:** this is the one setup where the UI and the API have
|
||||
> different origins, so the browser applies CORS and Private Network Access
|
||||
> rules. 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.
|
||||
|
||||
### Capture utility (`simtrace2-pysniff`)
|
||||
|
||||
@@ -401,6 +383,71 @@ If installed via `pip install -e .`, use the console script directly:
|
||||
simtrace2-pysniff --format atr-time
|
||||
```
|
||||
|
||||
### Utility 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 utility 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.
|
||||
|
||||
## USB Device Access
|
||||
|
||||
Required for capture from SIMtrace2 hardware (the utility and the server's
|
||||
@@ -438,70 +485,73 @@ through: `start.bat --capture direct` starts the analyser server and
|
||||
Python 3 must be on `PATH` (verify with `python --version` in a new command
|
||||
prompt).
|
||||
|
||||
## Utility CLI Options
|
||||
## Components
|
||||
|
||||
```
|
||||
python -m simtrace2_pysniff [OPTIONS]
|
||||
- **Analysis server + UI** (`simtrace-analyser-server`) — stores captured
|
||||
traffic in SQLite, decodes it, and serves the UI ([`frontend/`](frontend/))
|
||||
plus the HTTP API on a single origin. Three capture modes: a GSMTAP
|
||||
listener, direct SIMtrace2 hardware capture, or disabled (browse existing
|
||||
captures only).
|
||||
- **Capture utility** (`simtrace2-pysniff`) — captures SIMtrace2 hardware
|
||||
traffic and writes it to stdout, GSMTAP (Wireshark), or PCAP files. It is
|
||||
one GSMTAP source of several that the analyser accepts (see also
|
||||
[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)).
|
||||
- **UI** ([`frontend/`](frontend/)) — trace browser with decoded APDU,
|
||||
SIM Toolkit, SMS and SCP80 OTA detail; sessions, PCAP and COMPRION trace
|
||||
import, EN/RU UI.
|
||||
|
||||
--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)
|
||||
## Features
|
||||
|
||||
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)
|
||||
```
|
||||
**APDU decoder** (server-side, rendered by the UI):
|
||||
|
||||
## Output Formats
|
||||
- Full APDU decode — CLA per ISO 7816-4 / ETSI coding with the **logical
|
||||
channel 0-19** (standard channels from b2-b1, the extended channels 4-19
|
||||
from b4-b1 per TS 102 221 §10.3), secure messaging and command chaining,
|
||||
INS names from a spec table, SFI-aware P1/P2 for READ/UPDATE BINARY and
|
||||
record commands; MANAGE CHANNEL replies show the channel the card
|
||||
assigned
|
||||
- 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
|
||||
- TERMINAL CAPABILITY (TS 102 221 §11.1.19) — terminal power supply
|
||||
(voltage class, maximum current, clock), extended logical channels,
|
||||
additional interfaces (UICC-CLF) and eUICC device capabilities
|
||||
(SGP.22/SGP.32)
|
||||
- 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, truncated-ATR safe)
|
||||
and FCP/FCI TLV; the historical bytes are decoded as the UICC's
|
||||
COMPACT-TLV objects (TS 102 221 §6.3.1) — card service data, the **card
|
||||
capabilities** (ISO 7816-4 §8.1.1.2.7 Table 88: the assignment methods
|
||||
and the announced maximum number of logical channels, `8 or more` for the
|
||||
extended-capable cards) and the trailing status indicator (LCS/SW)
|
||||
|
||||
- **`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`
|
||||
**SIMtrace Analyser UI** ([`frontend/`](frontend/)):
|
||||
|
||||
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 utility 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.
|
||||
- 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`),
|
||||
COMPRION trace import (the Device Manager *ISO Protocol Layer* text export),
|
||||
search and a **multi-select command filter** — pick any number of commands
|
||||
and/or the conversation presets (*Proactive sessions*: FETCH, TERMINAL
|
||||
PROFILE and every command answered with SW 91xx; *File operations*: SELECT,
|
||||
READ/UPDATE BINARY and READ/UPDATE RECORD, with the GET RESPONSE carrying a
|
||||
selected command's data)
|
||||
- Installable **PWA** (progressive web app: installs to the desktop or home
|
||||
screen and works offline), dark theme, English/Russian UI
|
||||
|
||||
## Related
|
||||
|
||||
@@ -513,7 +563,7 @@ Use `--inactivity-timeout` to also trigger reconnect on silent firmware hangs.
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](LICENSE). The decoders and the PWA's DES/3DES
|
||||
MIT — see [LICENSE](LICENSE). The decoders and the UI's DES/3DES
|
||||
implementation are original, written from the ISO 7816, ETSI and 3GPP
|
||||
specifications; no third-party code is bundled. PyUSB (BSD-3-Clause) is a
|
||||
runtime dependency for direct hardware capture.
|
||||
+245
-199
@@ -9,111 +9,43 @@ SIM/UICC из UDP-потока GSMTAP (или импортирует файлы
|
||||
на Python, которая захватывает трафик с оборудования Osmocom SIMtrace2
|
||||
и может передавать GSMTAP этому анализатору.
|
||||
|
||||

|
||||
📢 Новости и обновления проекта: [atroshin.ru](https://atroshin.ru) | [Telegram-канал](https://t.me/youeyeseesee)
|
||||
|
||||
## Компоненты
|
||||
|
||||
- **Анализирующий сервер + PWA** (`simtrace-analyser-server`) — сохраняет
|
||||
захваченный трафик в SQLite, декодирует его и отдаёт PWA
|
||||
([`frontend/`](frontend/)) вместе с HTTP API на одном origin. Три режима
|
||||
захвата: GSMTAP-листенер, захват напрямую с оборудования SIMtrace2 или
|
||||
отключённый захват (только просмотр существующих записей).
|
||||
- **Утилита захвата** (`simtrace2-pysniff`) — захватывает трафик
|
||||
оборудования SIMtrace2 и выводит его в stdout, GSMTAP (Wireshark) или
|
||||
PCAP-файлы. Это один из нескольких источников GSMTAP, которые принимает
|
||||
анализатор (см. также
|
||||
[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)).
|
||||
- **PWA** ([`frontend/`](frontend/)) — окно трассировки с декодированными
|
||||
APDU, SIM Toolkit, SMS и SCP80 OTA; сессии, импорт PCAP и трасс COMPRION,
|
||||
интерфейс EN/RU.
|
||||
|
||||
## Возможности
|
||||
|
||||
**Декодер APDU** (на стороне сервера, отображается в PWA):
|
||||
|
||||
- Полное декодирование APDU — CLA по ISO 7816-4 / ETSI с **логическим
|
||||
каналом 0-19** (стандартные каналы из b2-b1, расширенные 4-19 из b4-b1
|
||||
по TS 102 221 §10.3), secure messaging и chaining команд, имена INS из
|
||||
таблицы спецификаций, учёт SFI в P1/P2 для READ/UPDATE BINARY и команд
|
||||
с записями; ответ MANAGE CHANNEL показывает назначенный картой канал
|
||||
- Статусные слова — полный набор ISO 7816-4 плюс специфичные для UICC
|
||||
значения: `91XX` (ожидается proactive-команда), `62F1/F2/F3`,
|
||||
`63F1/F2` (больше данных), `9300` (SAT busy), `9850`, `9862–64`
|
||||
- SIM Toolkit — SAT (GSM 11.14), CAT (TS 102 223) и USAT (TS 31.111):
|
||||
proactive-команды с декодированными квалификаторами, TERMINAL RESPONSE,
|
||||
ENVELOPE (Menu Selection, Call Control, SMS-PP download…); учитываются
|
||||
известные несоответствия старых карт, нераспознанные TLV сохраняются
|
||||
- TERMINAL CAPABILITY (TS 102 221 §11.1.19) — питание терминала (класс
|
||||
напряжения, максимальный ток, тактовая частота), расширенные логические
|
||||
каналы, дополнительные интерфейсы (UICC-CLF) и возможности eUICC
|
||||
(SGP.22/SGP.32)
|
||||
- SMS TPDU — SMS-DELIVER/SUBMIT, метки времени SCTS, информационные
|
||||
элементы UDH
|
||||
- SCP80 OTA secured packets — биты SPI (шифрование, требование/режим PoR,
|
||||
RC/CC/DS, счётчик), алгоритм KIc/KID + набор ключей, TAR, CNTR/PCNTR;
|
||||
декодирование Response Packet (PoR) по GET RESPONSE; **опциональная
|
||||
расшифровка на клиенте** зашифрованных пакетов — вставьте 3DES/AES-ключ
|
||||
карты в панели деталей, чтобы увидеть настоящие CNTR и защищённые данные
|
||||
приложения (ключ остаётся в браузере, только в памяти; зашифрованные
|
||||
в эфире CNTR/PCNTR/RC — это шифротекст, и они так и помечены); защищённое
|
||||
сообщение приложения декодируется как поток **C-APDU** (SELECT,
|
||||
UPDATE BINARY, …) с полной разбивкой CLA/INS/P1/P2/Lc/Le — сразу для
|
||||
открытого текста или после расшифровки для зашифрованных пакетов
|
||||
- Разбор ATR (пересчёт тактовой частоты, Fi/Di, битовая маска T,
|
||||
безопасен для усечённых ATR) и FCP/FCI TLV; исторические байты
|
||||
разбираются как COMPACT-TLV объекты UICC (TS 102 221 §6.3.1) — card
|
||||
service data, **card capabilities** (ISO 7816-4 §8.1.1.2.7 таблица 88:
|
||||
способы назначения и заявленное максимальное число логических каналов,
|
||||
`8 or more` у карт с расширенными каналами) и завершающий индикатор
|
||||
состояния (LCS/SW)
|
||||
|
||||
**PWA SIMtrace Analyser** ([`frontend/`](frontend/)):
|
||||
|
||||
- Окно трассировки с режимами «Карта»/«Список» — proactive,
|
||||
TERMINAL RESPONSE, ENVELOPE и AUTH-команды выделяются в режиме карты
|
||||
- Сессии с прямыми ссылками (`#session=N`), импорт PCAP
|
||||
(`.pcap/.pcapng/.cap`), импорт трасс COMPRION (текстовый экспорт
|
||||
«ISO Protocol Layer» из Device Manager), поиск и **фильтр команд с
|
||||
множественным выбором** — любые команды и/или готовые пресеты («Проактивные
|
||||
сессии»: FETCH, TERMINAL PROFILE и все команды с ответом SW 91xx;
|
||||
«Файловые операции»: SELECT,
|
||||
READ/UPDATE BINARY и READ/UPDATE RECORD, вместе с GET RESPONSE, несущим
|
||||
данные выбранной команды)
|
||||
- Устанавливаемая PWA, тёмная тема, интерфейс на английском/русском
|
||||

|
||||
|
||||
## Требования
|
||||
|
||||
- **Python 3.9+**
|
||||
- **PyUSB** — `pip install pyusb` (нужен только для захвата с оборудования
|
||||
SIMtrace2; захват GSMTAP/UDP и импорт PCAP работают без него)
|
||||
**Обязательно**
|
||||
|
||||
- **Python 3.9+** — для захвата GSMTAP, импорта PCAP и просмотра достаточно
|
||||
стандартной библиотеки.
|
||||
|
||||
**Только для захвата с оборудования Osmocom SIMtrace2** (`--capture direct` и
|
||||
встроенная утилита `simtrace2-pysniff`):
|
||||
|
||||
- **PyUSB** — `pip install pyusb`
|
||||
- **libusb** — системная библиотека, обычно уже есть в Linux; в Windows
|
||||
нужно заменить драйвер SIMtrace2
|
||||
(см. [Доступ к USB-устройству](#доступ-к-usb-устройству))
|
||||
- **Оборудование SIMtrace2** с прошивкой в режиме *trace* (только для
|
||||
прямого захвата; VID `1d50`, PID `60e3`, USB class `ff`, subclass `01`).
|
||||
О сборке и прошивке trace-прошивки см.
|
||||
[проект SIMtrace2](https://gitea.osmocom.org/sim-card/simtrace2).
|
||||
- **Оборудование SIMtrace2** с прошивкой в режиме *trace* (VID `1d50`, PID
|
||||
`60e3`, USB class `ff`, subclass `01`); сборка и прошивка trace-прошивки
|
||||
описаны в
|
||||
[проекте SIMtrace2](https://gitea.osmocom.org/sim-card/simtrace2).
|
||||
|
||||
Других зависимостей нет. Вывод PCAP, GSMTAP и hex dump использует только
|
||||
стандартную библиотеку Python.
|
||||
Для `--capture gsmtap` (источник GSMTAP может быть даже на другой машине),
|
||||
`--capture disabled` и импорта PCAP анализатору ничего из этого не нужно.
|
||||
|
||||
## Установка
|
||||
## Быстрый старт
|
||||
|
||||
Есть два способа получить анализатор: установить артефакт релиза (без истории
|
||||
git) или склонировать репозиторий для разработки. В обоих случаях в комплекте
|
||||
одна и та же PWA.
|
||||
Три способа запустить анализатор; все они отдают один и тот же веб-интерфейс на
|
||||
http://127.0.0.1:8081/.
|
||||
|
||||
### Из релиза (без истории git)
|
||||
### 1. Wheel (pip)
|
||||
|
||||
Всё находится на странице
|
||||
[последнего релиза](https://github.com/anttro/simtrace-analyser/releases/latest).
|
||||
|
||||
**Wheel** (PWA внутри пакета):
|
||||
Wheel содержит интерфейс внутри пакета, поэтому сервер отдаёт его сам:
|
||||
|
||||
```sh
|
||||
pip install ./simtrace_analyser-2.7.13-py3-none-any.whl
|
||||
|
||||
# затем запуск (интерфейс отдаётся на http://127.0.0.1:8081/):
|
||||
simtrace-analyser-server --capture gsmtap
|
||||
```
|
||||
|
||||
@@ -121,31 +53,43 @@ simtrace-analyser-server --capture gsmtap
|
||||
Fedora), сначала создайте виртуальное окружение:
|
||||
`python3 -m venv .venv && . .venv/bin/activate`.
|
||||
|
||||
`pip` также может скачать wheel прямо со страницы релиза (подставьте версию,
|
||||
указанную там):
|
||||
Все артефакты лежат на странице
|
||||
[последнего релиза](https://github.com/anttro/simtrace-analyser/releases/latest).
|
||||
`pip` может скачать wheel напрямую (подставьте версию со страницы), а GitHub
|
||||
CLI — выбрать последнюю:
|
||||
|
||||
```sh
|
||||
pip install https://github.com/anttro/simtrace-analyser/releases/download/v2.7.13/simtrace_analyser-2.7.13-py3-none-any.whl
|
||||
```
|
||||
|
||||
С GitHub CLI можно скачать wheel последнего релиза, не зная версии:
|
||||
|
||||
```sh
|
||||
# или:
|
||||
gh release download --pattern '*.whl'
|
||||
pip install ./simtrace_analyser-*.whl
|
||||
```
|
||||
|
||||
**Архив исходников** — ассеты *Source code (zip / tar.gz)* содержат полное
|
||||
дерево без истории git: распакуйте, перейдите в каталог и используйте скрипты
|
||||
запуска ниже (`./start.sh` в Linux/macOS, `start.bat` в Windows).
|
||||
### 2. Zip (без установки)
|
||||
|
||||
**Zip (для Windows, без установки)** — `simtrace-analyser-2.7.13.zip`
|
||||
содержит только рабочее дерево (пакеты, PWA, скрипты запуска, документацию;
|
||||
без тестов и git): скачайте, распакуйте в любое место и запустите `start.bat`
|
||||
(Windows) или `./start.sh` (Linux/macOS). Python 3 должен быть в `PATH`;
|
||||
`pip install pyusb` нужен только для прямого захвата с SIMtrace2.
|
||||
Скачайте `simtrace-analyser-2.7.13.zip` со страницы релиза и распакуйте в любое
|
||||
место: это рабочее дерево (пакеты Python, интерфейс, скрипты запуска и документация —
|
||||
без тестов и git). Архив подходит для любой ОС. Затем запустите.
|
||||
|
||||
### Из клона репозитория (для разработки)
|
||||
Windows:
|
||||
|
||||
```bat
|
||||
start.bat
|
||||
```
|
||||
|
||||
Linux/macOS:
|
||||
|
||||
```sh
|
||||
./start.sh
|
||||
```
|
||||
|
||||
Python 3 должен быть в `PATH`; `pip install pyusb` нужен только для прямого
|
||||
захвата с SIMtrace2. Скрипты принимают параметры сервера
|
||||
(`start.bat --capture direct`, `./start.sh --capture direct --port 8080`).
|
||||
(Архивы *Source code (zip / tar.gz)* из релиза — это полное дерево вместе с
|
||||
тестами; они работают так же, как клон ниже.)
|
||||
|
||||
### 3. Клон репозитория (для разработки)
|
||||
|
||||
```sh
|
||||
git clone https://github.com/anttro/simtrace-analyser.git
|
||||
@@ -154,30 +98,38 @@ cd simtrace-analyser
|
||||
```
|
||||
|
||||
Скрипты запуска добавляют каталог в `PYTHONPATH` и запускают
|
||||
`python -m simtrace_analyser`, поэтому для просмотра и захвата GSMTAP
|
||||
установка не нужна; они принимают параметры сервера
|
||||
(`./start.sh --capture direct --port 8080`). Для прямого захвата с
|
||||
оборудования нужен **PyUSB** (`pip install pyusb`).
|
||||
|
||||
Чтобы получить консольные команды (`simtrace-analyser-server`,
|
||||
`simtrace2-pysniff`), установите пакет:
|
||||
`python -m simtrace_analyser`, поэтому для просмотра и захвата GSMTAP ничего
|
||||
устанавливать не нужно; их параметры — это параметры сервера
|
||||
(`./start.sh --capture direct --port 8080`). Для прямого захвата с
|
||||
оборудования нужен **PyUSB** (`pip install pyusb`). Чтобы получить консольные
|
||||
команды (`simtrace-analyser-server`, `simtrace2-pysniff`), установите пакет:
|
||||
|
||||
```sh
|
||||
pip install -e .
|
||||
simtrace-analyser-server --capture gsmtap
|
||||
```
|
||||
|
||||
В Windows скрипты `.bat` вызывают команду `python`, поэтому Python 3 должен
|
||||
быть в `PATH` (проверьте `python --version`); для прямого захвата по USB
|
||||
дополнительно нужна замена драйвера, описанная в разделе
|
||||
[Доступ к USB-устройству](#доступ-к-usb-устройству).
|
||||
### Первый запуск
|
||||
|
||||
## Запуск
|
||||
Откройте **http://127.0.0.1:8081/** в браузере. `Ctrl+C` останавливает
|
||||
сервер.
|
||||
|
||||
### Анализирующий сервер + PWA (`simtrace-analyser-server`)
|
||||
- `--capture gsmtap` (по умолчанию) — слушать GSMTAP-SIM на UDP 4729,
|
||||
например от `simtrace2-pysniff` или `sigrok_iso7816_stream`;
|
||||
- `--capture direct` — читать оборудование SIMtrace2 напрямую (нужен PyUSB; в
|
||||
Windows также нужна замена драйвера, см.
|
||||
[Доступ к USB-устройству](#доступ-к-usb-устройству));
|
||||
- `--capture disabled` — только просмотр сохранённых захватов.
|
||||
|
||||
Полное руководство по работе (параметры сервера, экраны интерфейса, утилита захвата)
|
||||
находится в разделе [Использование](#использование).
|
||||
|
||||
## Использование
|
||||
|
||||
### Анализирующий сервер + интерфейс (`simtrace-analyser-server`)
|
||||
|
||||
Сохраняет захваченный APDU-трафик в SQLite и отдаёт его по HTTP вместе
|
||||
со встроенной PWA **SIMtrace Analyser** (`frontend/` в исходном клоне, при
|
||||
со встроенным фронтендом **SIMtrace Analyser** (`frontend/` в исходном клоне, при
|
||||
установке — внутри пакета) на том же origin.
|
||||
Три режима захвата:
|
||||
|
||||
@@ -192,6 +144,27 @@ simtrace-analyser-server --capture direct
|
||||
simtrace-analyser-server --capture disabled
|
||||
```
|
||||
|
||||
При запуске из клона или рабочего zip те же режимы доступны через скрипты
|
||||
запуска.
|
||||
|
||||
Linux/macOS:
|
||||
|
||||
```sh
|
||||
./start.sh --capture gsmtap
|
||||
./start.sh --capture direct
|
||||
./start.sh --capture disabled
|
||||
```
|
||||
|
||||
Windows:
|
||||
|
||||
```bat
|
||||
start.bat --capture gsmtap
|
||||
start.bat --capture direct
|
||||
start.bat --capture disabled
|
||||
```
|
||||
|
||||
Параметры передаются как есть (`./start.sh --capture direct --port 8080`).
|
||||
|
||||
Сервер пишет в stderr информацию о жизненном цикле захвата (каждая строка
|
||||
с локальным временем): `Capture started` при старте, периодический
|
||||
heartbeat `Capture alive: session=N messages=M bytes=B dropped=D skipped=S`
|
||||
@@ -230,7 +203,7 @@ RST несёт измеренную частоту CLK (декодер v1.9.0+,
|
||||
(табулированный текст) из COMPRION Device Manager — байтовое представление
|
||||
протокола (ATR, PPS, APDU с кодами возврата). Экспорт *ISO Application
|
||||
Layer* не содержит необработанных байтов ответов и не нужен; при его выборе
|
||||
выводится указание на файл Protocol Layer (та же проверка выполняется в PWA
|
||||
выводится указание на файл Protocol Layer (та же проверка выполняется в интерфейсе
|
||||
до загрузки и на сервере — для вызовов API).
|
||||
|
||||
Обмены перекодируются в такие же «проводные» TPDU, какие несёт захват
|
||||
@@ -349,25 +322,27 @@ TS 51.011), поэтому FID, повторно используемый в р
|
||||
--db FILE путь к базе SQLite (по умолчанию: ~/.simtrace-analyser/sessions.db)
|
||||
--capture MODE gsmtap | direct | disabled (по умолчанию: gsmtap)
|
||||
--gsmtap-port PORT UDP-порт листенера GSMTAP (по умолчанию: 4729)
|
||||
--web-dir PATH каталог статических файлов PWA (по умолчанию: PWA внутри
|
||||
установленного пакета или <repo>/frontend при запуске из исходников)
|
||||
--gsmtap-bind ADDR UDP-адрес привязки листенера GSMTAP (по умолчанию: 127.0.0.1;
|
||||
используйте 0.0.0.0, чтобы принимать из Docker-сети или с другого хоста)
|
||||
--web-dir PATH каталог статических файлов интерфейса (по умолчанию:
|
||||
фронтенд внутри установленного пакета или
|
||||
<repo>/frontend при запуске из исходников)
|
||||
```
|
||||
|
||||
Затем откройте **http://127.0.0.1:8081/** в браузере — PWA отдаётся
|
||||
сервером, поэтому UI и API используют один origin, и настройка
|
||||
CORS/Private-Network-Access не требуется. Используйте `--web-dir PATH`,
|
||||
чтобы отдавать другой каталог PWA (по умолчанию: PWA внутри пакета или
|
||||
`<repo>/frontend` при запуске из исходников).
|
||||
Затем откройте **http://127.0.0.1:8081/** в браузере. Используйте
|
||||
`--web-dir PATH`, чтобы отдавать другой каталог интерфейса (по умолчанию:
|
||||
фронтенд внутри пакета или `<repo>/frontend` при запуске из исходников).
|
||||
|
||||
### Размещённая PWA (лендинг)
|
||||
### Размещённый интерфейс (лендинг)
|
||||
|
||||
Автономная копия PWA размещена на **https://simtrace.atroshin.ru**.
|
||||
Это чистый фронтенд: укажите в нём (Settings → Server URL) адрес
|
||||
Автономная копия интерфейса размещена на **https://simtrace.atroshin.ru**.
|
||||
Это только интерфейс: укажите в нём (Settings → Server URL) адрес
|
||||
локально запущенного `simtrace-analyser-server`.
|
||||
|
||||
> **Ограничение браузера:** когда PWA отдаётся с публичного HTTPS-хоста,
|
||||
> доступ к локальному серверу (`http://127.0.0.1:8081`) требует двух
|
||||
> вещей: сервер должен отправлять
|
||||
> **Ограничение браузера:** это единственная схема, где интерфейс и API
|
||||
> находятся на разных origin, поэтому браузер применяет правила CORS и
|
||||
> Private Network Access. Доступ к локальному серверу
|
||||
> (`http://127.0.0.1:8081`) требует двух вещей: сервер должен отправлять
|
||||
> `Access-Control-Allow-Private-Network: true` (этот сервер отправляет),
|
||||
> и браузер должен иметь разрешение на доступ к локальной сети —
|
||||
> в Chrome/Edge/Vivaldi: Настройки сайта → Доступ к локальной сети →
|
||||
@@ -413,6 +388,77 @@ python -m simtrace2_pysniff --pcap trace.pcap
|
||||
simtrace2-pysniff --format atr-time
|
||||
```
|
||||
|
||||
### Параметры CLI утилиты
|
||||
|
||||
```
|
||||
python -m simtrace2_pysniff [OPTIONS]
|
||||
|
||||
--format, -f FORMAT Формат вывода (по умолчанию: hex)
|
||||
hex — обычный hex-дамп
|
||||
timestamp — строки TPDU с префиксом [ЧЧ:ММ:СС.мс]
|
||||
atr-time — строки TPDU с префиксом [СССС.мс] от последнего ATR
|
||||
--gsmtap HOST[:PORT] Отправлять ATR/TPDU как GSMTAP по UDP (порт по умолчанию 4729)
|
||||
--pcap FILE Записывать перехваченные данные в PCAP для Wireshark
|
||||
--output, -o FILE Записывать hex-дамп в файл
|
||||
--no-stdout Не выводить hex-дамп в stdout
|
||||
--vendor HEX USB vendor ID (по умолчанию: 0x1d50)
|
||||
--product HEX USB product ID (по умолчанию: автоопределение)
|
||||
|
||||
Параметры восстановления:
|
||||
--no-reconnect Выходить при отключении USB вместо переподключения
|
||||
--reconnect-delay-min SEC Минимальная задержка переподключения (по умолчанию: 1.0)
|
||||
--reconnect-delay-max SEC Максимальная задержка переподключения (по умолчанию: 30.0)
|
||||
--backoff-factor N Множитель экспоненциальной задержки (по умолчанию: 1.5)
|
||||
--inactivity-timeout SEC Переподключаться после N секунд тишины (по умолчанию: выключено)
|
||||
```
|
||||
|
||||
### Форматы вывода
|
||||
|
||||
- **`hex`** (по умолчанию): обычный hex-дамп — `ATR: 3b 9e ...`,
|
||||
`TPDU: a0 a4 00 00 02 3f 00`
|
||||
- **`timestamp`**: строки TPDU с локальным временем —
|
||||
`[14:32:05.123] TPDU: a0 a4 00 00 02 3f 00`
|
||||
- **`atr-time`**: строки TPDU с секундами от последнего ATR —
|
||||
`[0001.234] TPDU: a0 a4 00 00 02 3f 00`
|
||||
|
||||
Сообщения, не являющиеся TPDU (ATR, PPS, изменения состояния карты, Fi/Di),
|
||||
выводятся одинаково во всех форматах.
|
||||
|
||||
- **GSMTAP**: сообщения ATR и APDU по UDP (порт 4729) в Wireshark
|
||||
- **PCAP**: сообщения ATR/TPDU как пакеты Ethernet/IP/UDP/GSMTAP,
|
||||
открываются в Wireshark
|
||||
|
||||
### Фоновый режим / демон
|
||||
|
||||
SIGHUP автоматически игнорируется, когда stdin не является терминалом
|
||||
(т.е. при запуске в фоне или через канал). Сессии в терминале на переднем
|
||||
плане по-прежнему обрабатывают SIGHUP обычным образом.
|
||||
|
||||
Для постоянной работы в фоне с выводом в файлы:
|
||||
|
||||
```sh
|
||||
nohup ./sniff-start.sh --output /tmp/sniff.log &> /tmp/sniff-err.log &
|
||||
# или
|
||||
FORMAT=timestamp nohup python -m simtrace2_pysniff --output /tmp/sniff.log &> /tmp/sniff-err.log &
|
||||
```
|
||||
|
||||
### Использование как библиотеки
|
||||
|
||||
```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()}")
|
||||
```
|
||||
|
||||
### Восстановление
|
||||
|
||||
Утилита по умолчанию переживает сбросы оборудования, отключения кабеля
|
||||
и зависания прошивки — она переподключается с экспоненциальной задержкой
|
||||
(1с → 30с). Используйте `--inactivity-timeout`, чтобы также переподключаться
|
||||
при «тихих» зависаниях прошивки.
|
||||
|
||||
## Доступ к USB-устройству
|
||||
|
||||
Нужен для захвата с оборудования SIMtrace2 (утилита и режим
|
||||
@@ -451,76 +497,76 @@ sudo udevadm trigger
|
||||
Python 3 должен быть в `PATH` (проверьте `python --version` в новом окне
|
||||
команды).
|
||||
|
||||
## Параметры CLI утилиты
|
||||
## Компоненты
|
||||
|
||||
```
|
||||
python -m simtrace2_pysniff [OPTIONS]
|
||||
- **Анализирующий сервер + интерфейс** (`simtrace-analyser-server`) — сохраняет
|
||||
захваченный трафик в SQLite, декодирует его и отдаёт интерфейс
|
||||
([`frontend/`](frontend/)) вместе с HTTP API на одном origin. Три режима
|
||||
захвата: GSMTAP-листенер, захват напрямую с оборудования SIMtrace2 или
|
||||
отключённый захват (только просмотр существующих записей).
|
||||
- **Утилита захвата** (`simtrace2-pysniff`) — захватывает трафик
|
||||
оборудования SIMtrace2 и выводит его в stdout, GSMTAP (Wireshark) или
|
||||
PCAP-файлы. Это один из нескольких источников GSMTAP, которые принимает
|
||||
анализатор (см. также
|
||||
[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)).
|
||||
- **Интерфейс** ([`frontend/`](frontend/)) — окно трассировки с декодированными
|
||||
APDU, SIM Toolkit, SMS и SCP80 OTA; сессии, импорт PCAP и трасс COMPRION,
|
||||
интерфейс EN/RU.
|
||||
|
||||
--format, -f FORMAT Формат вывода (по умолчанию: hex)
|
||||
hex — обычный hex-дамп
|
||||
timestamp — строки TPDU с префиксом [ЧЧ:ММ:СС.мс]
|
||||
atr-time — строки TPDU с префиксом [СССС.мс] от последнего ATR
|
||||
--gsmtap HOST[:PORT] Отправлять ATR/TPDU как GSMTAP по UDP (порт по умолчанию 4729)
|
||||
--pcap FILE Записывать перехваченные данные в PCAP для Wireshark
|
||||
--output, -o FILE Записывать hex-дамп в файл
|
||||
--no-stdout Не выводить hex-дамп в stdout
|
||||
--vendor HEX USB vendor ID (по умолчанию: 0x1d50)
|
||||
--product HEX USB product ID (по умолчанию: автоопределение)
|
||||
## Возможности
|
||||
|
||||
Параметры восстановления:
|
||||
--no-reconnect Выходить при отключении USB вместо переподключения
|
||||
--reconnect-delay-min SEC Минимальная задержка переподключения (по умолчанию: 1.0)
|
||||
--reconnect-delay-max SEC Максимальная задержка переподключения (по умолчанию: 30.0)
|
||||
--backoff-factor N Множитель экспоненциальной задержки (по умолчанию: 1.5)
|
||||
--inactivity-timeout SEC Переподключаться после N секунд тишины (по умолчанию: выключено)
|
||||
```
|
||||
**Декодер APDU** (на стороне сервера, отображается в интерфейсе):
|
||||
|
||||
## Форматы вывода
|
||||
- Полное декодирование APDU — CLA по ISO 7816-4 / ETSI с **логическим
|
||||
каналом 0-19** (стандартные каналы из b2-b1, расширенные 4-19 из b4-b1
|
||||
по TS 102 221 §10.3), secure messaging и chaining команд, имена INS из
|
||||
таблицы спецификаций, учёт SFI в P1/P2 для READ/UPDATE BINARY и команд
|
||||
с записями; ответ MANAGE CHANNEL показывает назначенный картой канал
|
||||
- Статусные слова — полный набор ISO 7816-4 плюс специфичные для UICC
|
||||
значения: `91XX` (ожидается proactive-команда), `62F1/F2/F3`,
|
||||
`63F1/F2` (больше данных), `9300` (SAT busy), `9850`, `9862–64`
|
||||
- SIM Toolkit — SAT (GSM 11.14), CAT (TS 102 223) и USAT (TS 31.111):
|
||||
proactive-команды с декодированными квалификаторами, TERMINAL RESPONSE,
|
||||
ENVELOPE (Menu Selection, Call Control, SMS-PP download…); учитываются
|
||||
известные несоответствия старых карт, нераспознанные TLV сохраняются
|
||||
- TERMINAL CAPABILITY (TS 102 221 §11.1.19) — питание терминала (класс
|
||||
напряжения, максимальный ток, тактовая частота), расширенные логические
|
||||
каналы, дополнительные интерфейсы (UICC-CLF) и возможности eUICC
|
||||
(SGP.22/SGP.32)
|
||||
- SMS TPDU — SMS-DELIVER/SUBMIT, метки времени SCTS, информационные
|
||||
элементы UDH
|
||||
- SCP80 OTA secured packets — биты SPI (шифрование, требование/режим PoR,
|
||||
RC/CC/DS, счётчик), алгоритм KIc/KID + набор ключей, TAR, CNTR/PCNTR;
|
||||
декодирование Response Packet (PoR) по GET RESPONSE; **опциональная
|
||||
расшифровка на клиенте** зашифрованных пакетов — вставьте 3DES/AES-ключ
|
||||
карты в панели деталей, чтобы увидеть настоящие CNTR и защищённые данные
|
||||
приложения (ключ остаётся в браузере, только в памяти; зашифрованные
|
||||
в эфире CNTR/PCNTR/RC — это шифротекст, и они так и помечены); защищённое
|
||||
сообщение приложения декодируется как поток **C-APDU** (SELECT,
|
||||
UPDATE BINARY, …) с полной разбивкой CLA/INS/P1/P2/Lc/Le — сразу для
|
||||
открытого текста или после расшифровки для зашифрованных пакетов
|
||||
- Разбор ATR (пересчёт тактовой частоты, Fi/Di, битовая маска T,
|
||||
безопасен для усечённых ATR) и FCP/FCI TLV; исторические байты
|
||||
разбираются как COMPACT-TLV объекты UICC (TS 102 221 §6.3.1) — card
|
||||
service data, **card capabilities** (ISO 7816-4 §8.1.1.2.7 таблица 88:
|
||||
способы назначения и заявленное максимальное число логических каналов,
|
||||
`8 or more` у карт с расширенными каналами) и завершающий индикатор
|
||||
состояния (LCS/SW)
|
||||
|
||||
- **`hex`** (по умолчанию): обычный hex-дамп — `ATR: 3b 9e ...`,
|
||||
`TPDU: a0 a4 00 00 02 3f 00`
|
||||
- **`timestamp`**: строки TPDU с локальным временем —
|
||||
`[14:32:05.123] TPDU: a0 a4 00 00 02 3f 00`
|
||||
- **`atr-time`**: строки TPDU с секундами от последнего ATR —
|
||||
`[0001.234] TPDU: a0 a4 00 00 02 3f 00`
|
||||
**Интерфейс SIMtrace Analyser** ([`frontend/`](frontend/)):
|
||||
|
||||
Сообщения, не являющиеся TPDU (ATR, PPS, изменения состояния карты, Fi/Di),
|
||||
выводятся одинаково во всех форматах.
|
||||
|
||||
- **GSMTAP**: сообщения ATR и APDU по UDP (порт 4729) в Wireshark
|
||||
- **PCAP**: сообщения ATR/TPDU как пакеты Ethernet/IP/UDP/GSMTAP,
|
||||
открываются в Wireshark
|
||||
|
||||
## Фоновый режим / демон
|
||||
|
||||
SIGHUP автоматически игнорируется, когда stdin не является терминалом
|
||||
(т.е. при запуске в фоне или через канал). Сессии в терминале на переднем
|
||||
плане по-прежнему обрабатывают SIGHUP обычным образом.
|
||||
|
||||
Для постоянной работы в фоне с выводом в файлы:
|
||||
|
||||
```sh
|
||||
nohup ./sniff-start.sh --output /tmp/sniff.log &> /tmp/sniff-err.log &
|
||||
# или
|
||||
FORMAT=timestamp nohup python -m simtrace2_pysniff --output /tmp/sniff.log &> /tmp/sniff-err.log &
|
||||
```
|
||||
|
||||
## Использование как библиотеки
|
||||
|
||||
```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()}")
|
||||
```
|
||||
|
||||
## Восстановление
|
||||
|
||||
Утилита по умолчанию переживает сбросы оборудования, отключения кабеля
|
||||
и зависания прошивки — она переподключается с экспоненциальной задержкой
|
||||
(1с → 30с). Используйте `--inactivity-timeout`, чтобы также переподключаться
|
||||
при «тихих» зависаниях прошивки.
|
||||
- Окно трассировки с режимами «Карта»/«Список» — proactive,
|
||||
TERMINAL RESPONSE, ENVELOPE и AUTH-команды выделяются в режиме карты
|
||||
- Сессии с прямыми ссылками (`#session=N`), импорт PCAP
|
||||
(`.pcap/.pcapng/.cap`), импорт трасс COMPRION (текстовый экспорт
|
||||
«ISO Protocol Layer» из Device Manager), поиск и **фильтр команд с
|
||||
множественным выбором** — любые команды и/или готовые пресеты («Проактивные
|
||||
сессии»: FETCH, TERMINAL PROFILE и все команды с ответом SW 91xx;
|
||||
«Файловые операции»: SELECT,
|
||||
READ/UPDATE BINARY и READ/UPDATE RECORD, вместе с GET RESPONSE, несущим
|
||||
данные выбранной команды)
|
||||
- **PWA** (progressive web app): устанавливается на рабочий стол или домашний
|
||||
экран и работает офлайн; тёмная тема, интерфейс на английском/русском
|
||||
|
||||
## Связанные проекты
|
||||
|
||||
@@ -533,7 +579,7 @@ for msg in session.iter_messages():
|
||||
|
||||
## Лицензия
|
||||
|
||||
MIT — см. [LICENSE](LICENSE). Декодеры и реализация DES/3DES в PWA написаны
|
||||
MIT — см. [LICENSE](LICENSE). Декодеры и реализация DES/3DES в интерфейсе написаны
|
||||
самостоятельно по спецификациям ISO 7816, ETSI и 3GPP; сторонний код в проект
|
||||
не включён. PyUSB (BSD-3-Clause) — зависимость для прямого захвата с
|
||||
оборудования.
|
||||
@@ -1,7 +1,8 @@
|
||||
"""simtrace-analyser-server — CLI entry point.
|
||||
|
||||
Usage:
|
||||
simtrace-analyser-server --capture gsmtap [--gsmtap-port 4729] [--port 8081]
|
||||
simtrace-analyser-server --capture gsmtap [--gsmtap-bind 0.0.0.0]
|
||||
[--gsmtap-port 4729] [--port 8081]
|
||||
simtrace-analyser-server --capture direct [--port 8081]
|
||||
"""
|
||||
|
||||
@@ -46,6 +47,9 @@ def main():
|
||||
help='Capture mode: gsmtap (listen UDP 4729), direct (SIMtrace2 USB), or disabled (no capture)')
|
||||
p.add_argument('--gsmtap-port', type=int, default=4729,
|
||||
help='UDP port for GSMTAP listener (default: 4729)')
|
||||
p.add_argument('--gsmtap-bind', default='127.0.0.1', metavar='ADDR',
|
||||
help='UDP bind address for the GSMTAP listener '
|
||||
'(default: 127.0.0.1; use 0.0.0.0 in a container)')
|
||||
p.add_argument('--log-interval', type=float, default=60.0,
|
||||
help='Seconds between capture liveness heartbeat logs '
|
||||
'(default: 60.0)')
|
||||
@@ -61,7 +65,7 @@ def main():
|
||||
|
||||
capture = None
|
||||
if args.capture == 'gsmtap':
|
||||
backend = GsmtapListener(bind_port=args.gsmtap_port)
|
||||
backend = GsmtapListener(bind_ip=args.gsmtap_bind, bind_port=args.gsmtap_port)
|
||||
capture = CaptureManager(backend, db, log_interval=args.log_interval)
|
||||
elif args.capture == 'direct':
|
||||
backend = DirectSniffer()
|
||||
@@ -78,6 +82,7 @@ def main():
|
||||
print(f'simtrace-analyser-server v{__version__} — http://{args.host}:{args.port}', file=sys.stderr)
|
||||
print(f' capture mode: {args.capture}', file=sys.stderr)
|
||||
if args.capture == 'gsmtap':
|
||||
print(f' GSMTAP bind: {args.gsmtap_bind}', file=sys.stderr)
|
||||
print(f' GSMTAP port: {args.gsmtap_port}', file=sys.stderr)
|
||||
print(f' database: {args.db}', file=sys.stderr)
|
||||
print(f' PWA served at http://{args.host}:{args.port}/', file=sys.stderr)
|
||||
|
||||
@@ -39,15 +39,17 @@ def gsmtap_msg_type(sub_type):
|
||||
|
||||
|
||||
class GsmtapListener:
|
||||
def __init__(self, bind_port=4729):
|
||||
def __init__(self, bind_port=4729, bind_ip='127.0.0.1'):
|
||||
self._bind_port = bind_port
|
||||
self._receiver = GsmtapReceiver(bind_port=bind_port)
|
||||
self._bind_ip = bind_ip
|
||||
self._receiver = GsmtapReceiver(bind_ip=bind_ip, bind_port=bind_port)
|
||||
self._running = False
|
||||
self._dropped = 0
|
||||
|
||||
def start(self):
|
||||
if getattr(self._receiver, '_closed', False):
|
||||
self._receiver = GsmtapReceiver(bind_port=self._bind_port)
|
||||
self._receiver = GsmtapReceiver(bind_ip=self._bind_ip,
|
||||
bind_port=self._bind_port)
|
||||
self._running = True
|
||||
self._dropped = 0
|
||||
|
||||
|
||||
@@ -206,6 +206,41 @@ class TestGsmtapListenerRobustness(unittest.TestCase):
|
||||
self.assertEqual(listener.dropped, 1)
|
||||
|
||||
|
||||
class TestGsmtapListenerBind(unittest.TestCase):
|
||||
def test_bind_ip_reaches_the_receiver(self):
|
||||
from simtrace_analyser import capture
|
||||
calls = []
|
||||
|
||||
class _FakeReceiver:
|
||||
def __init__(self, bind_ip='127.0.0.1', bind_port=4729):
|
||||
calls.append((bind_ip, bind_port))
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
real = capture.GsmtapReceiver
|
||||
capture.GsmtapReceiver = _FakeReceiver
|
||||
try:
|
||||
listener = capture.GsmtapListener(bind_ip='0.0.0.0', bind_port=4729)
|
||||
listener._receiver._closed = True # force start() to re-create it
|
||||
listener.start()
|
||||
finally:
|
||||
capture.GsmtapReceiver = real
|
||||
self.assertEqual(calls, [('0.0.0.0', 4729), ('0.0.0.0', 4729)])
|
||||
|
||||
def test_all_interfaces_bind(self):
|
||||
from simtrace_analyser.capture import GsmtapListener
|
||||
listener = GsmtapListener(bind_ip='0.0.0.0', bind_port=0)
|
||||
self.addCleanup(listener.stop)
|
||||
self.assertEqual(listener._receiver._sock.getsockname()[0], '0.0.0.0')
|
||||
|
||||
def test_default_bind_is_loopback(self):
|
||||
from simtrace_analyser.capture import GsmtapListener
|
||||
listener = GsmtapListener(bind_port=0)
|
||||
self.addCleanup(listener.stop)
|
||||
self.assertEqual(listener._receiver._sock.getsockname()[0], '127.0.0.1')
|
||||
|
||||
|
||||
class TestCaptureLoopRobustness(unittest.TestCase):
|
||||
def test_capture_loop_survives_insert_error(self):
|
||||
mgr = CaptureManager(_OneShotBackend(), _NullDb())
|
||||
|
||||
Reference in new issue
Block a user