# syntax=docker/dockerfile:1.7 # # Multi-stage build with automatic signature discovery: # 1. base — PMS base image (source of the binary to analyze) # 2. discover — auto-discover hook patterns from the PMS binary # 3. builder — cross-compile the .so with zig (musl) + generated patterns # 4. runtime — layer onto lscr.io/linuxserver/plex with LD_PRELOAD wrapper # # Based on https://github.com/authrequest/Freeloader (AGPL-3.0-or-later). ARG PLEX_BASE_IMAGE=lscr.io/linuxserver/plex:latest # ── Stage 1: base (PMS image, used as source for discovery) ────────────── FROM ${PLEX_BASE_IMAGE} AS base # ── Stage 2: discover hook patterns from the PMS binary ───────────────── # Auto-discovers byte patterns by analyzing the PMS binary. If a pattern # can't be found, the build fails here — before compiling or shipping. FROM debian:bookworm-slim AS discover RUN apt-get update \ && apt-get install -y --no-install-recommends python3 python3-pip \ && pip3 install --break-system-packages capstone \ && rm -rf /var/lib/apt/lists/* COPY scripts/discover_patterns.py /tmp/discover_patterns.py COPY --from=base /usr/lib/plexmediaserver/ /tmp/plex/ RUN python3 /tmp/discover_patterns.py "/tmp/plex/Plex Media Server" \ -o /tmp/patterns_generated.h \ && cat /tmp/patterns_generated.h # ── Stage 3: build the musl .so ─────────────────────────────────────────── FROM debian:bookworm-slim AS builder ARG ZIG_VERSION=0.13.0 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates curl xz-utils \ && rm -rf /var/lib/apt/lists/* WORKDIR /src RUN mkdir -p /src/toolchain \ && curl -fsSL \ "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-x86_64-${ZIG_VERSION}.tar.xz" \ -o /tmp/zig.tar.xz \ && tar -C /src/toolchain --strip-components=1 -xf /tmp/zig.tar.xz \ && rm /tmp/zig.tar.xz ENV PATH="/src/toolchain:${PATH}" COPY Freeloader/build.sh ./ COPY Freeloader/src ./src COPY Freeloader/third_party ./third_party COPY --from=discover /tmp/patterns_generated.h ./src/patterns_generated.h RUN bash build.sh # ── Stage 4: runtime -- patch lscr.io/linuxserver/plex ──────────────────── FROM ${PLEX_BASE_IMAGE} AS runtime ARG PLEX_BASE_IMAGE ARG PATCH_VERSION=dev LABEL org.opencontainers.image.title="plexmediaserver-crack (linuxserver)" \ org.opencontainers.image.source="https://github.com/authrequest/Freeloader" \ org.opencontainers.image.licenses="AGPL-3.0-or-later" \ plex_patch.base="${PLEX_BASE_IMAGE}" \ plex_patch.version="${PATCH_VERSION}" RUN set -eux; \ PMS="/usr/lib/plexmediaserver/Plex Media Server"; \ PMS_LIB="/usr/lib/plexmediaserver/lib"; \ RUN_SCRIPT="/etc/s6-overlay/s6-rc.d/svc-plex/run"; \ [ -x "${PMS}" ] || { echo "patcher: missing ${PMS} in ${PLEX_BASE_IMAGE}"; exit 1; }; \ [ -d "${PMS_LIB}" ] || { echo "patcher: missing ${PMS_LIB}/ in ${PLEX_BASE_IMAGE}"; exit 1; }; \ [ -f "${RUN_SCRIPT}" ] || { echo "patcher: missing ${RUN_SCRIPT} in ${PLEX_BASE_IMAGE}"; exit 1; } COPY --from=builder /src/build/plexmediaserver_crack.so \ /usr/lib/plexmediaserver/lib/plexmediaserver_crack.so RUN chmod 0644 /usr/lib/plexmediaserver/lib/plexmediaserver_crack.so COPY wrapper.sh /usr/lib/plexmediaserver/plex-crack-wrapper.sh RUN chmod 0755 /usr/lib/plexmediaserver/plex-crack-wrapper.sh RUN set -eux; \ RUN_SCRIPT="/etc/s6-overlay/s6-rc.d/svc-plex/run"; \ cp "${RUN_SCRIPT}" "${RUN_SCRIPT}.orig"; \ printf '#!/usr/bin/with-contenv bash\nexec s6-setuidgid abc /usr/lib/plexmediaserver/plex-crack-wrapper.sh\n' \ > "${RUN_SCRIPT}"; \ chmod 0755 "${RUN_SCRIPT}"