Null-DRM-Official/README.md
404errordeveloper 2fa8f2435f Initial commit: Null DRM Official
Capture, decrypt, and restream toolkit with compiled-in app modules
(RTE, TG4, BBC), on-device MITM proxy, streamd control plane, and www.
BBC module.yaml is published (clear streams); other module values stay local.
2026-10-06 00:25:35 +02:00

4.7 KiB

DRM-Decryption

Capture Widevine live sessions from Android streaming apps and restream them.

Everything is one Go binary — drm — with every app module compiled in. Each streaming app (RTE, TG4, …) is a Go package under apps/modules/; its secrets and IDs live in a local, gitignored values file that you fill in yourself.

  • docs/ — architecture, module authoring, per-provider setup
  • docs/quickstart.md — the longer version of what follows

Quick start

1. Prerequisites

Need Why
Go 1.25+ builds everything
Python 3.10+ apps/wvkey/wvkey.py talks to the Widevine CDM
adb (platform-tools) on PATH only for phone capture
A .wvd Widevine device file only for fetching keys

Phone capture additionally needs a rooted Android device (Magisk) so the MITM CA can be injected into the system trust store. Catalog lookups need no phone.

2. Clone and build

git clone https://git.nulldrm.com/nulldrm/Null-DRM-Official.git
cd Null-DRM-Official

# Linux / macOS
go -C apps/cli build -o ../../bin/drm .

# Windows
go -C apps/cli build -o ../../bin/drm.exe .

Check it:

./bin/drm help
./bin/drm modules     # which app modules this build contains

drm modules works immediately, but channel lists stay empty until you add values — that is the next step.

3. Python CDM helper

python -m venv .venv
.venv/bin/pip install -r apps/wvkey/requirements.txt    # Windows: .venv\Scripts\pip

Put your Widevine device file in data/ (gitignored), e.g. data/device.wvd.

4. Fill in a module's values

Compiled-in module code carries no account IDs, policy keys, video IDs, license URLs or key IDs. Those go in a gitignored file per module, which you create:

apps/modules/tg4/module.yaml
apps/modules/rte/module.yaml

Where each value comes from:

Any value can be passed per-run instead of stored:

./bin/drm catalog --app tg4 --channel ioi --tg4.policy-key 'BCpkAD...'
TG4_POLICY_KEY='BCpkAD...' ./bin/drm catalog --app tg4 --channel ioi

5. Run something

# keys from a public catalog — no phone needed
./bin/drm catalog --app tg4 --channel ioi --keys --wvd data/device.wvd

# phone capture: launch the app, drive it to a channel, grab license + keys
./bin/drm proxy build        # once: cross-compile the on-device MITM
./bin/drm capture --app rte --channel rteone --auto-play --wvd data/device.wvd

# control plane + dashboard on http://127.0.0.1:8083
./bin/drm serve --bind 127.0.0.1:8083 --data .cache/streamd --token SECRET

# always-on refresher: watches streamd, re-captures dead channels
STREAMD_TOKEN=SECRET ./bin/drm agent run --config apps/agent/agent.yaml

Results land in outputs/<app>/<timestamp>/, with latest/ kept as a copy.


Subcommands

Command What it does
drm modules list compiled-in app modules, their channels and config source
drm capture one-shot phone MITM capture → outputs/<app>/<stamp>/
drm catalog resolve a channel from its public catalog, no phone
drm serve streamd: REST API + dashboard + media supervisor
drm agent run / status / devices / enqueue / cancel
drm proxy build / push / install-ca / start / stop / discover / pull

Run any of them with --help.

Layout

apps/cli/        the binary            -> bin/drm
apps/modules/    app modules: Go (tracked) + module.yaml (gitignored)
apps/pkg/        shared, provider-neutral libraries
apps/capture/    phone capture command
apps/agent/      always-on key refresher
apps/streamd/    control plane: API, SQLite, dashboard, supervisor
apps/proxy/      MITM host CLI + on-device proxy source
apps/wvkey/      wvkey.py — CDM only
docs/            architecture, authoring, provider setup
data/            secrets: .wvd, CA        (gitignored)
outputs/         capture sessions         (gitignored)
bin/             built binaries           (gitignored)
www/             static site

Tests

go -C apps/pkg test ./...
go -C apps/modules test ./...
go -C apps/streamd test ./...

Tests that hit a live origin are behind a build tag, so they stay out of the normal run:

go -C apps/modules test -tags live ./rte/ -v

Scope

For use only on services you are authorised to access, with content you have the right to decrypt. docs/architecture.md describes what the system does and where it stops.