SReverseby Simpa Labs

DRM & Media

How ExoPlayer uses Android MediaDrm

ExoPlayer is the playback and network stack; MediaDrm is the DRM underneath. The reconstructable part is the request flow.

Trace the player's request chain

Media3 ExoPlayer uses Android's MediaDrm API for protected playback, but the app controls the network around it: entitlement, playback token, manifest URL, DRM configuration, license URL and request headers. Those calls explain most failures before a license reaches the device DRM module, so they are where the reconstruction work sits.

Find the DRM configuration

Find where the app builds its MediaItem or DrmConfiguration and record the scheme UUID, the manifest URI, the license URI, the multi-session setting and the request properties. A custom DrmSessionManager or callback can replace the default request handling, so follow those classes when the traffic differs from a standard ExoPlayer setup.

jadx -d out app.apk
grep -rloE 'MediaDrm|DrmConfiguration|MediaItem.Builder|HttpMediaDrmCallback' out/sources | sort -u

The manifest carries protection-system data. Widevine uses the scheme UUID edef8ba9-79d6-4ace-a3c8-27dcd51d21ed, and the license request passes through a partner-operated proxy per Google's Widevine architecture. That means the license URL is a proxy, not Google's service directly, and the proxy applies the operator's business rules before the request reaches Widevine.

Capture the license exchange

Hook MediaDrm to see the request and response at the boundary. getKeyRequest returns the PSSH plus the configuration the app posts to the license URI, and provideKeyResponse returns the device-bound license. Observe the HTTP exchange over the proxy as well; the two together separate a network failure from a DRM failure.

Java.perform(function () {
  var M = Java.use('android.media.MediaDrm');
  M.getKeyRequest.implementation = function (sessionId, data, mimeType, keyType, opts) {
    var out = this.getKeyRequest(sessionId, data, mimeType, keyType, opts);
    console.log('key request type', keyType, 'mime', mimeType);
    return out;
  };
});

Separate server state from device DRM

  • Entitlement confirms the account can play the title.
  • Playback APIs return a manifest URL and short-lived tokens.
  • The manifest describes the streams and the protection metadata.
  • The DRM client creates a key request from that metadata.
  • The license proxy checks policy and returns a device-bound response.

Each step is a separate network call, and each one can fail for a different reason. Reconstruct the whole chain in order, because a failure in entitlement means the client never reaches the manifest, and a failure in the manifest means the client never builds a key request.

Choose the next layer by signal

SignalWhat it points toNext check
401 or 403 at entitlement or license proxyAccount state, token, cookie or request signing.Trace the entitlement and token flow, then the request headers.
A Media3 DRM error after a good HTTP responseScheme, session, policy or protection data.Check the pssh, the scheme UUID and the supported security level.
No key request sentThe manifest did not reach the DRM client.Confirm the manifest and any proxy that edits it.
License denied on your build, works in the appDevice-bound key or a proxy policy.Check the security level and what the query proves.

The device-bound constraint

Widevine security levels matter. A software (L3) license can often be reproduced outside the device; a hardware (L1) key is device-bound and CopyProtection media can block capture and screen recording. That is a deployment requirement, not a reversing problem. A ported client cannot produce an L1 license without the device key, so the analysis has to state which level the content requires before promising a server-side reproduction.

Read the pssh and the license response

The manifest carries the protection metadata. For a DASH stream that is a pssh box inside an init segment; for an HLS stream it is a key attribute in the playlist. Extract it and read the scheme it names, because that tells you which DRM system the stream uses before you look at the app.

# find the pssh box in an init segment or a plain stream
grep -aob 'pssh' sample.mp4 | head
xxd -l 48 sample.mp4 | head
# and confirm the scheme UUID that the box carries

The key request the app posts is built from that pssh plus a device-wide session. The license that comes back is bound to that device and session, not to the pssh alone. So a license you captured from one device will not validate on another, and that is expected rather than a fault in your reconstruction.

When the app builds a second request with the same pssh and the server rejects it, compare the session data and the policy returned in the first response. The pssh is a constant for a given title; the session and the key are not.

Reviewed 30 August 2026 · SReverse research desk

Related

Start a project

Send the full APK

Send the full APK. We review the application and quote its complete API reconstruction.

Projects start at $120. Most are delivered in 24 to 72 hours.

Start your full APK reconstruction

Send the full APK

Projects start at $120. Choose WhatsApp or email, then attach the APK in the app that opens. We reply within one hour with the next step and send the fixed quote after review.

Want us to contact you?