First we must ask ourselves, what is Widevine?
- DRM solution acquired by google in 2010
- Three levels, L1, L2, L3
- L1 (in android) is done inside the Trusted Execution Environment (TEE), so hardware dependant
- and is often required for HD decryption
- L2 doesn't exist in android
- L3 is software based
- L1 (in android) is done inside the Trusted Execution Environment (TEE), so hardware dependant
Terminology
- License Request: DRM fuckery talks to license server to get content keys
- ex license server: youtube.com/youtubei/v1/player/get_drm_license
- DASH: Dynamic adaptive streaming over HTTP
I think this is basically the spec for an MPD manifest, which most streaming sites using widevine use?
- PSSH: Protection System Specific Header
- part of a license request
- MPD: Media Presentation Description
- I think this is an xml manifest that says what the content URLs are, supposed to define pssh, and maybe license servers
- PSSH: Protection System Specific Header
- CDM
Open Quetions
- the L1/L3 device keys are genrated by the Root of Trust 128 AES device key, where does that come from (especially in an emulator?)
- Can we get the device key and generate the L1/L3 keys ourselves?
Prior Art
I did the "make it kinda work" half before the "learn how it's supposed to work" half and I must say, cargo cult script kiddie shit sucks. Did work though.
Research
The explinations above are me butchering these
- Exploring Widevine for Fun and Profit from Gwendal Patat, Mohamed Sabt, and Pierre-Alain Fouque
- Your DRM Can Watch You Too: Exploring the Privacy Implications of Browsers (mis)Implementations of Widevine EME from Gwendal Patat, Mohamed Sabt, and Pierre-Alain Fouque
Application
I'm mostly summarizing these after a fair amount of trial and an unfair amount of error
- Mo Ismailzai has a blog post that's close to what I did
- cedric8528 on VideoHelp has a post
- [ss]vegeta on VideoHelp had helpful tips for using the dumper
- stabbedbybrick on VideoHelp showed how to get youtube keys
Actually doing it
Get L3 DDM
Tools
- android emulator running Oreo x86 Android 8.0 (Google APIs)
- 10/Q didn't work, and without google APIs won't have chrome so we won't have widevine support I think the internet said Google Play vs Google APIs won't work but I don't remember why.
- https://github.com/frida/frida/releases/
- show more, find frida-server-whatever
- https://github.com/Diazole/dumper
steps
- run emulator
- install via studio, or maybe something like
sdkmanager "platform-tools" "platforms;android-26" sdkmanager "system-images;android-26;google_apis;x86" sdkmanager --licenses
emulator -avd Medium_Phone_API_26 -wipe-data -netdelay none -netspeed full
- install via studio, or maybe something like
- push frida-server to /sdcard, move to
/data/local/tmp
& chmod +x - run frida-server as root
- find libwvhidl.so, copy to somewhere readable and pull it
- Look at it with
strings
, the functions names you want are between_lcc43
and_ZN6wvoec333OEMCrypto_Level3AndroidFileSystem4ReadEPKcPvj
(Second occourance of OEMCrypto_Level3 in the file) - put those function names in dumper/Helpers/scripts.sh KNOWN_DYNAMIC_FUNCTION_NAMES
- run dumper, this will listen in on those functions for drm functions and log keys
- I had a lot of issues with this I think it just started working once I went old enough? Don't really remmeber
- Open DRM in a chrome tab in the phone
adb shell am start -n com.android.chrome/com.google.android.apps.chrome.Main -d "https://bitmovin.com/demos/drm"
- You will have to click accept a few times or whatever
- Hope dumper writes
key_dumps/Android\ Emulator\ */private_keys/*/*/client_id.bin
andprivate_key.pem
These steps are fairly well documented in the first two prior art posts.
Something something youtube
Knowing anything about widevine or DASH would really have helped here.
Tools
- https://github.com/medvm/widevine_keys
- https://forum.videohelp.com/threads/408556-How-to-decrypt-YouTube-Movies-TV-files/page2#post2687354
- copy it into a script in widivine_keys directory
- https://github.com/axiomatic-systems/Bento4
Steps
cp dumper/key_dumps/*/private_keys/*/*/client_id.bin widevine_keys/cdm/devices/device_client_id_blob
cp dumper/key_dumps/*/private_keys/*/*/private_key.pem widevine_keys/cdm/devices/device_private_key
- open youtube video in browser, find keyserver request in network
- youtube keyserver: https://www.youtube.com/youtubei/v1/player/get_drm_license
- copy request, put into widivine_keys/headers.py
- Put keyserver url in stabbedbybrick's script
- run stabbedbybrick's script, get keys output
yt-dlp --allow-unplayable-formats https://www.youtube.com/watch?v=CYV9LmANWOQ
./mp4decrypt <--key whatever>... encrypted.mp4 decrypted.mp4
ffmpeg -i decrypted_video.mp4 -i decrypted_audio.m4a -vcodec copy -acodec copy decrypted_bundle.mp4
Making this not fucking suck to do
Expectations
- yt-dlp interface that handles this stupid stuff with no manual steps