Free forever · open source

Capture, decrypt and restream your own subscriptions.

NULLDRM logs the Widevine handshake from an Android app, recovers the content keys, and keeps a live restream healthy. One binary, self-hosted, no license keys.

How it works

A capture, start to finish

An HTTPS proxy runs on the phone. NULLDRM drives the real app to a channel, reads the licence exchange as it happens, and resolves the keys with your own CDM.

drm capture — rteone
PS C:\DRM-Decryption> ./bin/drm capture --app rte --channel rteone --auto-play
[*] Stopping any old appproxy...
[*] Pushing appproxy...
20:30:45 CA cert: /data/local/tmp/appproxy-ca.crt
20:30:45 capture → /data/local/tmp/appproxy_cap.json
20:30:45 DNS → [1.1.1.1:53 1.0.0.1:53 8.8.8.8:53]
20:30:45 listening on [::]:8080
[+] appproxy pid=12004; capture -> /data/local/tmp/appproxy_cap.json
[*] Setting HTTP proxy -> 127.0.0.1:8080 (was "null")
[*] Re-injecting system CA (Magisk)...
[+] System CA present in conscrypt
[*] Launching rte (package from module.yaml)…
[*] Auto-play RTE One…
[*] tap_ui "Live"/"Live tab, 2 out of 5" @ 324,2253
[*] tap Play @ 540,720
[+] player is PLAYING
[*] Waiting for license + PSSH + manifest…
    watch: .cache\appproxy-default.log
[+] Capture:
    pid: ••••••••••••
    mpd: https://dai.google.com/linear/dash/pa/event/••••/stream/••••
    license: https://widevine.entitlement.••••/wv/web/ModularDrm?schema=1.0&form=json
    pssh: AAAASnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACoiIG••••…
[+] key: ••••••••••••••••••••••••••••••••:••••••••••••••••••••••••••••••••
[+] session: outputs\rte\20261005-203112\session.json
[*] Closing player…
[*] HTTP proxy cleared

Redacted above: the package id, licence account, programme id, PSSH and keys. Those belong to your device and your subscription — NULLDRM keeps them in a local file that is never committed.

Nothing is cracked

Keys come from a Widevine device file you supply. NULLDRM automates the request flow a normal client already performs — it does not break the DRM.

Catalogue or phone

Some apps publish a playback catalogue, so a channel resolves with no phone at all. Everything else goes through the on-device proxy.

Stale keys heal

Live keys rotate. The agent notices a dead channel, re-runs the capture on a phone and posts fresh credentials back to the restreamer.

Ways to run it

Start small, grow if you want to

Same binary in all three. You decide how much automation and how much cooperation.

On your desk

Run a capture when you need fresh material, decrypt locally, play it back. No server, nothing always-on.

  • One-shot captures
  • No VPS required

Server plus a phone

Host the restreamer so channels stay up. Leave a phone plugged into the agent and it refreshes keys on its own when something dies.

  • Dashboard and API on :8083
  • Agent watches health on a loop

Join a swarm

A host publishes the channel list. Contributors point agents at it and cover only the channels they actually subscribe to.

  • Nobody needs every platform
  • Any matching agent can heal a feed

That is the point of a swarm: distributed ownership. One person should not need every subscription. Many agents, many logins, one shared restream.

Quick start

Four commands

Go 1.25+ and Python 3.10+. A phone is only needed for the capture step.

# 1. build the one binary
git clone https://git.nulldrm.com/nulldrm/Null-DRM-Official
go -C apps/cli build -o ../../bin/drm .

# 2. the CDM helper
python -m venv .venv && .venv/bin/pip install -r apps/wvkey/requirements.txt

# 3. see which app modules are compiled in
./bin/drm modules

# 4. capture a channel
./bin/drm capture --app rte --channel rteone --auto-play --wvd data/device.wvd

A fresh clone ships no account ids, keys or hostnames — module code is public, its values are not. The quickstart walks through filling in your own, and the capture guide shows how to discover them for an app nobody has written a module for yet.

What is inside

One binary, a handful of parts

Everything ships as drm. Each subcommand is one of these.

PartWhat it does
drm capture Drives the phone through the on-device proxy and writes a session: manifest, PSSH, keys.
drm catalog Resolves a channel from a public playback catalogue, no phone involved.
drm serve Control plane: REST API, SQLite, dashboard, and the restream supervisor.
drm agent Polls the control plane, claims a free phone and refreshes dead channels.
drm proxy Builds and installs the on-device HTTPS proxy, and records unknown apps.
drm modules Lists the app modules this build contains and where each one reads its values.

An app module is a small Go package plus a local values file. Adding one means a new package and a single import line — no fork, no plugin runtime. See writing a module.

Source

git.nulldrm.com

Open source, free forever: no paid tiers, no licence keys, no feature gates. The official source is Forgejo at nulldrm/Null-DRM-Official.

—Stars
—Forks
—Issues
—Updated

Latest releases

Loading releases…