let e = "/api/ping/", i = "/api/drm/";
function n(t)
{
return [...new Uint8Array(t)].map((t => t.toString(16).padStart(2, "0"))).join("")
}
function s(t, e)
{
let r = new Uint8Array(t.length);
for (let i = 0; i < t.length; i++) {
r[i] = t[i]^e[i];
}
return r
}
class a extends t.DefaultConfig.loader
{
constructor(t)
{
super (t);
var r = this.load.bind(this);
this.load = function (t, a, o)
{
if (t && t.url.startsWith("key://"))
{
let r = t.url.substr(6);
t.url = e;
var l = o.onSuccess;
o.onSuccess = function (t, e, a)
{
(async function (t)
{
let e = await async function ()
{
let t = new Uint8Array(16);
crypto.getRandomValues(t);
let e = n(t.buffer) + Date.now() + Math.random();
return new Uint8Array((await async function (t)
{
const e = (new TextEncoder).encode(t);
return await crypto.subtle.digest("SHA-256", e)
}
(e)).slice(0, 16))
}();
var r = new URLSearchParams;
r.append("h", n(e.buffer)), r.append("id", t);
var a = {
method : "POST", headers : {
"Content-Type" : "application/x-www-form-urlencoded"
},
body : r
};
let o = await fetch(i, a), l = await o.arrayBuffer();
if (32 !== l.byteLength) {
throw new Error("Invalid response");
}
let u = new Uint8Array(l.slice(0, 16)), c = new Uint8Array(l.slice(16,
32));
return s(s(u, e), c);
})(r).then((t => {
l({
data : t.buffer
}, e, a)
}))
}
}
r(t, a, o)
}
}
}
显然,s(t,e)是一个按位异或,return s(s(u, e), c);可能为解密密钥
let u = new Uint8Array(l.slice(0, 16)), c = new Uint8Array(l.slice(16, 32)); 处可看出32byte密钥的前半部分为u,后半部分为c
var r = new URLSearchParams; r.append("h", n(e.buffer)), r.append("id", t); 处可看出e为URL参数h,在fiddler的/api/drm/处可找到
u=08a5e6c2c261a8acb4d79c49af160a3a
c=da4e5ceae16fed46eb6f498c9b63d53b
e=7b10311e6e310f0df068d9ede10475a8
解密密钥为u异或e异或c= a9fb8b364d3f4ae7afd00c28d571aaa9
然后找了个现成的ts解密工具(ts助手)解密得到mp4,播放mp4视频得到flag{like_sub_52tube}