10 Commits
Author SHA1 Message Date
catarrh 5a7768e6a9 README: stop framing the runtime zip as Windows-only
The zip is just an archive: it extracts and runs on any OS, and the release's
Source code assets are offered as zip as well as tar.gz, so users pick the
format they prefer.  The section is now "Zip (no installer)" (RU "Zip (без
установки)") and says the archive works on any OS; the Windows/Linux start
commands stay as instructions, not as the section's rationale.  The
source-archive note names both formats, and the release-notes template
follows.
2026-10-27 11:10:55 +03:00
catarrh 7801c62ca3 README: show the launcher forms in the Usage capture modes
The Usage server section only showed the console script and mentioned the
launchers in prose.  It now lists the three capture modes for ./start.sh
(Linux/macOS) and start.bat (Windows) right after the console-script block,
with the pass-through example (--port).
2026-10-27 11:08:11 +03:00
catarrh f18a11edaf README: say UI/frontend except where PWA actually matters
"PWA" appeared throughout the READMEs although most readers don't know the
term and it is usually irrelevant: the server just serves a web interface.
The text now says UI (web UI) for the app and frontend for the static files -
in the quick start, the install/zip/clone paths, the server and --web-dir
docs, the components list and the decoder notes.  The one place where it
matters - the feature list's installable PWA - keeps the term and unpacks it
(installs to the desktop or home screen and works offline); the hosted copy is
now "Hosted UI" since the point there is connecting to a local server.

Both languages; docs only, 557 Python + 80 Node tests.
2026-10-27 11:06:08 +03:00
catarrh 6fbe57052f README: drop the CORS aside from Quick start, keep it where origins differ
The first-run step explained that the PWA and the API share an origin and no
CORS/Private-Network-Access setup is involved - noise for the default setup,
which always serves both from the same server.  The line is gone (both
languages), the Usage server intro no longer repeats it either, and the one
place where it matters - the hosted PWA, which talks to a local server from
another origin - now says so explicitly before the browser requirements.
2026-10-27 11:00:27 +03:00
catarrh 9872913965 README: mark the SIMtrace2 USB prerequisites as conditional
The prerequisites read as if PyUSB, libusb and SIMtrace2 hardware were needed
generally.  They are only for `--capture direct` (and the bundled
`simtrace2-pysniff` utility): the analyser starts and captures GSMTAP with
just Python 3.9+ - verified in a fresh venv without PyUSB, where the server
served the PWA and a GSMTAP ATR+APDU landed in the session (2 messages).

Both READMEs split the list into "Required" (Python 3.9+) and "Only for
capturing from Osmocom SIMtrace2 hardware", and state that GSMTAP capture
(the source may even run on another machine), --capture disabled and PCAP
imports need none of it.  No code change; 557 Python + 80 Node tests.
2026-10-27 10:49:45 +03:00
catarrh a863f66860 README: quick start first, the runtime guide under Usage
The startup instructions were buried after Components/Features and mixed
release/download variants with runtime detail; a reader had to scroll through
the usage guide to find how to launch it, and the start scripts were only
mentioned in passing.

Both READMEs now lead with Prerequisites then a Quick start with three clear
paths - wheel (pip), runtime zip (start.bat / ./start.sh) and a git clone
(launchers, optional pip install -e .) - followed by First run (URL, capture
modes, Ctrl+C).  The detailed runtime guide moves under `Usage`: the server
and PWA, COMPRION import, the Files view, the hosted PWA, the capture utility,
the utility CLI options, output formats, the daemon, library usage and
recovery.  Components and Features follow the usage guide; USB device access
keeps its anchor.

Only the Analysis server intro gained the launcher note; every moved section
is byte-identical (checked old vs new).  557 Python + 80 Node tests.
2026-10-27 05:20:55 +03:00
catarrh 6ed3a7b7d6 README: link the project website next to the Telegram channel
Project news now lives on https://atroshin.ru as well; both links sit on the
same line near the top, in the English and the Russian README.
2026-10-26 22:12:05 +03:00
catarrh 903ead9791 GSMTAP: --gsmtap-bind to listen beyond loopback (containers)
A container's 127.0.0.1 is its own loopback, so a GSMTAP feed sent to the
container's bridge address never reached the listener: it was hard-bound to
127.0.0.1.

- `simtrace-analyser-server --gsmtap-bind ADDR` (default 127.0.0.1) is passed
  through GsmtapListener to GsmtapReceiver (whose bind_ip already existed),
  including the receiver re-created by a start() after close.  The startup
  banner prints the effective bind address next to the port.
- READMEs (EN/RU) document the option, naming the container case.
- tests: the listener forwards the address on construction and on start(),
  binds 0.0.0.0, and keeps the loopback default.

Verified end-to-end: with --gsmtap-bind 0.0.0.0 the socket listens on
0.0.0.0:14732 and an ATR + APDU sent to 127.0.0.1:14732 landed in the capture
session (2 messages); without the flag it listens on 127.0.0.1.
557 Python + 80 Node tests.
2026-10-26 14:45:58 +03:00
catarrh c810ff50cf README: link the project's Telegram channel
Adds the channel (project news and release announcements) right after the
introduction, in both the English and the Russian README.
2026-10-23 21:44:13 +03:00
catarrh 5fcd8e9fd6 Relicense to MIT (v2.7.13)
Release / release (push) Waiting to run
The project's only runtime dependency is PyUSB (BSD-3-Clause) and it bundles
no third-party code (the PWA's DES/3DES is written from the FIPS 46-3 tables,
AES uses WebCrypto, the decoders come from the ISO 7816/ETSI/3GPP specs), so
nothing forced GPL; the GPL-2.0-or-later declaration is replaced with MIT.

- LICENSE: the MIT text, Copyright (c) 2026 Anton Troshin.
- pyproject: license = "MIT" + license-files = ["LICENSE"] (PEP 639), and the
  build requirement moves to setuptools>=77 for the SPDX form.  The wheel now
  carries dist-info/licenses/LICENSE and License-Expression: MIT, the sdist
  and the runtime zip carry LICENSE at the top.
- READMEs (EN/RU): a License section (original decoders/DES implementation,
  PyUSB as the only runtime dependency).
- tests: the packaging test pins the MIT declaration and the LICENSE text;
  the release-zip test requires LICENSE in the archive.
- version 2.7.13; SW cache v95.

Copies published before this tag (v2.7.10-v2.7.12) remain under the license
they were released with.
2026-10-21 01:03:55 +03:00
15 changed files with 590 additions and 403 deletions

No files matched your search

+3 -1
View File
@@ -13,8 +13,10 @@ 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
needed for direct SIMtrace2 capture.
The project is MIT-licensed (see `LICENSE`).
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Anton Troshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+1
View File
@@ -1,3 +1,4 @@
graft frontend
include LICENSE
include README.md README_RUS.md 70-simtrace2-pysniff.rules
include start.sh start.bat sniff-start.sh sniff-start.bat
+248 -191
View File
@@ -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.
![SIMtrace Analyser PWA](frontend.png)
📢 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
![SIMtrace Analyser UI](frontend.png)
## 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.12-py3-none-any.whl
# then run (the UI is served at http://127.0.0.1:8081/):
pip install ./simtrace_analyser-2.7.13-py3-none-any.whl
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):
```sh
pip install https://github.com/anttro/simtrace-analyser/releases/download/v2.7.12/simtrace_analyser-2.7.12-py3-none-any.whl
```
With the GitHub CLI, download the latest wheel without knowing the version:
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
# 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.12.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
@@ -510,3 +560,10 @@ Use `--inactivity-timeout` to also trigger reconnect on silent firmware hangs.
- **[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)** —
FX2LP-based passive ISO 7816 sniffer that emits the same GSMTAP-SIM stream
on UDP 4729 (accepted by this project's GSMTAP listener).
## License
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.
+252 -199
View File
@@ -9,111 +9,43 @@ SIM/UICC из UDP-потока GSMTAP (или импортирует файлы
на Python, которая захватывает трафик с оборудования Osmocom SIMtrace2
и может передавать GSMTAP этому анализатору.
![PWA SIMtrace Analyser](frontend.png)
📢 Новости и обновления проекта: [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, тёмная тема, интерфейс на английском/русском
![Интерфейс SIMtrace Analyser](frontend.png)
## Требования
- **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.12-py3-none-any.whl
# затем запуск (интерфейс отдаётся на http://127.0.0.1:8081/):
pip install ./simtrace_analyser-2.7.13-py3-none-any.whl
simtrace-analyser-server --capture gsmtap
```
@@ -121,31 +53,43 @@ simtrace-analyser-server --capture gsmtap
Fedora), сначала создайте виртуальное окружение:
`python3 -m venv .venv && . .venv/bin/activate`.
`pip` также может скачать wheel прямо со страницы релиза (подставьте версию,
указанную там):
```sh
pip install https://github.com/anttro/simtrace-analyser/releases/download/v2.7.12/simtrace_analyser-2.7.12-py3-none-any.whl
```
С GitHub CLI можно скачать 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
# или:
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.12.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
установка не нужна; они принимают параметры сервера
`python -m simtrace_analyser`, поэтому для просмотра и захвата GSMTAP ничего
устанавливать не нужно; их параметры — это параметры сервера
(`./start.sh --capture direct --port 8080`). Для прямого захвата с
оборудования нужен **PyUSB** (`pip install pyusb`).
Чтобы получить консольные команды (`simtrace-analyser-server`,
`simtrace2-pysniff`), установите пакет:
оборудования нужен **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): устанавливается на рабочий стол или домашний
экран и работает офлайн; тёмная тема, интерфейс на английском/русском
## Связанные проекты
@@ -530,3 +576,10 @@ for msg in session.iter_messages():
- **[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)** —
пассивный ISO 7816 сниффер на базе FX2LP, выдающий такой же поток
GSMTAP-SIM на UDP 4729 (принимается GSMTAP-листенером этого проекта).
## Лицензия
MIT — см. [LICENSE](LICENSE). Декодеры и реализация DES/3DES в интерфейсе написаны
самостоятельно по спецификациям ISO 7816, ETSI и 3GPP; сторонний код в проект
не включён. PyUSB (BSD-3-Clause) — зависимость для прямого захвата с
оборудования.
+1 -1
View File
@@ -3389,7 +3389,7 @@ function onSearchChange() {
}
// ──────────────────── Versioning ────────────────────
const PWA_VERSION = '2.7.12';
const PWA_VERSION = '2.7.13';
const MIN_SERVER_VERSION = '2.3.0';
function parseVersion(v) {
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simtrace-analyser-v94';
const CACHE = 'simtrace-analyser-v95';
const PRECACHE = [
'index.html',
+4 -3
View File
@@ -1,13 +1,14 @@
[build-system]
requires = ["setuptools>=64"]
requires = ["setuptools>=77"]
build-backend = "setuptools.build_meta"
[project]
name = "simtrace-analyser"
version = "2.7.12"
version = "2.7.13"
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
readme = {file = "README.md", content-type = "text/markdown"}
license = {text = "GPL-2.0-or-later"}
license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.9"
dependencies = [
"pyusb>=1.2",
+7 -2
View File
@@ -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)
+5 -3
View File
@@ -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
+1 -1
View File
@@ -1,3 +1,3 @@
"""Single source of truth for the SIMtrace Analyser version."""
__version__ = '2.7.12'
__version__ = '2.7.13'
+35
View File
@@ -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())
+9
View File
@@ -70,6 +70,15 @@ class TestDistributionMetadata(unittest.TestCase):
# The sdist carries frontend/, so a wheel built from it has the PWA.
self.assertIn('graft frontend', self._read('MANIFEST.in'))
def test_license_is_mit(self):
# The project is MIT; the metadata and the file must not drift apart.
pyproject = self._read('pyproject.toml')
self.assertIn('license = "MIT"', pyproject)
self.assertIn('license-files = ["LICENSE"]', pyproject)
license_text = self._read('LICENSE')
self.assertTrue(license_text.startswith('MIT License\n'))
self.assertIn('Permission is hereby granted, free of charge', license_text)
def test_setup_py_bundles_the_pwa(self):
setup_py = self._read('setup.py')
self.assertIn('frontend', setup_py)
+1 -1
View File
@@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase):
class TestVersion(unittest.TestCase):
def test_package_version(self):
from simtrace2_pysniff import __version__
self.assertEqual(__version__, '2.7.12')
self.assertEqual(__version__, '2.7.13')
def test_status_includes_version(self):
import os
+1
View File
@@ -51,6 +51,7 @@ class TestReleaseZip(unittest.TestCase):
'sniff-start.sh',
'sniff-start.bat',
'70-simtrace2-pysniff.rules',
'LICENSE',
'README.md'):
self.assertIn('%s/%s' % (top, rel), self.names)