最近有空在处理视频去水印的需求,通过观察调试和github资料最终成功完成🍉视频的无水印视频链接。本次分享一下逆向过程。
经过比对,某音、某条、某🍉前端加密、混淆技术基本相似,同时他们都是使用的xgplayer,基本上很多某音视频、某条视频链接都可以转成🍉视频链接(经过我测试的很多都能转,目前还没着重处理这块儿,后期有机会稳定了再分享)。
JSVMP 全称 Virtual Machine based code Protection for JavaScript,即 JS 代码虚拟化保护方案。
JSVMP 的概念最早应该是由西北大学2015级硕士研究生匡开圆,在其2018年的学位论文中提出的,论文标题为:《基于 WebAssembly 的 JavaScript 代码虚拟化保护方法研究与实现》,同年还申请了国家专利,专利名称:《一种基于前端字节码技术的 JavaScript 虚拟化保护方法》,网上可以直接搜到。
我们访问一个🍉视频url,进入后,开启开发者工具,然后清空localstoreage、cookie等。
接着在url上复制详情ID,如下图的框框里的7440408860818407948。然后,打开网络,我们需要过滤出所有7440408860818407948相关的请求,因此就在过滤那里输入7440408860818407948(具体的ID)。在接着,就刷新网页。
在下面的图里,我全出了3个相关的请求,从这3个请求,我们能看到__ac_signature、__ac_nonce等🏊参数生成的情况。因此我一个个来分析。
第一个请求,会得到__ac_nonce
,这个值会在响应的cookie拿到,同时这个请求得到的是虚拟代码$_jsvmprt
和调用sign生成__ac_nonce
,下面第一张图可以看到返回了两段脚本代码。
第一个脚本就是虚拟化代码。因为虚拟化技术,因此核心的sign 的操作的对象、函数代码都被隐藏了。
第二个脚本就是调用sign,我们来美化代码看下:
<script>
function _f1(e, t) {
if ("string" != typeof t) return;
var o, n = e + "=",
r = t.split(/[;&]/);
for (var e = 0; e < r.length; e++) {
for (o = r[e];
" " === o.charAt(0);) o = o.substring(1, o.length);
if (0 === o.indexOf(n)) return o.substring(n.length, o.length)
}
return ""
}
function _f2(e) {
return _f1(e, document.cookie)
}
function _f3(e, t, o) {
try {
o && (window.sessionStorage && window.sessionStorage.setItem(e, t), window.localStorage && window.localStorage.setItem(e, t));
var n = 31536e6;
document.cookie = e + "=; expires=Mon, 20 Sep 1970 00:00:00 UTC; path=/;" + (window.location.protocol == 'https:' ? 'SameSite=None; Secure;' : ''), document.cookie = e + "=" + t + "; expires=" + new Date((new Date).getTime() + n).toGMTString() + "; path=/;" + (window.location.protocol == 'https:' ? 'SameSite=None; Secure;' : '')
} catch (e) { }
}
window.byted_acrawler.init({
aid: 99999999,
dfp: 0
});
var __ac_nonce = _f2("__ac_nonce");
var __ac_signature = window.byted_acrawler.sign("", __ac_nonce);
_f3("__ac_signature", __ac_signature);
_f3("__ac_referer", document.referrer || "__ac_blank", !0);
try {
sessionStorage.setItem("__ac_ns", performance.timing.navigationStart)
} catch (e) { }
window.location.reload()
</script>
这段代码window.byted_acrawler
就是核心的对象,从存储中取出随机字符串,然后作为签名的第2个参数,接着将签名存储,最后刷新,就开始第二次请求
浏览器调试截图:
第二个请求就是ttwid相关逻辑了,这个请求会携带第一个请求最后存储的__ac_nonce
和__ac_signature
,接着响应得到ttwid关联的几个cookie,以及下面的内容代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="//sf1-cdn-tos.douyinstatic.com/obj/eden-cn/lpqpflo/ixigua_favicon.ico">
</head>
<body>
<script nonce="bfe55e58540f4e80ac63d499a935c2b9">
var startTime = Date.now()
</script>
<script nonce="bfe55e58540f4e80ac63d499a935c2b9">
;(function (w, d, u, b, n, pc, ga, ae, po, s, p, e, t, pp) {pc = 'precollect';ga
= 'getAttribute';ae = 'addEventListener';po = 'PerformanceObserver';s = function
(m) {p = [].slice.call(arguments);p.push(Date.now(), location.href);(m == pc ?
s.p.a : s.q).push(p)};s.q = [];s.p = { a: [] };w[n] = s;e =
document.createElement('script');e.src = u + '?bid=' + b + '&globalName=' +
n;e.crossOrigin = u.indexOf('sdk-web') > 0 ? 'anonymous' :
'use-credentials';d.getElementsByTagName('head')[0].appendChild(e);if (ae in w)
{s.pcErr = function (e) {e = e || w.event;t = e.target || e.srcElement;if (t
instanceof Element || t instanceof HTMLElement) {if (t[ga]('integrity'))
{w[n](pc, 'sri', t[ga]('href') || t[ga]('src'))} else {w[n](pc, 'st', { tagName:
t.tagName, url: t[ga]('href') || t[ga]('src') })}} else {w[n](pc, 'err', e.error
|| e.message)}};s.pcRej = function (e) {e = e || w.event;w[n](pc, 'err',
e.reason || (e.detail && e.detail.reason))};w[ae]('error', s.pcErr,
true);w[ae]('unhandledrejection', s.pcRej,
true);};if('PerformanceLongTaskTiming' in w) {pp = s.pp = { entries: []
};pp.observer = new PerformanceObserver(function (l) {pp.entries =
pp.entries.concat(l.getEntries())});pp.observer.observe({ entryTypes:
['longtask', 'largest-contentful-paint','layout-shift']
})}})(window,document,'https://lf3-short.ibytedapm.com/slardar/fe/sdk-web/browser.cn.js','xigua_video_web_pc','Slardar') </script>
<script defer nonce="bfe55e58540f4e80ac63d499a935c2b9" src="https://privacy.zijieapi.com/api/web-cmp/sdk/?project_key=b443652e7ef8089c"></script>
<script src="https://unpkg.byted-static.com/byted-ucenter/ttwid-js/1.0.1/dist/index.umd.production.js" nonce="bfe55e58540f4e80ac63d499a935c2b9"></script>
<script defer src="https://lf-c-flwb.bytetos.com/obj/rc-client-security/c-webmssdk/1.0.0.15/webmssdk.js"
nonce="bfe55e58540f4e80ac63d499a935c2b9"></script>
<script src="https://lf-cdn-tos.bytescm.com/obj/static/secsdk/secsdk-lastest.umd.js"
nonce="bfe55e58540f4e80ac63d499a935c2b9"></script>
<script nonce="bfe55e58540f4e80ac63d499a935c2b9">
secsdk.csrf.setProtectedHost({
'www.ixigua.com': {
'GET': '*',
'POST': '*',
"TOKEN_PATH": "/api/",
},
});
</script>
<script nonce="bfe55e58540f4e80ac63d499a935c2b9">
var retryTimes = 0
var maxRetryTimes = 2
var instance = null
try {
window.Slardar('init', {
bid: 'xigua_video_web_pc',
pid: 'ttwid'
})
window.Slardar('start')
window.Slardar('sendEvent', {
name: "ttwid-pv",
metrics: { count: 1 },
})
init()
} catch (err) {
ttwidInitError()
reloadPage()
}
function insertParamAndReload(key, value) {
var kvp = document.location.search ? document.location.search.substr(1).split('&') : [];
var i = 0;
// 替换已有的
for (; i < kvp.length; i++) {
if (new RegExp('^' + key + '=').test(kvp[i])) {
var pair = kvp[i].split('=');
pair[1] = value;
kvp[i] = pair.join('=');
break;
}
}
// 新增
if (i >= kvp.length) {
kvp[kvp.length] = [key, value].join('=');
}
var params = kvp.join('&');
document.location.search = params;
}
function init() {
setRealReferrer()
if (!instance) {
instance = new window.TTWidInstance({
region: undefined,
aid: 1768,
needFid: false,
service: window.location.host,
migrate_info: {"ticket":"","source":"node"},
cbUrlProtocol: window.location.protocol.slice(0, -1)
})
}
instance.registerUnionWebId({}, function(registerError, cbResponse){
var callbackError = !cbResponse || cbResponse.status_code !== 0
if (registerError || callbackError) {
if (retryTimes < maxRetryTimes) {
retryTimes ++
init()
return
}
ttwidRegisterError()
} else {
window.Slardar('sendEvent', {
name: "ttwid-success",
metrics: { count: 1 },
})
}
reloadPage()
})
}
function reloadPage() {
reportDuration()
insertParamAndReload('wid_try','1')
}
// 记录正确的referrer, 优先取风控中间页记录的值
function setRealReferrer() {
var __AC_REFERER = '__ac_referer'
var acReferrer = window.sessionStorage.getItem(__AC_REFERER)
var realReferrer = acReferrer != null ? acReferrer : document.referrer
window.sessionStorage.setItem(__AC_REFERER, realReferrer || '__ac_blank')
}
function setTmpCookie() {
var maxAge = 60 * 60 * 24
document.cookie = 'ttwid_date=1; max-age=' + maxAge
}
function ttwidInitError() {
setTmpCookie()
window.Slardar('sendEvent', {
name: "ttwidInit-error",
metrics: { count: 1 },
})
}
function ttwidRegisterError() {
setTmpCookie()
window.Slardar('sendEvent', {
name: 'ttwidRegister-error',
metrics: { count: 1 },
})
}
function reportDuration() {
window.Slardar('sendEvent', {
name: 'ttwid-duration',
metrics: { count: Date.now() - startTime },
})
}
</script>
</body>
</html>
借用ai分析下上面代码的过程,主要涉及到错误处理、性能监控和页面初始化。以下是对该脚本的业务流程的分析:
初始化Slardar监控:
Slardar
监控工具。PerformanceObserver
监控长任务、最大内容绘制和布局偏移。错误处理:
error
和unhandledrejection
事件。Slardar
的precollect
方法记录错误信息。初始化TTWid实例:
init
函数用于初始化TTWidInstance
。ttwidInitError
记录错误并重载页面。TTWidInstance
注册成功后,发送ttwid-success
事件;否则,重试注册,最多重试两次。页面重载和参数插入:
reloadPage
函数用于在错误或成功后重载页面。insertParamAndReload
函数用于在URL中插入或更新参数。设置真实的referrer:
setRealReferrer
函数用于设置真实的referrer
,优先使用风控中间页记录的值。临时Cookie设置:
setTmpCookie
函数用于设置一个临时的Cookie,可能用于标记错误状态。错误事件记录:
ttwidInitError
和ttwidRegisterError
函数用于记录初始化和注册过程中的错误。性能报告:
reportDuration
函数用于记录从页面加载到当前时间的持续时间。这个脚本的主要目的是通过Slardar
工具监控页面性能和错误,并通过TTWidInstance
进行某种身份验证或注册操作。错误处理和重试机制确保在失败时能够进行适当的恢复和记录。
因此也引出了我们的第三个请求。
第三个请求是核心逆向的请求。这个请求最后的链接:https://www.ixigua.com/7440408860818407948?logTag=a226ed00791b3c5fd17f&wid_try=1
,logTag
不用关心,wid_try
是重要的参数,因为有它,我们能从响应内容里面得到window.getSSRHydratedData
这个函数(在响应内容可找到)。同时,这个请求也会在响应cookie 得到xiguavideopcwebid
相关的参数。更重要的是,这个请求也生成了整个页面了。
最后一个环节,我们通过开源node补环境框架在终端环境得到__ac_signture
,下面也推荐两个框架
git地址:https://github.com/bnmgh1/node-sandbox
function test_vm() {
const sandbox = {
wanfeng: wanfeng,
globalMy: globalMy,
console: console,
}
let workCode = fs.readFileSync("./work/ac_sign.js");
a = +new Date;
var callCode = `window.byted_acrawler.init({
aid: 99999999,
dfp: 0
});
var __ac_nonce = "06639eaa4009ab37b9a75";
var __ac_signature = window.byted_acrawler.sign("",__ac_nonce);
console.log("__ac_signature: ", __ac_signature)`;
var code = "debugger;\r\n" + globalMy_js + init_env + envCode + "\r\n" + workCode + "\r\n" + endCode + callCode;
vm.runInNewContext(code, sandbox);
console.log("运行环境Js + 工作Js 耗时:", +new Date - a, "毫秒");
}
test_vm();
git地址:https://github.com/ylw00/qxVm
const fs = require('fs');
const QXVM_GENERATE = require('../qxVm_sanbox/qxVm.sanbox');
function ReadCode(name, dir) {
let file_path = dir === undefined ? `${__dirname}/${name}` : `${__dirname}/${dir}/${name}`;
return fs.readFileSync(file_path) + "\r\n"
}
const js_code = ReadCode(`./ac_sign.js`);
const user_config = {
isTest: false,
runConfig: {
proxy: true,
logOpen: true
},
window_attribute: {},
env: {
navigator: {
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
},
location: {
href: "https://www.ixigua.com/"
},
document: {
referrer: "https://www.ixigua.com/",
cookie: ''
}
}
}
let window = QXVM_GENERATE.sanbox(js_code, "byted_acrawler", user_config, false);
const ac_nonce = "06757b48300510d8954c7"
let ac_sign = window.byted_acrawler.sign("", ac_nonce)
console.log("__ac_nonce:", ac_nonce)
console.log("__ac_signature:", ac_sign)
在附上ac_sign.js
,这个其实就是上面说的虚拟化代码,把请求中第一个script脚本复制粘贴下来就可以了。
var glb;(glb="undefined"==typeof window?global:window)._$jsvmprt=function(b,e,f){function a(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],(function(){}))),!0}catch(b){return!1}}function d(b,e,f){return(d=a()?Reflect.construct:function(b,e,f){var a=[null];a.push.apply(a,e);var d=new(Function.bind.apply(b,a));return f&&c(d,f.prototype),d}).apply(null,arguments)}function c(b,e){return(c=Object.setPrototypeOf||function(b,e){return b.__proto__=e,b})(b,e)}function n(b){return function(b){if(Array.isArray(b)){for(var e=0,f=new Array(b.length);e<b.length;e++)f[e]=b[e];return f}}(b)||function(b){if(Symbol.iterator in Object(b)||"[object Arguments]"===Object.prototype.toString.call(b))return Array.from(b)}(b)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}for(var i=[],r=0,t=[],o=0,l=function(b,e){var f=b[e++],a=b[e],d=parseInt(""+f+a,16);if(d>>7==0)return[1,d];if(d>>6==2){var c=parseInt(""+b[++e]+b[++e],16);return d&=63,[2,c=(d<<=8)+c]}if(d>>6==3){var n=parseInt(""+b[++e]+b[++e],16),i=parseInt(""+b[++e]+b[++e],16);return d&=63,[3,i=(d<<=16)+(n<<=8)+i]}},u=function(b,e){var f=parseInt(""+b[e]+b[e+1],16);return f=f>127?-256+f:f},s=function(b,e){var f=parseInt(""+b[e]+b[e+1]+b[e+2]+b[e+3],16);return f=f>32767?-65536+f:f},p=function(b,e){var f=parseInt(""+b[e]+b[e+1]+b[e+2]+b[e+3]+b[e+4]+b[e+5]+b[e+6]+b[e+7],16);return f=f>2147483647?0+f:f},y=function(b,e){return parseInt(""+b[e]+b[e+1],16)},v=function(b,e){return parseInt(""+b[e]+b[e+1]+b[e+2]+b[e+3],16)},g=g||this||window,h=Object.keys||function(b){var e={},f=0;for(var a in b)e[f++]=a;return e.length=f,e},m=(b.length,0),I="",C=m;C<m+16;C++){var q=""+b[C++]+b[C];q=parseInt(q,16),I+=String.fromCharCode(q)}if("HNOJ@?RC"!=I)throw new Error("error magic number "+I);m+=16;parseInt(""+b[m]+b[m+1],16);m+=8,r=0;for(var w=0;w<4;w++){var S=m+2*w,R=""+b[S++]+b[S],x=parseInt(R,16);r+=(3&x)<<2*w}m+=16,m+=8;var z=parseInt(""+b[m]+b[m+1]+b[m+2]+b[m+3]+b[m+4]+b[m+5]+b[m+6]+b[m+7],16),O=z,E=m+=8,j=v(b,m+=z);j[1];m+=4,i={p:[],q:[]};for(var A=0;A<j;A++){for(var D=l(b,m),T=m+=2*D[0],$=i.p.length,P=0;P<D[1];P++){var U=l(b,T);i.p.push(U[1]),T+=2*U[0]}m=T,i.q.push([$,i.p.length])}var _={5:1,6:1,70:1,22:1,23:1,37:1,73:1},k={72:1},M={74:1},H={11:1,12:1,24:1,26:1,27:1,31:1},J={10:1},N={2:1,29:1,30:1,20:1},B=[],W=[];function F(b,e,f){for(var a=e;a<e+f;){var d=y(b,a);B[a]=d,a+=2;k[d]?(W[a]=u(b,a),a+=2):_[d]?(W[a]=s(b,a),a+=4):M[d]?(W[a]=p(b,a),a+=8):H[d]?(W[a]=y(b,a),a+=2):J[d]?(W[a]=v(b,a),a+=4):N[d]&&(W[a]=v(b,a),a+=4)}}return K(b,E,O/2,[],e,f);function G(b,e,f,a,c,l,m,I){null==l&&(l=this);var C,q,w,S=[],R=0;m&&(C=m);var x,z,O=e,E=O+2*f;if(!I)for(;O<E;){var j=parseInt(""+b[O]+b[O+1],16);O+=2;var A=3&(x=13*j%241);if(x>>=2,A<1){A=3&x;if(x>>=2,A>2)(A=x)>10?S[++R]=void 0:A>1?(C=S[R--],S[R]=S[R]>=C):A>-1&&(S[++R]=null);else if(A>1){if((A=x)>11)throw S[R--];if(A>7){for(C=S[R--],z=v(b,O),A="",P=i.q[z][0];P<i.q[z][1];P++)A+=String.fromCharCode(r^i.p[P]);O+=4,S[R--][A]=C}else A>5&&(S[R]=h(S[R]))}else if(A>0){(A=x)>8?(C=S[R--],S[R]=typeof C):A>6?S[R]=--S[R]:A>4?S[R-=1]=S[R][S[R+1]]:A>2&&(q=S[R--],(A=S[R]).x===G?A.y>=1?S[R]=K(b,A.c,A.l,[q],A.z,w,null,1):(S[R]=K(b,A.c,A.l,[q],A.z,w,null,0),A.y++):S[R]=A(q))}else{if((A=x)>14)z=s(b,O),(U=function e(){var f=arguments;return e.y>0?K(b,e.c,e.l,f,e.z,this,null,0):(e.y++,K(b,e.c,e.l,f,e.z,this,null,0))}).c=O+4,U.l=z-2,U.x=G,U.y=0,U.z=c,S[R]=U,O+=2*z-2;else if(A>12)q=S[R--],w=S[R--],(A=S[R--]).x===G?A.y>=1?S[++R]=K(b,A.c,A.l,q,A.z,w,null,1):(S[++R]=K(b,A.c,A.l,q,A.z,w,null,0),A.y++):S[++R]=A.apply(w,q);else if(A>5)C=S[R--],S[R]=S[R]!=C;else if(A>3)C=S[R--],S[R]=S[R]*C;else if(A>-1)return[1,S[R--]]}}else if(A<2){A=3&x;if(x>>=2,A<1){if((A=x)>9);else if(A>7)C=S[R--],S[R]=S[R]&C;else if(A>5)z=y(b,O),O+=2,S[R-=z]=0===z?new S[R]:d(S[R],n(S.slice(R+1,R+z+1)));else if(A>3){z=s(b,O);try{if(t[o][2]=1,1==(C=G(b,O+4,z-3,[],c,l,null,0))[0])return C}catch(m){if(t[o]&&t[o][1]&&1==(C=G(b,t[o][1][0],t[o][1][1],[],c,l,m,0))[0])return C}finally{if(t[o]&&t[o][0]&&1==(C=G(b,t[o][0][0],t[o][0][1],[],c,l,null,0))[0])return C;t[o]=0,o--}O+=2*z-2}}else if(A<2){if((A=x)>12)S[++R]=u(b,O),O+=2;else if(A>10)C=S[R--],S[R]=S[R]<<C;else if(A>8){for(z=v(b,O),A="",P=i.q[z][0];P<i.q[z][1];P++)A+=String.fromCharCode(r^i.p[P]);O+=4,S[R]=S[R][A]}else A>6&&(q=S[R--],C=delete S[R--][q])}else if(A<3){(A=x)<2?S[++R]=C:A<4?(C=S[R--],S[R]=S[R]<=C):A<11?(C=S[R-=2][S[R+1]]=S[R+2],R--):A<13&&(C=S[R],S[++R]=C)}else{if((A=x)>12)S[++R]=l;else if(A>5)C=S[R--],S[R]=S[R]!==C;else if(A>3)C=S[R--],S[R]=S[R]/C;else if(A>1){if((z=s(b,O))<0){I=1,F(b,e,2*f),O+=2*z-2;break}O+=2*z-2}else A>-1&&(S[R]=!S[R])}}else if(A<3){A=3&x;if(x>>=2,A>2)(A=x)>7?(C=S[R--],S[R]=S[R]|C):A>5?(z=y(b,O),O+=2,S[++R]=c["$"+z]):A>3&&(z=s(b,O),t[o][0]&&!t[o][2]?t[o][1]=[O+4,z-3]:t[o++]=[0,[O+4,z-3],0],O+=2*z-2);else if(A>1){if((A=x)<2){for(z=v(b,O),C="",P=i.q[z][0];P<i.q[z][1];P++)C+=String.fromCharCode(r^i.p[P]);S[++R]=C,O+=4}else if(A<4)if(S[R--])O+=4;else{if((z=s(b,O))<0){I=1,F(b,e,2*f),O+=2*z-2;break}O+=2*z-2}else A<6?(C=S[R--],S[R]=S[R]%C):A<8?(C=S[R--],S[R]=S[R]instanceof C):A<15&&(S[++R]=!1)}else if(A>0){(A=x)<1?S[++R]=g:A<3?(C=S[R--],S[R]=S[R]+C):A<5?(C=S[R--],S[R]=S[R]==C):A<14&&(C=S[R-1],q=S[R],S[++R]=C,S[++R]=q)}else{(A=x)<2?(C=S[R--],S[R]=S[R]>C):A<9?(z=v(b,O),O+=4,q=R+1,S[R-=z-1]=z?S.slice(R,q):[]):A<11?(z=y(b,O),O+=2,C=S[R--],c[z]=C):A<13?(C=S[R--],S[R]=S[R]>>C):A<15&&(S[++R]=s(b,O),O+=4)}}else{A=3&x;if(x>>=2,A>2)(A=x)>13?(S[++R]=p(b,O),O+=8):A>11?(C=S[R--],S[R]=S[R]>>>C):A>9?S[++R]=!0:A>7?(z=y(b,O),O+=2,S[R]=S[R][z]):A>0&&(C=S[R--],S[R]=S[R]<C);else if(A>1){(A=x)>10?(z=s(b,O),t[++o]=[[O+4,z-3],0,0],O+=2*z-2):A>8?(C=S[R--],S[R]=S[R]^C):A>6&&(C=S[R--])}else if(A>0){if((A=x)<3){var D=0,T=S[R].length,$=S[R];S[++R]=function(){var b=D<T;if(b){var e=$[D++];S[++R]=e}S[++R]=b}}else A<5?(z=y(b,O),O+=2,C=c[z],S[++R]=C):A<7?S[R]=++S[R]:A<9&&(C=S[R--],S[R]=S[R]in C)}else{if((A=x)>13)C=S[R],S[R]=S[R-1],S[R-1]=C;else if(A>4)C=S[R--],S[R]=S[R]===C;else if(A>2)C=S[R--],S[R]=S[R]-C;else if(A>0){for(z=v(b,O),A="",P=i.q[z][0];P<i.q[z][1];P++)A+=String.fromCharCode(r^i.p[P]);A=+A,O+=4,S[++R]=A}}}}if(I)for(;O<E;){j=B[O];O+=2;A=3&(x=13*j%241);if(x>>=2,A<1){var U;A=3&x;if(x>>=2,A<1){if((A=x)>14)z=W[O],(U=function e(){var f=arguments;return e.y>0?K(b,e.c,e.l,f,e.z,this,null,0):(e.y++,K(b,e.c,e.l,f,e.z,this,null,0))}).c=O+4,U.l=z-2,U.x=G,U.y=0,U.z=c,S[R]=U,O+=2*z-2;else if(A>12)q=S[R--],w=S[R--],(A=S[R--]).x===G?A.y>=1?S[++R]=K(b,A.c,A.l,q,A.z,w,null,1):(S[++R]=K(b,A.c,A.l,q,A.z,w,null,0),A.y++):S[++R]=A.apply(w,q);else if(A>5)C=S[R--],S[R]=S[R]!=C;else if(A>3)C=S[R--],S[R]=S[R]*C;else if(A>-1)return[1,S[R--]]}else if(A<2){(A=x)<4?(q=S[R--],(A=S[R]).x===G?A.y>=1?S[R]=K(b,A.c,A.l,[q],A.z,w,null,1):(S[R]=K(b,A.c,A.l,[q],A.z,w,null,0),A.y++):S[R]=A(q)):A<6?S[R-=1]=S[R][S[R+1]]:A<8?S[R]=--S[R]:A<10&&(C=S[R--],S[R]=typeof C)}else if(A<3){if((A=x)>11)throw S[R--];if(A>7){for(C=S[R--],z=W[O],A="",P=i.q[z][0];P<i.q[z][1];P++)A+=String.fromCharCode(r^i.p[P]);O+=4,S[R--][A]=C}else A>5&&(S[R]=h(S[R]))}else{(A=x)<1?S[++R]=null:A<3?(C=S[R--],S[R]=S[R]>=C):A<12&&(S[++R]=void 0)}}else if(A<2){A=3&x;if(x>>=2,A>2)(A=x)>12?S[++R]=l:A>5?(C=S[R--],S[R]=S[R]!==C):A>3?(C=S[R--],S[R]=S[R]/C):A>1?O+=2*(z=W[O])-2:A>-1&&(S[R]=!S[R]);else if(A>1){(A=x)<2?S[++R]=C:A<4?(C=S[R--],S[R]=S[R]<=C):A<11?(C=S[R-=2][S[R+1]]=S[R+2],R--):A<13&&(C=S[R],S[++R]=C)}else if(A>0){if((A=x)<8)q=S[R--],C=delete S[R--][q];else if(A<10){for(z=W[O],A="",P=i.q[z][0];P<i.q[z][1];P++)A+=String.fromCharCode(r^i.p[P]);O+=4,S[R]=S[R][A]}else A<12?(C=S[R--],S[R]=S[R]<<C):A<14&&(S[++R]=W[O],O+=2)}else{if((A=x)<5){z=W[O];try{if(t[o][2]=1,1==(C=G(b,O+4,z-3,[],c,l,null,0))[0])return C}catch(m){if(t[o]&&t[o][1]&&1==(C=G(b,t[o][1][0],t[o][1][1],[],c,l,m,0))[0])return C}finally{if(t[o]&&t[o][0]&&1==(C=G(b,t[o][0][0],t[o][0][1],[],c,l,null,0))[0])return C;t[o]=0,o--}O+=2*z-2}else A<7?(z=W[O],O+=2,S[R-=z]=0===z?new S[R]:d(S[R],n(S.slice(R+1,R+z+1)))):A<9&&(C=S[R--],S[R]=S[R]&C)}}else if(A<3){A=3&x;if(x>>=2,A<1)(A=x)<2?(C=S[R--],S[R]=S[R]>C):A<9?(z=W[O],O+=4,q=R+1,S[R-=z-1]=z?S.slice(R,q):[]):A<11?(z=W[O],O+=2,C=S[R--],c[z]=C):A<13?(C=S[R--],S[R]=S[R]>>C):A<15&&(S[++R]=W[O],O+=4);else if(A<2){(A=x)<1?S[++R]=g:A<3?(C=S[R--],S[R]=S[R]+C):A<5?(C=S[R--],S[R]=S[R]==C):A<14&&(C=S[R-1],q=S[R],S[++R]=C,S[++R]=q)}else if(A<3){if((A=x)<2){for(z=W[O],C="",P=i.q[z][0];P<i.q[z][1];P++)C+=String.fromCharCode(r^i.p[P]);S[++R]=C,O+=4}else A<4?S[R--]?O+=4:O+=2*(z=W[O])-2:A<6?(C=S[R--],S[R]=S[R]%C):A<8?(C=S[R--],S[R]=S[R]instanceof C):A<15&&(S[++R]=!1)}else{(A=x)>7?(C=S[R--],S[R]=S[R]|C):A>5?(z=W[O],O+=2,S[++R]=c["$"+z]):A>3&&(z=W[O],t[o][0]&&!t[o][2]?t[o][1]=[O+4,z-3]:t[o++]=[0,[O+4,z-3],0],O+=2*z-2)}}else{A=3&x;if(x>>=2,A>2)(A=x)>13?(S[++R]=W[O],O+=8):A>11?(C=S[R--],S[R]=S[R]>>>C):A>9?S[++R]=!0:A>7?(z=W[O],O+=2,S[R]=S[R][z]):A>0&&(C=S[R--],S[R]=S[R]<C);else if(A>1){(A=x)>10?(z=W[O],t[++o]=[[O+4,z-3],0,0],O+=2*z-2):A>8?(C=S[R--],S[R]=S[R]^C):A>6&&(C=S[R--])}else if(A>0){if((A=x)>7)C=S[R--],S[R]=S[R]in C;else if(A>5)S[R]=++S[R];else if(A>3)z=W[O],O+=2,C=c[z],S[++R]=C;else if(A>1){D=0,T=S[R].length,$=S[R];S[++R]=function(){var b=D<T;if(b){var e=$[D++];S[++R]=e}S[++R]=b}}}else{if((A=x)<2){for(z=W[O],A="",P=i.q[z][0];P<i.q[z][1];P++)A+=String.fromCharCode(r^i.p[P]);A=+A,O+=4,S[++R]=A}else A<4?(C=S[R--],S[R]=S[R]-C):A<6?(C=S[R--],S[R]=S[R]===C):A<15&&(C=S[R],S[R]=S[R-1],S[R-1]=C)}}}return[0,null]}function K(b,e,f,a,d,c,n,i){var r,t;null==c&&(c=this),d&&!d.d&&(d.d=0,d.$0=d,d[1]={});var o={},l=o.d=d?d.d+1:0;for(o["$"+l]=o,t=0;t<l;t++)o[r="$"+t]=d[r];for(t=0,l=o.length=a.length;t<l;t++)o[t]=a[t];return i&&!B[e]&&F(b,e,2*f),B[e]?G(b,e,f,0,o,c,null,1)[1]:G(b,e,f,0,o,c,null,0)[1]}},(glb="undefined"==typeof window?global:window)._$jsvmprt("文章内容字数有限,这里删除了虚拟字节码",[,,"undefined"!=typeof exports?exports:void 0,"undefined"!=typeof module?module:void 0,"undefined"!=typeof define?define:void 0,"undefined"!=typeof Object?Object:void 0,void 0,"undefined"!=typeof TypeError?TypeError:void 0,"undefined"!=typeof document?document:void 0,"undefined"!=typeof InstallTrigger?InstallTrigger:void 0,"undefined"!=typeof safari?safari:void 0,"undefined"!=typeof Date?Date:void 0,"undefined"!=typeof Math?Math:void 0,"undefined"!=typeof navigator?navigator:void 0,"undefined"!=typeof location?location:void 0,"undefined"!=typeof history?history:void 0,"undefined"!=typeof Image?Image:void 0,"undefined"!=typeof console?console:void 0,"undefined"!=typeof PluginArray?PluginArray:void 0,"undefined"!=typeof indexedDB?indexedDB:void 0,"undefined"!=typeof DOMException?DOMException:void 0,"undefined"!=typeof parseInt?parseInt:void 0,"undefined"!=typeof String?String:void 0,"undefined"!=typeof Array?Array:void 0,"undefined"!=typeof Error?Error:void 0,"undefined"!=typeof JSON?JSON:void 0,"undefined"!=typeof Promise?Promise:void 0,"undefined"!=typeof WebSocket?WebSocket:void 0,"undefined"!=typeof eval?eval:void 0,"undefined"!=typeof setTimeout?setTimeout:void 0,"undefined"!=typeof encodeURIComponent?encodeURIComponent:void 0,"undefined"!=typeof encodeURI?encodeURI:void 0,"undefined"!=typeof Request?Request:void 0,"undefined"!=typeof Headers?Headers:void 0,"undefined"!=typeof decodeURIComponent?decodeURIComponent:void 0,"undefined"!=typeof RegExp?RegExp:void 0]);
这个项目是抽空做的,项目地址: short-video-parse, 目前还不完善,有空就会更新,喜欢可以star、fork、和交流。
实际测试中,目前看来__ac_nonce
和 __ac_signature
可以直接浏览器获取直接作为固定值用于请求中,但是也不能保证后期变化。最后,分享就到这了,以后有机会再来。
👍
没有微信视频号吗
支持https://weishi.qq.com/ 微视,但是微信视频号目前不支持的,视频号没有web分享地址,有空找下方案