339 lines
10 KiB
Markdown
339 lines
10 KiB
Markdown
# Plex Premium Hack
|
||
|
||
This repository contains a "mock" proxy that sits in your network and tricks Plex into thinking you have a Plex Premium
|
||
subscription.
|
||
|
||
### Requirements
|
||
|
||
- A router that **can redirect traffic** (i.e. OPNsense, pfSense, DD-WRT...)
|
||
- _(alternative) a DNS server that can redirect traffic (some apps won't work due to DNS pinning)_
|
||
- A reverse proxy (i.e. Traefik, Nginx, Caddy...)
|
||
- A Plex server (self-hosted)
|
||
|
||
### What works?
|
||
|
||
- Plexamp mobile (download mode)
|
||
- Plexamp Headless
|
||
|
||
## How to setup ?
|
||
|
||
Due to the nature of this hack, you'll have to :
|
||
|
||
- generate a new certificate authority (CA) for the proxy
|
||
- trust or patch the CA on clients and/or apps that will connect to your Plex server
|
||
|
||
### 1. Generate a new Certificate Authority (CA) and proxy certificate
|
||
|
||
```bash
|
||
# Generate a root CA
|
||
openssl genrsa -out plexhackCA.key 4096
|
||
# Create a self-signed root CA certificate
|
||
openssl req -x509 -new -nodes -key plexhackCA.key -sha256 -days 3650 -out plexhackCA.pem -subj "/C=US/ST=SomeState/L=SomeCity/O=PlexHack/OU=PlexHack/CN=PlexHackCA"
|
||
|
||
# Generate private key for proxy
|
||
openssl genrsa -out plexhackproxy.key 2048
|
||
|
||
# Create a config file for the proxy certificate (SANs)
|
||
cat > plexhacksan.cnf <<EOL
|
||
[req]
|
||
distinguished_name = req_distinguished_name
|
||
req_extensions = v3_req
|
||
prompt = no
|
||
|
||
[req_distinguished_name]
|
||
C = US
|
||
ST = SomeState
|
||
L = SomeCity
|
||
O = PlexHack
|
||
OU = PlexHack
|
||
CN = plex.tv
|
||
|
||
[v3_req]
|
||
subjectAltName = @alt_names
|
||
|
||
[alt_names]
|
||
DNS.1 = plex.tv
|
||
DNS.2 = *.plex.tv
|
||
DNS.3 = *.provider.plex.tv
|
||
|
||
EOL
|
||
|
||
# Create a certificate signing request (CSR) using the SAN config
|
||
openssl req -new -key plexhackproxy.key -out plexhackproxy.csr -config plexhacksan.cnf
|
||
|
||
# Sign the CSR with your root CA to create the proxy certificate
|
||
openssl x509 -req -in plexhackproxy.csr -CA plexhackCA.pem -CAkey plexhackCA.key -CAcreateserial -out plexhackproxy.crt -days 365 -sha256 -extfile plexhacksan.cnf -extensions v3_req
|
||
```
|
||
|
||
Now you should have two files `plexhackproxy.crt` and `plexhackproxy.key` that you will use in your reverse proxy.
|
||
You should also have the `plexhackCA.crt` file that you will need to trust on your clients.
|
||
|
||
> [!IMPORTANT]
|
||
> You will need to trust the `plexhackCA.crt` certificate on every device that
|
||
> will connect to your Plex server (i.e. mobile, desktop, smart TV...).
|
||
> How to do this depends on the device and OS, you will need to search for instructions
|
||
> specific to your device.
|
||
|
||
### 2. Setup reverse proxy
|
||
|
||
In my case I'm using Traefik, so here is an example configuration :
|
||
|
||
```yaml
|
||
tls:
|
||
certificates:
|
||
# use certificates generated in step 1
|
||
- certFile: /etc/traefik/ssl/custom/plexhackproxy.crt
|
||
keyFile: /etc/traefik/ssl/custom/plexhackproxy.key
|
||
|
||
http:
|
||
routers:
|
||
plex:
|
||
entryPoints:
|
||
- https
|
||
service: plex
|
||
rule: Host(`plex.<your-domain>.com`)
|
||
# you may want to use TLS here too (don't use the custom CA cert generated in step 1)
|
||
plex_proxy:
|
||
entryPoints:
|
||
- https
|
||
service: plex_proxy
|
||
rule: HostRegexp(`^.+\.plex\.tv$`) || Host(`plex.tv`)
|
||
tls: { }
|
||
|
||
services:
|
||
plex:
|
||
loadBalancer:
|
||
servers:
|
||
- url: http://<plex-machine-ip>:32400
|
||
plex_proxy:
|
||
loadBalancer:
|
||
servers:
|
||
- url: http://<machine-where-proxy-is>:8000
|
||
```
|
||
|
||
### 3. Redirect traffic
|
||
|
||
For this to work we need to redirect the domain `clients.plex.tv` and `plex.tv` to our proxy.
|
||
This is easily done if you own a router that can do this but might be tricky if you don't.
|
||
> [!IMPORTANT]
|
||
> Mobile/desktop apps tends to use hardcoded DNS servers so if you don't have a router that can redirect traffic, you
|
||
> will not be able to use this hack.
|
||
> It might be possible to patch the app to use a custom DNS server but the apps are usually obfuscated and it's not easy
|
||
> to do so.
|
||
|
||
#### OPNsense / pfSense
|
||
|
||
First, find the IP address behind the plex domains.
|
||
|
||
```bash
|
||
dig clients.plex.tv +short
|
||
# 172.64.151.205
|
||
# 104.18.36.51
|
||
|
||
dig plex.tv +short
|
||
# 52.17.59.150
|
||
# 52.49.56.127
|
||
|
||
dig features.plex.tv +short
|
||
# global-latency.plex.bz. -> we can ignore this one it points to the 3 IPs below
|
||
# 34.246.123.195
|
||
# 52.210.35.163
|
||
# 54.216.30.15
|
||
```
|
||
|
||
Then go into `Firewall` > `Aliases` and create two aliases:
|
||
|
||
- `plex_ips`
|
||
- Type: Host(s)
|
||
- Content: <the IPs you found above>
|
||
- `plex_do_not_proxy`
|
||
- Type: Host(s)
|
||
- Content: <your plex server IP> and <your proxy server IP>
|
||
|
||
Then go into `Firewall` > `NAT` > `Port Forward` and create a new rule:
|
||
|
||
- Interface: `LAN`
|
||
- Protocol: `TCP`
|
||
- Source / Invert: [☑️]
|
||
- Source: *(select alias)* `plex_do_not_proxy`
|
||
- Source Port Range: `any`
|
||
- Destination: *(select alias)* `plex_ips`
|
||
- Destination Port Range: `443`
|
||
- Redirect Target IP: `<your proxy server IP>`
|
||
- Redirect Target Port: `443`
|
||
|
||
Finally go to `Firewall` > `NAT` > `Outbound` and create a new rule *(select Hybrid mode if needed)*:
|
||
|
||
- Interface: `LAN`
|
||
- TCP/IP Version: `IPv4`
|
||
- Protocol: `any`
|
||
- Source address: `any`
|
||
- Destination address: <your proxy server IP>
|
||
- Destination port : `443`
|
||
- Translation / target: `Interface address`
|
||
|
||
##### Test the redirection
|
||
|
||
Now if you try to go to `https://clients.plex.tv/proxy` you should see a JSON response along the lines of :
|
||
|
||
```json
|
||
{
|
||
"status": "OK, Plex Pass features proxy enabled"
|
||
}
|
||
```
|
||
|
||
If you see the Plex "Oops, 404" page then something is wrong with your redirection or proxy.
|
||
|
||
## Patch Plexamp
|
||
|
||
> [!IMPORTANT]
|
||
> You'll need to have the official PlexAmp app installed on your device for this to work.
|
||
|
||
You can use ADB to extract the APK from your device:
|
||
|
||
```bash
|
||
# Execute this from the root of the cloned repo
|
||
# Also make sure you have adb installed and your device connected
|
||
mkdir extracted_apks && cd extracted_apks
|
||
for apk in $(adb shell pm path tv.plex.labs.plexamp | sed 's/package://'); do
|
||
adb pull "$apk" .
|
||
done
|
||
```
|
||
|
||
> [!NOTE]
|
||
> You might be able to download the APK from some websites but it's safer to extract it from your own device.
|
||
|
||
You'll end up with something like this in the `extracted_apks` folder:
|
||
|
||
```
|
||
.
|
||
├── base.apk
|
||
├── split_config.arm64_v8a.apk
|
||
├── split_config.de.apk
|
||
├── split_config.fr.apk
|
||
├── split_config.it.apk
|
||
└── split_config.xxxhdpi.apk
|
||
```
|
||
|
||
Then you need to patch the `cacert.pem` file inside the `base.apk` to add the `plexhackCA.crt` certificate generated in
|
||
step 1 and re-sign all the APKs.
|
||
_This might sound harder than it is, just follow these steps_:
|
||
|
||
```bash
|
||
# 1. Extract the existing cacert.pem from base.apk
|
||
unzip base.apk assets/cacert.pem -d ./
|
||
|
||
# 2. Append your custom CA cert
|
||
echo -e "\nPlexHack" >> assets/cacert.pem
|
||
echo -e "==================================" >> assets/cacert.pem
|
||
cat ../certs/plexhackCA.pem >> assets/cacert.pem
|
||
|
||
# 3. Remove old cacert.pem and add the new one (with no compression)
|
||
zip -d base.apk assets/cacert.pem
|
||
zip -X0 base.apk assets/cacert.pem
|
||
|
||
# 4. Remove existing signatures from ALL APKs (base + splits)
|
||
for f in base.apk split_config.*.apk; do
|
||
zip -d "$f" 'META-INF/*'
|
||
done
|
||
|
||
# 5. Generate a keystore if you don’t already have one
|
||
mkdir -p ../keystores
|
||
# This will prompt you for some info, you can put whatever you want here and enter "yes" at the end
|
||
# WARNING: Take note of the password you enter here as you'll need it to sign the APKs
|
||
keytool -genkey -v -keystore ../keystores/plexamphack.keystore -alias plexamphack -keyalg RSA -keysize 2048 -validity 10000
|
||
|
||
# 6. Sign ALL APKs with the same key
|
||
for f in base.apk split_config.*.apk; do
|
||
apksigner sign --ks ../keystores/plexamphack.keystore "$f"
|
||
done
|
||
```
|
||
|
||
You can now install the modified APK on your Android device.
|
||
|
||
```bash
|
||
# Make sure to uninstall the official PlexAmp app first
|
||
adb install-multiple base.apk split_config.*.apk
|
||
```
|
||
|
||
## Patch Plexamp Headless
|
||
|
||
```bash
|
||
# Execute this from the root of the cloned repo
|
||
mkdir plexamp_headless && cd plexamp_headless
|
||
|
||
# Download and extract Plexamp Headless
|
||
wget --no-check-certificate https://plexamp.plex.tv/headless/Plexamp-Linux-headless-v4.12.4.tar.bz2 -O plexamp-headless.tar.bz2
|
||
tar -xvf plexamp-headless.tar.bz2 && rm plexamp-headless.tar.bz2
|
||
mv plexamp/* ./ && rmdir plexamp
|
||
|
||
# Add the custom CA cert to the cacert.pem file
|
||
echo -e "\nPlexHack" >> cacert.pem
|
||
echo -e "==================================" >> cacert.pem
|
||
cat ../certs/plexhackCA.pem >> cacert.pem # you might have to adjust the path here if on a different machine
|
||
|
||
# Now you can run Plexamp Headless with the custom CA cert
|
||
node js/index.js
|
||
|
||
# (optional) You can also setup the systemd service included
|
||
mv plexamp.service /etc/systemd/system/
|
||
systemctl daemon-reload
|
||
systemctl enable --now plexamp # to start at boot and start now
|
||
```
|
||
|
||
### Configure Plexamp Headless
|
||
|
||
Once started I recommend using these settings for optimal experience:
|
||
|
||
```bash
|
||
# Do not mixdown to stereo (val: true/false)
|
||
echo "Bfalse" > ${HOME}/.local/share/Plexamp/Settings/%40Plexamp%3Asettings%3AaudioMixdownToStereo
|
||
|
||
# Set cache size to 512MB (val: 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072)
|
||
echo "N512" > ${HOME}/.local/share/Plexamp/Settings/%40Plexamp%3Asettings%3AcacheSize
|
||
|
||
# Set how many songs to precache on WiFi (val: 0/5/10/15/20/25/40)
|
||
echo "N0" > ${HOME}/.local/share/Plexamp/Settings/%40Plexamp%3Asettings%3AcachingWiFi
|
||
|
||
# Set player name (Marantz here)
|
||
echo "SMarantz" > ${HOME}/.local/share/Plexamp/Settings/%40Plexamp%3Asettings%3AplayerName
|
||
|
||
# Set precache network speed to 10Mbps (val: 0/1/5/10/50/100)
|
||
echo "N10" > ${HOME}/.local/share/Plexamp/Settings/%40Plexamp%3Asettings%3AprecacheNetworkSpeed
|
||
|
||
# Set sample rate conversion quality to highest (64 point sinc) (val: 0-4)
|
||
echo "N4" > ${HOME}/.local/share/Plexamp/Settings/%40Plexamp%3Asettings%3AsampleRateConversionQuality
|
||
|
||
# Set sample rate matching to "Strict" (val: 0-2)
|
||
echo "N2" > ${HOME}/.local/share/Plexamp/Settings/%40Plexamp%3Asettings%3AsampleRateMatching
|
||
```
|
||
|
||
_I don't recommend accessing the Plexamp Headless webUI as it might cause issues with the hack (not tested though)._
|
||
|
||
#### Setup output device
|
||
|
||
I had to manually overwrite the default connection as I wanted to output to a S/PDIF device, check your devices with
|
||
`aplay -l` :
|
||
|
||
```
|
||
**** List of PLAYBACK Hardware Devices ****
|
||
card 1: PCH [HDA Intel PCH], device 0: ALCS1200A Analog [ALCS1200A Analog]
|
||
Subdevices: 1/1
|
||
Subdevice #0: subdevice #0
|
||
```
|
||
|
||
Create the file ``/etc/asound.conf`` and modify it to match your device, this worked for me:
|
||
|
||
```
|
||
pcm.!default {
|
||
type plug
|
||
slave {
|
||
pcm "iec958:CARD=PCH,DEV=0"
|
||
}
|
||
}
|
||
|
||
ctl.!default {
|
||
type hw
|
||
card PCH
|
||
}
|
||
``` |