Parent
5350515c5d
révision
73037d5ab9
4 fichiers modifiés avec 52 ajouts et 52 suppressions
|
@ -3,7 +3,7 @@
|
|||
|
||||
But Widevine's least secure security level, L3, as used in most browsers and PCs, is implemented 100% in software (i.e no hardware TEEs), thereby making it reversible and bypassable.
|
||||
|
||||
This Chrome extension demonstates how it's possible to bypass Widevine DRM by hijacking calls to the browser's [Encrypted Media Extensions (EME)](https://www.html5rocks.com/en/tutorials/eme/basics) and decrypting all Widevine content keys transferred - effectively turning it into a clearkey DRM.
|
||||
This Chrome extension demonstrates how it's possible to bypass Widevine DRM by hijacking calls to the browser's [Encrypted Media Extensions (EME)](https://www.html5rocks.com/en/tutorials/eme/basics) and decrypting all Widevine content keys transferred - effectively turning it into a clearkey DRM.
|
||||
|
||||
## Usage
|
||||
To see this concept in action, just load the extension in Developer Mode and browse to any website that plays Widevine-protected content, such as https://bitmovin.com/demos/drm _[Update: link got broken?]_.
|
||||
|
@ -35,5 +35,5 @@ Some reversing job on that binary can then be done to extract the secret keys an
|
|||
## Why
|
||||
This PoC was done to further show that code obfuscation, anti-debugging tricks, whitebox cryptography algorithms and other methods of security-by-obscurity will eventually by defeated anyway, and are, in a way, pointless.
|
||||
|
||||
## Legal Desclaimer
|
||||
## Legal Disclaimer
|
||||
This is for educational purposes only. Downloading copyrighted materials from streaming services may violate their Terms of Service. **Use at your own risk.**
|
||||
|
|
|
@ -166,21 +166,21 @@ function wordToByteArray(wordArray)
|
|||
// byte array to CryptoJS format
|
||||
function arrayToWordArray(u8Array)
|
||||
{
|
||||
var words = [], i = 0, len = u8Array.length;
|
||||
var words = [], i = 0, len = u8Array.length;
|
||||
|
||||
while (i < len) {
|
||||
words.push(
|
||||
(u8Array[i++] << 24) |
|
||||
(u8Array[i++] << 16) |
|
||||
(u8Array[i++] << 8) |
|
||||
(u8Array[i++])
|
||||
);
|
||||
}
|
||||
while (i < len) {
|
||||
words.push(
|
||||
(u8Array[i++] << 24) |
|
||||
(u8Array[i++] << 16) |
|
||||
(u8Array[i++] << 8) |
|
||||
(u8Array[i++])
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
sigBytes: len,
|
||||
words: words
|
||||
};
|
||||
return {
|
||||
sigBytes: len,
|
||||
words: words
|
||||
};
|
||||
}
|
||||
|
||||
const toHexString = bytes => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
|
||||
|
@ -209,4 +209,4 @@ function PEM2Binary(pem)
|
|||
return bytes.buffer;
|
||||
}
|
||||
|
||||
}());
|
||||
}());
|
||||
|
|
|
@ -2,9 +2,9 @@ injectScripts();
|
|||
|
||||
async function injectScripts()
|
||||
{
|
||||
await injectScript('lib/pbf.3.0.5.min.js');
|
||||
await injectScript('lib/cryptojs-aes_0.2.0.min.js');
|
||||
await injectScript('protobuf-generated/license_protocol.proto.js');
|
||||
await injectScript('lib/pbf.3.0.5.min.js');
|
||||
await injectScript('lib/cryptojs-aes_0.2.0.min.js');
|
||||
await injectScript('protobuf-generated/license_protocol.proto.js');
|
||||
|
||||
|
||||
await injectScript('content_key_decryption.js');
|
||||
|
@ -13,14 +13,14 @@ async function injectScripts()
|
|||
|
||||
function injectScript(scriptName)
|
||||
{
|
||||
return new Promise(function(resolve, reject)
|
||||
{
|
||||
var s = document.createElement('script');
|
||||
s.src = chrome.extension.getURL(scriptName);
|
||||
s.onload = function() {
|
||||
this.parentNode.removeChild(this);
|
||||
resolve(true);
|
||||
};
|
||||
(document.head||document.documentElement).appendChild(s);
|
||||
});
|
||||
}
|
||||
return new Promise(function(resolve, reject)
|
||||
{
|
||||
var s = document.createElement('script');
|
||||
s.src = chrome.extension.getURL(scriptName);
|
||||
s.onload = function() {
|
||||
this.parentNode.removeChild(this);
|
||||
resolve(true);
|
||||
};
|
||||
(document.head||document.documentElement).appendChild(s);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Widivine Decryptor",
|
||||
"name": "Widevine Decryptor",
|
||||
"short_name": "WidevineDecryptor",
|
||||
"description": "Decrypts and logs media keys from websites that use Widivine DRM",
|
||||
"description": "Decrypts and logs media keys from websites that use Widevine DRM",
|
||||
"version": "1.0.0",
|
||||
"permissions":
|
||||
"permissions":
|
||||
[
|
||||
|
||||
|
||||
],
|
||||
"icons":
|
||||
{
|
||||
|
||||
},
|
||||
"browser_action": {
|
||||
|
||||
},
|
||||
|
||||
"content_scripts":
|
||||
[
|
||||
{
|
||||
"matches": ["https://*/*"],
|
||||
"js": ["content_script.js"],
|
||||
"icons":
|
||||
{
|
||||
|
||||
},
|
||||
"browser_action": {
|
||||
|
||||
},
|
||||
"content_scripts":
|
||||
[
|
||||
{
|
||||
"matches": ["https://*/*"],
|
||||
"js": ["content_script.js"],
|
||||
"css": [],
|
||||
"run_at": "document_start"
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": ["content_key_decryption.js", "eme_interception.js", "lib/*", "protobuf-generated/*"]
|
||||
}
|
||||
"run_at": "document_start",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": ["content_key_decryption.js", "eme_interception.js", "lib/*", "protobuf-generated/*"]
|
||||
}
|
||||
|
|
Référencer dans un nouveau ticket