I-330 - Posts

Posted: April 05, 2023 by I-330

Breaking Widevine [Ep. 01]

Preface :

Have you ever watched a Netflix video and thought to yourself "I really wish I could just download this?" Well I would never because I despise the idea of violating intellectual property laws ;3. However, if someone were to have that goal in mind, the first thing they'd have to bypass is Googles infamous DRM software widevine.

In collaboration with amazing computer engineer Alex Wilson, we've been able to break apart much of widevine's features and exploit its implementation inside of the most superior web browser... Firefox! Firefox not only has the most open platform for poking and prodding, it also gives easy access to all of the tools it uses to interact with the widevine libraries. Firefox also has a wonderful 3rd party tool called serachfox which makes searching through source code super simple!

Analyzing Widevine :

Before starting with the brutalities, the first step was to figure out how firefox implements widevine in the first place. Knowing this will help later when trying to exploit it. Based on the limited analysis we've done on firefox's widevine implementation, it seems that once the video is decrypted, it is just as accessible as any regular video embed. This means that in theory, all that's needed in order to retrieve the original video data is to intercept the frames as they are decoded by widevine.

Now, while intercepting decrypted video frames does help to bypass a large part of the decoding process, it does have it's own draw backs. Firstly, you still need to worry about adaptive bit-rate, and secondly you will need to figure out a way to request more frames from the video server than typical during regular video playback.

Breaking Widevine in Half:

Of course an idea is only half of the battle, implementing it is another beast all together. Obviously mozilla, is going to put in some barriers to prevent the user from simply capturing frame data right?... right? NOPE! With a couple lines of code you can bypass almost every restriction mozilla has built to prevent the user from grabbing frames.

The first hurdle to jump is firefox's restriction on recording DRM restricted video. While you might think this would be difficult to do, it's really just as simple as un-commenting a single if statement. Seriously, the only think keeping you from sharing your netflix stream with friends on discord is a single if statement.

// /dom/html/htmlmediaelement.cpp#3796
// prevent capturing restricted video
if (acapturetype == streamcapturetype::capture_all_tracks && containsrestrictedcontent()) {
  return false;
}
return true;

While that's cool and all, you're still going to be recording heavily encoded and video with heavy artifacting. If only there were an easy way to capture the frames immediately after they're decoded. If only firefox had a built in method specifically for capturing the frames of DRM protected content... Oh wait, they do! In dom/media/gmp/ChromiumCDMChild.cpp, they give you all the tools you need to grab frame info, codecs, and save every frame decoded by Widevine.

Below is a snip of code which can capture, write, and format captured video data directly from widevine and append it to a file as raw yuv420 video. While I'm aware that this isn't a perfect appproach, it's a big leap towards high res widevine video capture as it doesn't distinguish between L1, L2, or L3 encryption.

WidevineVideoFrame frame;
cdm::Status rv = mCDM->DecryptAndDecodeFrame(input, &frame);

//====[Widevine Frame Extraction]=====|
// Make sure to build/run with file sandboxing disabled

printf("Decrypted frame! w:%i h:%i f:%i\n", frame.Size().width, frame.Size().height, frame.Format());
printf("\tOffsets - Y:%i U:%i V:%i\n", frame.PlaneOffset(cdm::kYPlane), frame.PlaneOffset(cdm::kUPlane), frame.PlaneOffset(cdm::kVPlane));
printf("\tStride - Y:%i U:%i V:%i\n", frame.Stride(cdm::kYPlane), frame.Stride(cdm::kUPlane), frame.Stride(cdm::kVPlane));

if (frame.Size().width > 0) {
  FILE *fptr;
  fptr = fopen("/tmp/widevine_frame.yuv", "ab");
  fwrite(frame.FrameBuffer()->Data(), frame.FrameBuffer()->Size(), 1, fptr);
  fclose(fptr);
}
//====[End of Extraction]=============|

While it's not a perfect implementation by any means, there seems to be many ways to further break firefox's implementation of widevine, next on the list being audio extraction and rapid frame requesting. If those two hurdles can be cleared, we'll be one step closer to the dream of right-click downloading DRM protected content.