参数名取值说明max_behot_time1542351388变categoryvideo_new变utm_sourcetoutiao不变widen1不变tadrequiretrue不变asA1D57BBEAE87838变cp5BEE7798D358EE1变_signatureRU1MfhAUHqXfJZp0ysi3V0VNTG变
一个一个的看
从参数的数看应该是一个时间戳,暂时可以不用管
从字段的意思看是视频的频道(分类),video_new 应该是推荐页面,但是从页面上看不到任何分类信息,所以第一个需要找的参数就是视频的频道列表。
这个参数比较简单,可以直接拿video_new 参数值去视频js文件中搜索一下
整理如下:
频道id频道名称video_new推荐subv_voice音乐subv_funny搞笑subv_society社会subv_comedy小品subv_life生活subv_movie影视subv_entertainment娱乐subv_cute呆萌subv_game游戏subv_boutique原创subv_broaden_view开眼
按照上面的方法还是去js文件中搜索,不过由于该参数每次变化,所以只能搜索参数名。
搜索cp,发现cp和as都找到了,一下逮住俩
执行的时候,发现找不到s
,断点走一遍发现(0, s.default)(t)
就是把t
做了一遍md5
function i() {
var t = Math.floor((new Date).getTime() / 1e3),
e = t.toString(16).toUpperCase(),
n = (0, s.default)(t).toString().toUpperCase(); // 直接换成自己对t做md5操作就可以了
if (8 != e.length)
return {
as: "479BB4B7254C150",
cp: "7E0AC8874BB0985"
};
for (var r = n.slice(0, 5), i = n.slice(-5), o = "", a = 0; a < 5; a++)
o += r[a] + e[a];
for (var u = "", l = 0; l < 5; l++)
u += e[l + 3] + i[l];
return {
as: "A1" + o + e.slice(-3),
cp: e.slice(0, 3) + u + "E1"
}
}
继续搜索
看一看到_signature
这个参数就是r
,而var r = (0, m.sign)(n + "");
然后打断点继续找m
,
一步一步往上找,最后在下图位置找到
Function(function(t) {
return 'e(e,a,r){(b[e]||(b[e]=t("x,y","x "+e+" y")(r,a)}a(e,a,r){(k[r]||(k[r]=t("x,y","new x[y]("+Array(r+1).join(",x[y]")(1)+")")(e,a)}r(e,a,r){n,t,s={},b=s.d=r?r.d+1:0;for(s["$"+b]=s,t=0;t<b;t)s[n="$"+t]=r[n];for(t=0,b=s=a;t<b;t)s[t]=a[t];c(e,0,s)}c(t,b,k){u(e){v[x]=e}f{g=,ting(bg)}l{try{y=c(t,b,k)}catch(e){h=e,y=l}}for(h,y,d,g,v=[],x=0;;)switch(g=){case 1:u(!)4:f5:u((e){a=0,r=e;{c=a<r;c&&u(e[a]),c}}(6:y=,u((y8:if(g=,lg,g=,y===c)b+=g;else if(y!==l)y9:c10:u(s(11:y=,u(+y)12:for(y=f,d=[],g=0;g<y;g)d[g]=y.charCodeAt(g)^g+y;u(String.fromCharCode.apply(null,d13:y=,h=delete [y]14:59:u((g=)?(y=x,v.slice(x-=g,y:[])61:u([])62:g=,k[0]=65599*k[0]+k[1].charCodeAt(g)>>>065:h=,y=,[y]=h66:u(e(t[b],,67:y=,d=,u((g=).x===c?r(g.y,y,k):g.apply(d,y68:u(e((g=t[b])<"<"?(b--,f):g+g,,70:u(!1)71:n72:+f73:u(parseInt(f,3675:if(){bcase 74:g=<<16>>16g76:u(k[])77:y=,u([y])78:g=,u(a(v,x-=g+1,g79:g=,u(k["$"+g])81:h=,[f]=h82:u([f])83:h=,k[]=h84:!085:void 086:u(v[x-1])88:h=,y=,h,y89:u({e{r(e.y,arguments,k)}e.y=f,e.x=c,e})90:null91:h93:h=0:;default:u((g<<16>>16)-16)}}n=this,t=n.Function,s=Object.keys||(e){a={},r=0;for(c in e)a[r]=c;a=r,a},b={},k={};r'.replace(/[-]/g, function(e) {
return t[15 & e.charCodeAt(0)]
})
}("v[x++]=v[--x]t.charCodeAt(b++)-32function return ))++.substrvar .length(),b+=;break;case ;break}".split("")))()('gr$Daten Иb/s!l y͒yĹg,(lfi~ah`{mv,-n|jqewVxp{rvmmx,&effkx[!cs"l".Pq%widthl"@q&heightl"vr*getContextx$"2d[!cs#l#,*;?|u.|uc{uq$fontl#vr(fillTextx$$龘ฑภ경2<[#c}l#2q*shadowBlurl#1q-shadowOffsetXl#$$limeq+shadowColorl#vr#arcx88802[%c}l#vr&strokex[ c}l"v,)}eOmyoZB]mx[ cs!0s$l$Pb<k7l l!r&lengthb%^l$1+s$jl s#i$1ek1s$gr#tack4)zgr#tac$! +0o![#cj?o ]!l$b%s"o ]!l"l$b*b^0d#>>>s!0s%yA0s"l"l!r&lengthb<k+l"^l"1+s"jl s&l&z0l!$ +["cs\'(0l#i\'1ps9wxb&s() &{s)/s(gr&Stringr,fromCharCodes)0s*yWl ._b&s o!])l l Jb<k$.aj;l .Tb<k$.gj/l .^b<k&i"-4j!+& s+yPo!]+s!l!l Hd>&l!l Bd>&+l!l <d>&+l!l 6d>&+l!l &+ s,y=o!o!]/q"13o!l q"10o!],l 2d>& s.{s-yMo!o!]0q"13o!]*Ld<l 4d#>>>b|s!o!l q"10o!],l!& s/yIo!o!].q"13o!],o!]*Jd<l 6d#>>>b|&o!]+l &+ s0l-l!&l-l!i\'1z141z4b/@d<l"b|&+l-l(l!b^&+l-l&zl\'g,)gk}ejo{cm,)|yn~Lij~em["cl$b%@d<l&zl\'l $ +["cl$b%b|&+l-l%8d<@b|l!b^&+ q$sign ', [Object.defineProperty(e, "__esModule", {
value: !0
})])
看不懂,所以先执行一下,结果如下,报错e is not defined
,e没有定义,把e的模块单独拿出来
[Object.defineProperty(e, "__esModule", {value: !0 })]
搜了一下方法Object.defineProperty
如下:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
简单说意思就是,e.__esModule=!0
,对于单独获取这一个参数来看,好像没啥用,那就先删掉看看。
没报错,不过什么也没有
简化一下代码,把字符串都去掉,如下:
Function(function(t) {
return 'str'.replace(/[-]/g, function(e) {
return t[15 & e.charCodeAt(0)]
})
}("str".split("str")))()('str', [{}])
这样就清晰了很多,一点一点看,看里面
function(t) {
return 'str'.replace(/[-]/g, function(e) {
return t[15 & e.charCodeAt(0)]
})
}("str".split("str"))
相当于把 "str".split("str")
这个数组传入函数,然后返回一个字符串。再简化如下:
Function(
return str
)()('str', [{}])
Function(return str)()
执行结果应该返回一个包含两个参数的的function
所以再简化
function(a,b)('str', [{}])
第一个参数是一个字符串,所以返回的东西应该在第二个参数里,即function(a,b)('str', [a={}])
从上图看,已经找到了sign
函数,回到var r = (0, m.sign)(n + "");
,把n
传入该方法就可以了
var e = (0, p.default)(),
n = 0;
this.url = this._url, "refresh" === t ? (n = this.list.length > 0 ? this.list[0].behot_time : 0, this.url += "min_behot_time=" + n) : (n = this.list.length > 0 ? this.list[this.list.length - 1].behot_time : 0, this.url += "max_behot_time=" + n);
var r = (0, m.sign)(n + "");
(0, o.default)(this.params, {
as: e.as,
cp: e.cp,
_signature: r
})
可以看到n
就是参数min_behot_time
,冤家路窄啊。取一个时间戳就行,顺着js往上找一下也行,找到一个behot_time: Math.floor((new Date).getTime() / 1e3)
,确实是一个时间戳。
终于凑够了,执行的时候提示没有userAgent
信息。设置一下就ok了。
最终版本js就出来了,如下:
navigator = {};
navigator.userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36";
function getsign(userid) {
Function(
function(t) {
return 'e(e,a,r){(b[e]||(b[e]=t("x,y","x "+e+" y")(r,a)}a(e,a,r){(k[r]||(k[r]=t("x,y","new x[y]("+Array(r+1).join(",x[y]")(1)+")")(e,a)}r(e,a,r){n,t,s={},b=s.d=r?r.d+1:0;for(s["$"+b]=s,t=0;t<b;t)s[n="$"+t]=r[n];for(t=0,b=s=a;t<b;t)s[t]=a[t];c(e,0,s)}c(t,b,k){u(e){v[x]=e}f{g=,ting(bg)}l{try{y=c(t,b,k)}catch(e){h=e,y=l}}for(h,y,d,g,v=[],x=0;;)switch(g=){case 1:u(!)4:f5:u((e){a=0,r=e;{c=a<r;c&&u(e[a]),c}}(6:y=,u((y8:if(g=,lg,g=,y===c)b+=g;else if(y!==l)y9:c10:u(s(11:y=,u(+y)12:for(y=f,d=[],g=0;g<y;g)d[g]=y.charCodeAt(g)^g+y;u(String.fromCharCode.apply(null,d13:y=,h=delete [y]14:59:u((g=)?(y=x,v.slice(x-=g,y:[])61:u([])62:g=,k[0]=65599*k[0]+k[1].charCodeAt(g)>>>065:h=,y=,[y]=h66:u(e(t[b],,67:y=,d=,u((g=).x===c?r(g.y,y,k):g.apply(d,y68:u(e((g=t[b])<"<"?(b--,f):g+g,,70:u(!1)71:n72:+f73:u(parseInt(f,3675:if(){bcase 74:g=<<16>>16g76:u(k[])77:y=,u([y])78:g=,u(a(v,x-=g+1,g79:g=,u(k["$"+g])81:h=,[f]=h82:u([f])83:h=,k[]=h84:!085:void 086:u(v[x-1])88:h=,y=,h,y89:u({e{r(e.y,arguments,k)}e.y=f,e.x=c,e})90:null91:h93:h=0:;default:u((g<<16>>16)-16)}}n=this,t=n.Function,s=Object.keys||(e){a={},r=0;for(c in e)a[r]=c;a=r,a},b={},k={};r'
.replace(/[-]/g, function(e) {
return t[15 & e.charCodeAt(0)]
})
}
("v[x++]=v[--x]t.charCodeAt(b++)-32function return ))++.substrvar .length(),b+=;break;case ;break}"
.split("")))
()
(
'gr$Daten Иb/s!l y͒yĹg,(lfi~ah`{mv,-n|jqewVxp{rvmmx,&effkx[!cs"l".Pq%widthl"@q&heightl"vr*getContextx$"2d[!cs#l#,*;?|u.|uc{uq$fontl#vr(fillTextx$$龘ฑภ경2<[#c}l#2q*shadowBlurl#1q-shadowOffsetXl#$$limeq+shadowColorl#vr#arcx88802[%c}l#vr&strokex[ c}l"v,)}eOmyoZB]mx[ cs!0s$l$Pb<k7l l!r&lengthb%^l$1+s$jl s#i$1ek1s$gr#tack4)zgr#tac$! +0o![#cj?o ]!l$b%s"o ]!l"l$b*b^0d#>>>s!0s%yA0s"l"l!r&lengthb<k+l"^l"1+s"jl s&l&z0l!$ +["cs\'(0l#i\'1ps9wxb&s() &{s)/s(gr&Stringr,fromCharCodes)0s*yWl ._b&s o!])l l Jb<k$.aj;l .Tb<k$.gj/l .^b<k&i"-4j!+& s+yPo!]+s!l!l Hd>&l!l Bd>&+l!l <d>&+l!l 6d>&+l!l &+ s,y=o!o!]/q"13o!l q"10o!],l 2d>& s.{s-yMo!o!]0q"13o!]*Ld<l 4d#>>>b|s!o!l q"10o!],l!& s/yIo!o!].q"13o!],o!]*Jd<l 6d#>>>b|&o!]+l &+ s0l-l!&l-l!i\'1z141z4b/@d<l"b|&+l-l(l!b^&+l-l&zl\'g,)gk}ejo{cm,)|yn~Lij~em["cl$b%@d<l&zl\'l $ +["cl$b%b|&+l-l%8d<@b|l!b^&+ q$sign ',
[ TAC = {} ])
var data = TAC.sign(userid + '0');
return data
}
上面的链接拼接完成之后,视频列表可以正常请求了,请求回来的数据取一条看一下。
{
"single_mode": true,
"abstract": "八卦象棋:想重炮将死我,只能对炮了,仅此一步棋可以化解",
"middle_mode": true,
"more_mode": false,
"tag": "video_sports",
"has_gallery": false,
"tag_url": "video",
"title": "八卦象棋:想重炮将死我,只能对炮了,仅此一步棋可以化解",
"has_video": true,
"chinese_tag": "视频",
"source": "八卦讲棋",
"group_source": 2,
"image_url": "http://p99.pstatp.com/list/190x124/111d9000bc384a1e7c376",
"media_url": "/c/user/63387812477/",
"media_avatar_url": "http://p1.pstatp.com/large/9062000424ee2d9e7539",
"video_duration_str": "15:33",
"source_url": "/group/6622421805481067012/",
"article_genre": "video",
"is_feed_ad": false,
"video_id": "v02004740000bfjp2a8m4cim9gian7o0",
"behot_time": 1542366341,
"comments_count": 11,
"video_play_count": 3630,
"group_id": "6622421805481067012"
}
发现并没有视频链接。打开视频详情页。找到一个链接http://ib.365yg.com/video/urls/v/1/toutiao/mp4/v020041d0000bfl6fafrri6cjb9b5rg0?r=990702939595272&s=2968355509&aid=1364&callback=axiosJsonpCallback1&`_`=1542366691315
在返回的数据中看到字段main_url
和backup_url_1
,这是一个base64加密的链接,解密过后发现正是视频的地址
接下来的任务就是解析获取视频信息的链接,继续拆分参数
参数名取值说明r990702939595272变s2968355509变aid1364未知callbackaxiosJsonpCallback1未知_1542366691315变
继续上面的过程,找参数
搜索r,由于太多,搜?r
,找到的各个可疑位置打断点,跟一下。如下图
发现都在这,不仅有r
和s
,而且最后直接返回了链接。
var e = document.createElement("a");
e.href = t;
var n = function() {
for (var t = 0, e = new Array(256), n = 0; 256 !== n; ++n)
t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = n) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1, e[n] = t;
return "undefined" != typeof Int32Array ? new Int32Array(e) : e
}(),
r = e.pathname + "?r=" + Math.random().toString(10).substring(2);
"/" !== r[0] && (r = "/" + r);
var i = function(t) {
for (var e, r, i = -1, o = 0, a = t.length; o < a;)
(e = t.charCodeAt(o++)) < 128 ? i = i >>> 8 ^ n[255 & (i ^ e)] : e < 2048 ? i = (i = i >>> 8 ^ n[255 & (i ^ (192 | e >> 6 & 31))]) >>> 8 ^ n[255 & (i ^ (128 | 63 & e))] : e >= 55296 && e < 57344 ? (e = 64 + (1023 & e), r = 1023 & t.charCodeAt(o++), i = (i = (i = (i = i >>> 8 ^ n[255 & (i ^ (240 | e >> 8 & 7))]) >>> 8 ^ n[255 & (i ^ (128 | e >> 2 & 63))]) >>> 8 ^ n[255 & (i ^ (128 | r >> 6 & 15 | (3 & e) << 4))]) >>> 8 ^ n[255 & (i ^ (128 | 63 & r))]) : i = (i = (i = i >>> 8 ^ n[255 & (i ^ (224 | e >> 12 & 15))]) >>> 8 ^ n[255 & (i ^ (128 | e >> 6 & 63))]) >>> 8 ^ n[255 & (i ^ (128 | 63 & e))];
return -1 ^ i
}(r) >>> 0;
return (location.protocol.indexOf("http") > -1 ? [location.protocol, e.hostname] : ["http:", e.hostname]).join("//") + r + "&s=" + i
看上面代码发现r
、s
、_
三个参数都有了,然后继续往下找aid
,然后断点,发现aid
是一个定值
搜索axiosJsonpCallback
发现变化也不大。
这样链接就凑够了,简单梳理一下js。
function get_url(t) {
var index = 1,aid=1364
var url_split=t.split("ib.365yg.com")
var n = function() {
for (var t = 0, e = new Array(256), n = 0; 256 !== n; ++n)
t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = 1 & (t = n) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1) ? -306674912 ^ t >>> 1 : t >>> 1, e[n] = t;
return "undefined" != typeof Int32Array ? new Int32Array(e) : e
}(),
r = url_split[1] + "?r=" + Math.random().toString(10).substring(2);
"/" !== r[0] && (r = "/" + r);
print(r)
var i = function(t) {
for (var e, r, i = -1, o = 0, a = t.length; o < a;)
(e = t.charCodeAt(o++)) < 128 ? i = i >>> 8 ^ n[255 & (i ^ e)] : e < 2048 ? i = (i = i >>> 8 ^ n[255 & (i ^ (192 | e >> 6 & 31))]) >>> 8 ^ n[255 & (i ^ (128 | 63 & e))] : e >= 55296 && e < 57344 ? (e = 64 + (1023 & e), r = 1023 & t.charCodeAt(o++), i = (i = (i = (i = i >>> 8 ^ n[255 & (i ^ (240 | e >> 8 & 7))]) >>> 8 ^ n[255 & (i ^ (128 | e >> 2 & 63))]) >>> 8 ^ n[255 & (i ^ (128 | r >> 6 & 15 | (3 & e) << 4))]) >>> 8 ^ n[255 & (i ^ (128 | 63 & r))]) : i = (i = (i = i >>> 8 ^ n[255 & (i ^ (224 | e >> 12 & 15))]) >>> 8 ^ n[255 & (i ^ (128 | e >> 6 & 63))]) >>> 8 ^ n[255 & (i ^ (128 | 63 & e))];
return -1 ^ i
}(r) >>> 0;
var _ = (new Date).getTime()
var callback = "axiosJsonpCallback"+index
return "http://ib.365yg.com"+r + "&s=" + i+"&aid="+aid+"&callback="+callback+"&_="+_
};