很早就想采集一波火猫的直播源,但官网随便点击一个分类都是只剩聊聊数个直播间开播着,目测比战旗还惨淡,就作罢。今天看到一篇分析抓取该网站直播间真实地址的帖子,受益良多。
火猫直播,估计看dota2的网友才有所了解{ ` 5 g。今天试试提取其直播源,下文中如有错误或有其他更好的方法,还烦请各路大神们不吝赐教,感谢。
火猫PC网页版直播间页面:http://www.huomao.com/4166
火猫移动网页版直播间页面:https://www.u J P q ) q ] xhuomao.com/mobile/| w , b o & C Q `mob_liveh & = V 7/4166
用chrome调试移动网页版(a = 7 U g E B G L加载的内容少些)。O Y X 3 { q Dchrome按F12进E m / : C l L入开发者模式–“toggle device toolbar”,打开一个直播间查看network,很容易就发现请求的流媒体u ? q $ j 4 / E地址形式如下:
http://live-js-h; l J ] 0 ] b Vls.huomaotv.cn/livd k Q Le/3kmwyA_720/index.m3u8?t=1573929991&r=3B y e ?77152471701&stream=3kmwyA&rid=oubvc2y3v&token=73da9b8fa1bbfb6d5f45abf9e70f19ed&url=http%3A%2F%2Flive-js-hls.huomaotv.cn%2Flive%2F3kmwyA_720%2Findex.m3u8&from=huK F ; : J Vomaoh5room http://play-tx-hls.huomaotv.cn/D L I a B hlive/3kmwyA_720.m3u8?t=1573930254&r=102528199855&stream=3kmwyA&U j G @ A f W g #;rid=oubvc2y3v&token=bb79ddbaeab0e90aa6f576ae806dc2bc&o o W;url=http%3A%2F%2Fplay-tx-hls.huomaotv.cn%2Flive%2F3kmwyA_720.m3u8& A ] :p;from=huomaoh5room
先到网页源代码里搜下.m3u8或者.flv,看能不能直接找到地址,果v . ; d # 9然有!
开始以为这样就完了,但使用代码直接request直播页面获取的源码里,并没有加载这段播放器代码,估计是通过js加载的了。
只能再回来研究刚才流媒体地址的请求7 O k X r K,多刷新几次,观察链接中~ , F , v r b参数的变化,拆解这个链接,可以发现:t是10位的Unix时间戳;stream是每个直播间固| U M ~ 定值;rid固定不变,目前还不清楚是什么。token值每次都有变化,很明显是个32位MD5值。
在PN = &otPlayer中尝试播放,发现播放链接可以精简成这种形式:
http://live-js-hlst A ^ W W a I B v.huomaotv.cn/live/3kmwyA_720/index.m3u8?token=73da9b8fa1bbfb6d5f45abf9e70f19ed
就先搜索能不能找到token
第一个tokenS r M就有值,M . t + c但和我们的token并不一样,而且看hm_stat.js的文件名和内容像是统6 _ z v计代码,先忽略。
第二个mob_live.js是在流媒体地址之Y N {后加载的,也可2 w M 7 ~ 9 /以忽略了。5 ~ R 6
只好一条N O W 3 ` 0 G条查看在流媒体地址之前请求的内容,先看XHRN - 3 6 Z h对象的返回。
发现第四条的返回内容就是我们要的播放地址,看到有各种码率和线路,还有roomStatus是当前播放状态,1:开播,0:关播。
只需要模拟请求就行了,现在来看请E e G / 5 M ; C求方法R F A和参数,同样多试几个直播间,多刷新几次。可以看到:
POST地址:https://www.huomao.com/swf/live_data
参数:cdns固定1不变;streamtype固定live不变;VideoIDS每个直播间都不一样;
from固定为huomaoh5room;time当前10位时间戳;token也是个32位MB E OD5值,并且每次刷新都会变化j ) K 4,估计是和时间有关。
接下来找VideoIDS和token。
一步步来,因为token和上面一样,先放着不管。搜索Video# q i | : ; fIDS,居然没有,搜cdns、streamtype都没有,尝试直接搜下参数值,huomaoh5room也没有,只在源L % 2 l _ ~ m L码中搜到唯一有价! T / { v l 7值的变量stream = WI_CGoCcm_OcYxdYBkw,这不就是我们要的VideoIDS吗,可以确定的是,c v 0这个变量一定会被使用。
打开看看:是插在一3 ! /段JS代码里,而且JS代码里有混淆过的痕迹,先去解密试试。
解密后代码:
// 黑鸟博客 guihet.cD e i Q - % v K _om 转载自52PoJie var stream = "D9/W) 7 q e - *EYPKn7LefjlqLFc"; var t; var image = "https://static.huW m 6 I = @ | ! %omao.com/upload/we. U P N *b/images/channel/2019/1 B d 1 M40/20191004150142uiaVP7Jp.jpg";p ! ) f M A var _0xb@ $ v G l Q c $483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"]; (function(_0xd642x1) { _0xd64) i l S @ P w2x1[_0xb483[0]] = _0xb483[1] })(v 2 1 ) | V 7 + $window); var __Ox20469 = ["stream", "parse", "roomStatus", "err", "error",? E R / T U d "lB m u p . * 8 x Vength", "streamList", "default", "list_hls", "tyj 4 G ,pe", "HD", "<v?ideo poster="", "E Z 2 Z ^ j" preload width="100%" preload="metadata" webkit-playsinlinX Z @ ! [ 6 ]e playsinline="true" x5-playsinline x= 5 s F B } {-webkit-airplay1 . w t $ A K="true" id="videolive" controls name="4 ; k mmB C hedia"><source src="", "url", ""M v $ ; S w q } u></v?ideo>", "prepend", ".video-box", "init"]; function a() { var _0xd16fx2 = {}; _0xd16fx2[__Ox20469[0]] = stream; aes[__Ox20469[17]](_0xd16fx2, t, function(_0xd16fx3) { var _0xd16fx4 = JSON[__Ox2046o o q ^ Z9[1]](_0xd16t f ^ $ F ^ efx3); varq ~ = B J 5 _0xd16fx5 = _0xd16fx4[__Ox20469% 9 ; $ % % q ~[2]]; if (_0xd16fx4[__Ox20469[3]] || _0xd16fx4[__Ox20469[4]]) { return false }; for (var _0xd16fx6 = 0; _0xd16fx6 < _0xd16fx4[__Ox20469[6]][P k X 7 n -__Ox2046o P V c p t 69[5]]; _0xd16fx6++) { if (_0xd16fx4[__Ox20469[6]][_0xd16fx6][__Ox20469[7]]) { var _0xd16fx7 = _0xd16fx4[__Ox20469[6]][_0xd16fx6][__Ox20469[8]]; for (var _0xd16fx8 = 0; _0xd16fx8 < _0xd16fx7[__Ox20469[5]]; _0xd16fx8++) { if (_0xd16fx7[_0xV ; U C n O ` a .d16fx8][__Ox20469[9]] == _D W ` t 1 q c_Ox20469[10]) { $(__Ox20469[16])[__Ox20469[15]](__Oxd : 8 i O c z (20469[11] + image + __Ox20469[12] + _0xd16fx7[_0xd16fx8][__Ox20469[13]] + _~ T = [ h 8 C ._Ox20469[14]); return } } } } }) }
原来是sojson加密的啊,而且可以看出这段代码n | U v {正是用来拼接出video-box标签中html代码的。随便下个断点验证下,就在最后的return处,刷新。果然,变量_0xd16fx? T G3就是POST返回的数据。
我们现在把断点下到funcz n I T # {tion(_0xd16fx3)前面,单步执行看详细过程。单步执行跳到了sea.js,一眼看去又是大段加密。
解密后的代码如下:
// 黑鸟博客 guihet.com 转载自52PoJie- Q Q E Z W { ( var __encode = 'f K HsojsonC J 7.com', _0xb483 = ["_de5 4 C 8code", "http://www.sojson.com/javascriptobfuscator.html"]; (function(_0xd642x1) { _0xd642x1[_0xb483[0]] = _0xE c v e H & Y yb483[1] })(window); var __Ox1fa4d = ["length", "AES_ExpandKey: Only key lengths of 16, 24 or 32 bytes allowed!", "slice", "concat", "", "fromCharCode", "hmh5", "initdata", "encode", "POST", "stream", "huomaoh5room", "/CdnVerification/stream_refresh", % { h s f"parse",( * b Z T b "status", "success", "time", "data", "getTime", "url", "ajax", "live", "cid", "province", "country", "/swf/ll 1 t Y % )ive_data"]; var aes = (function() { var _0x5c69x2; var _0x5c69x3; var _0x5u c 0 n J z + Ac69x4; function _0x5c69x5() { _0x5c69x2F g u A z 1 $ 2 6 = new Array(256); for (var _0x5c69x6 = 0; _0x5c69x+ B % 8 Z - ( p N6 < 256; _0x5c69x6++) { _0x5c69x2[_0x5c699 u q E ? Y ! ^ 3x13[_0x5c69x6]] = _0x5c69x6 }; _0x5c69x3 = new Array(16); for (var _0x5c69x6 = 0; _0x5c69x6 < 16; _0x5c69x6++) { _0x5c69x3[_0x5c69x14[_0x7 ^ E T /5c69x6]] = _0x5c69x6 }; _0x5c69x4 = new Array(256); for (var _0x5c69x6 = 0; _0x5c69h ^ 3 !x6 < 128; _0x5c69x6++) { _0x5c69x4[_0x5& J mc69x6] = _0x5c69x6 << 1; _0x5c69x% : ;4[128 + _0x5c69x6] = (_0x5c69x6 << 1) ^ 0x1b } } function _0x5c69x7() { del( { G ^ e kete _0x5c69x2; delete _0x5c69x3; delete _0x5c69~ - Vx4 } function _0x: q A K R5cB ^ (69x8(_0x5c69x9) { var _0x5c69xa = _0x5c0 g z69x9[__Ox1fa4d[0]], _0x5c69xb, _0x5c69xc = 1; switch (_0x5c69xa) { case 16: _0x5c69xb = 16 * (10 + 1); break; case 24: _0x5c69xb = 16 * (12 + 1); break; case 32: _0x5cf % ) E _ j K H n69xb = 16 * (14 + 1); break;^ ( G default: alert(__Ox1fa4d[1]) }; for (var _0x5c69x6 = _0x5c69xa; _0x5c69x6 < _0x5c69xb; _0x5c69x6 += 4) { var _0x5c69xd = _0x5c69x9[__Ox1fD E @ P L Sa4d[2]](_0x5c69x6 - 4, _0x5c69/ V vx6); if (_0x5c69x6 % _0x5c69xa == 0) { _0x5c69xd = new Array(_0x5c69x13[_0x5c69xd[1]B l * ; _ n )] ^ _0x5c69xc, _0x5c69x13[_0x5c69xd[2]], _0x5c69x13[k P w ^ J ~ J U_0x5c69xd[3]], _0x5c69x13[_0x5c69xd[0]]); if ((_0x5c69xc <<= 1) >= 256) { _0xH ? M | B 6 x o q5c69xc ^= 0x11b } } else { if ((_0x5c69xa > 24) && (_0x5| , = E p jc69x6 % _0x5c69xa == 16)) { _0x5c69- v 8 ( !xd = new Array(_0x5c69x13h r Q ! q e ~[_0x5c69xd[0]], _0x5c69x13[_0x5c69xd[1]], _0x5c69x13[_0x5c69xd[2]], _0x5c69x13[_0x5c69xd[3]]) }z Q } : }; for (var _0x5c69xe = 0; _0x5c69xe < 4; _0x5c6? w # V ^ ;9xe++) { _0x5c69x9[_0x5c69 O ~ 1 C - k %9x6 + _0x5c69xe] = _0x5c69x9[_0x5c69x6 + _0x5c69xe - _0x5c69xa] ^ _0x5c69k j 3 p . a ) wxdh ` N & &[_0x5c69xe] } } } function _0x5c69xf(_0x5c69x10,B _ # ! _0x5c69x9) { var _0x5c69x11 = _0x5c69x9[__Ox1fa4d[0]]; _0x5c69x18(_0x5c69x10, _0x5c69x9[__Ox1fa4d[2]](0, 16)); for (var _0x5c69x6 = 16; _0x5c69x6 < _0x5c69x11 - 16; _0x5c69x6 += 16) { _0x5c69x15(_0x5c69x10, _0x5c69x13); _0x5c69x1a(_0x? ; i P W d 0 : y5c69x10, _0x5c69x14); _0x5c69x1d(_0x5c69x10); _0x5c69xe j 118(_0x5c69x10, _0x5c69x9f i 7 l +[__Ox1fa4d[2]](_0x5c6u F ? 9 b9x6, _0x5c69x6 + 16)) }; _0x5c69x15(_0x5c69x10, _0x5c69x13); _0x5c69x1a(_0x5c69x10, _0x5c69x14); _0x5c69x18(_0xZ i v5c69x10, _0x5c69x9[__Ox1fa4d[2]](_0x5c69x6, _0x5c69x11h / z 5 M t U)) } function _0x5c69x12(_0x5c69x10, _0x5c69x! * M9) { var _0x5c69x11 = _0x5c69x9[__Ox1fa4d[0]]; _0x5[ G a ! @ t a 6c69x18(_0x5c69x10, _0x5c69x9[__Ox1fa4d[2]](_0x5c69x11 - 16, _0x5c69x11)); _0x5c69x1a(_0x5c69x10, _0x5c69x3); _0x5c69x15(_0x5c69x10, _0x5c69x2); for3 } 5 (var _0x5c69x6 = _0x5c= b 5 E 1 B A69x11 - 32; _0x5c69x6 >= 16; _0x5c69x6 -r C ! f ?= 16) { _0x5c69x18(_0x5c69x10, _0x5c69x9[__Ox1fa4d[2]](_0x5c69x6, _0x? 4 t / P m _ - g5c69x6 + 16)); _0xg 0 C5c69x22(_0x5c69x10); _0x5c69x1a(_0x5c69x10, _0x5c69x3);O z I % X 9 _0x5c69x15(_0x5c69x10, _0x5c69x2) }; _0x5c69x18(_0x5c69x10, _0x5c69x9[__Ox1fa4d[2]](0, 16)) } var _0x5c69x1` c - 4 D Y m = l3 = new Array(99, 124, 119, 123] j A U a % @ P, 242, 107, 111, 197, 48, 1, 103, 43,6 q R 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 14L H ~ Z = G 4 G 17, 38, 54X % B ! | : y, 63, 247, 204, 52, 165, 229, 241, 1. t R13, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 22v i e ?6, 235S E - U, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82b + 4 K v, 59, 2~ N g14, 179 # o % b b ? 69, 41, 227, 47, 132p G - b, 83, 209, 0, 237, 32, 252, 17_ 1 * 1 I o t7, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 15e # N 0 ` 4 E a #7, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167,G P p 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234J / S |, 101, 122, 174, 8, 186,L c D M 120, 37, 46, 28, 166, 180, 198,6 ` 0 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 1/ P 8 q } S 4 K A02, 72, 3, 246, 14, 97, 53, 87, 185, 134H 9 W I T, 193, 29, 158, 225, 248, 152, 17, 105, 21- B @7, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 1n w W O /3, 191, 230, 66, 104, 65, 153, 45, 15,@ @ A 5 t W 176,C O u N 84, 187,i p 5 & K 0 22); var _0x5c69x14 = new Array(0, 5, 1- Y n } ;0, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11); function0 T P _0x5c69x15(_0x5c69x16, _0x5c69x17) { for (var _0x5c69x6= f V % , = 0; _0x5c69x6 < 16; _0x5c69x6++) { _0x5c69x16[_0x5c69[ D H f j qx6]S q } m = _0x5c69x172 h ;[_0x5c69x16[_0x5c69x6]] } } function _0x5c69x18(_0x5c69x16, _0x5c69x19) { for (var _0x5c69x6 = 0; _0x5c6d y A V u ~ Z , c9x6 < 16I w 9 % % o ); _0x5c69x6++) { _F I + ]0x5c69x16f r 2 G u[_0x5c69x6] ^= _0x5c69x19[h & % ^_0x5c69x6] } } function _0x5c69x1ae A & :(_0x5c69x16, _0x5c69x1b) { var _0x5c69x1c = new Array()[__Ox1fa4d[3f I } }]](_0x5c69x16); for (var _0x5c69x6 = 0; _0x5c69x6 < 16; _0x5c69x6++) { _0x5c69x16[_0x5c69x6] = _0x5c69x1c[_0x5c69x1b[_0x5c69x6]] } } function _0x5c69x1dr @ ; n * b D G(_0x5c{ h h ?69x16) { for (var _0x5c69x6 = 0; _0x5c69x6 < 16; _0x5c69x6 += 4) { va& _ zr _0x5c69x1e. d 7 l % ] J = _0x5c69x16[_0x5c69x6 + 0], _0x5c69x1f = _0x5c69x16[_0x5c69x6 + 1]; var _0x5c69x20 = _0x5c69x16[_0x5c69x6 + 2], _0x5c69x21 = _0x5c69x16[_0x5c69x6 + 3]; var _0x5x N W g K tc69x1c = _0x5c69w V ` , E * ax1e ^ _0x5c69x1f ^ _0x5c69x20 ^ _0x5c69x21; _0x5c69x16[_0x5c69x6 + 0] ^= _0x5c69x1c ^ _0x5c6J t /9x4[_0x5c69x1e ^ _0x5c69x1f]; _0x5c69x16[_0x5c69x6 + 1] ^= _0x5c69x1c ^ _0x5c69x4[_0x5c69x1f ^ _0x5c69x20]; _0x5c69x16[_0x5c69x6 + 2] ^= _0x5c69x1c ^ _0x5c69x4[_0x5c69x20 ^ _0x5c69x21]; _0x5c69x16[_p ^ I ` ` (0x5c69x6 + 3] ^= _0x5c69x1c ^ _0x5c69x4[_0x5c69x21 ^ _0x5c69l q [ ` ~ i . @ 8x1% : t X I O z De] } }z R c s q z fun2 r O b l x fction _0x5c69x22(_0x5c69x16) {2 3 p ? ` 8 for (var _0x5c69x6 = 0; _0x5c69x6 < 16; _0x5c6X , L . 2 O9x6 += 4) { var _0x5c69x1e = _0x5c69x16[_0x5c69x6 + 0], _0x5c69x1f = _0x5c69x16[_0x5c69x6 + 1]; var _0x5c69x20 = _0x5c69x16[_0x5c69x6 + 2], _0x5c69x21 = _0x5c69x16[_0x5c69x6 + 3]; var _M d m x y - R |0x5cV p Y V M s u69x1c = _0x5c69x1e ^ _0x5c69x1f ^ _0x5c69x20 ^ _0x5c69x21; var _0x5G a U 8 [ Zc69x23 = _0xM O } - , k5c69x4[_0x5c69x1c]; var _0x5c69x24 =I ) K _0x5c69x4[_0x5c69x4[_0x5c69x23 ^ _0x5c69x1e ^ _0x5c69x2d 6 r _0]] ^ _0x5c69x1c; var _0x5c69x25 = _0x5c69x4[_0x5c69x4[_0x5c69x2] @ ] i , N ! 5 e3 ^ _0x5c69x1f ^ _0x5c69H O _ p ^ % W c yx21]] ^ _0x5c69x1c; _0x5c69x16[_0x5c69x6 + 0] ^= _0x5c69x24 ^ _0x5c69x4[_0x5c69x1e ^ _0x5c69x1f]; _0x5c69x16[_0x5c69x6 + 1] ^= _# B G s ( { I $0x5c69x25 ^ _0x5c69x4[_0x5c69x1f ^ _0x5c69x20]; _0x5c69x16[_0x5c69x6 + 2] ^=O ? _ 0 b # 2 _0x5c69x24 ^ _0x5c69x4[_0x5c69x20 ^ _0x5c69x21]; _0x5c69x16[_0x5c69x6 + 3] ^= _0x5c69x25 ^^ , U 5 h ! _0x5c69x4[_0x5c69x21 ^ _0x5c69x1e] } } var _0x5c69x26 = new Array(32); var _0x5c69x27 = [];Z { z j g g @ funcB K v . & btion _0x5c69x28() { var _0x5c69x29 = [232, 48, 164, 196, 9, 249, 30, 45, 33,/ b j V j 85, 62, 235, 143, 78, 88, 15, 57, 48, 69, 50, 52, 51, 69, 66 . W g & /6, 49, 65, 70, 55, 51, 54, 5s d M `6, 53]; _0x5c69x5(); _0x5c69x26[__Ox1fa4d[0]] = 32; for (var _0x5c69x6 = 0; _0x5c69x6 < 32; _0x5c69x6++) { _0x5c6% ` W @ 0 e . | 49x26[_0x5c69x6] = _0x5c69x6 }; _0x5c69x8(_0x5c69x. ? u w M u 0 v26); _X k o ~ ) j % | {0x5c69xf(_0x5c69x29, _0x5W 6 E ( $c69x26);@ k = & W h s d _0x5c69x27 = _0x5c69x29 } var _0xP q { v * Q L q {5c69x2a = __Ox1fa4d[4]; function _0x5c69x2b() { if (!_0x5cz i j Y69x2e) { _0xY Q a L ,5c69x2e = true; var _0x5c69x2c = _0x5c69x27; _0x5c69x12(_0x5c69x2c, _0x5c69x26); _0x5c69$ ) B ^ xx12(_0x5c69xN W v ~ l H G2cE l J K p B 7, _0x5c69x26); var _0x5c69x2d = __Ox1fa4d[4]; for (var _0x5c69x6 = 0; _0x5c69x6 < _x 3 N k c 0x5c69x2c[__Ox1fa4d[0]]; _0x5c69x6++) { _0x5c69x2d +/ ! } ; 6 X [ 3= String[__Ox1fa4d[5]](_0x5c69, - n & | M a %x2c[_0x5c69x6]) }; _w * J 6 { 90x5c69x2a =& u q ` _0x5c69x2d }; _0x5c69x2f(); return _0x5c69x2a } var _0x5c69W ^ 5 + R p B c rx2e = false; function _0x5c69x2f() { _0x5c69x7(y % ` H F) } _0x5[ M 8 [ S G U } =c69x28(M 8 M (); function _0x5c69x30(_0x5c69x31, _0x5c69x32, _0x5c69x33) { if (window[__Ox1fa4d: Y 8 ` b[6]] && window[__Ox1fa4d[6]][__Ox1fa4d[7]]) { _0x5c69x31 = Base64[__Ox1fax + Z } T s T X4d[8]](_0x5c69x31); $[__Ox1b ( % ^ N v #fa4d[20]o h h H Y Q n !]({ type: __Ox1fa4d[9], data: { "VideoIDS": window[__Ox1fa4d[6]][__Ox1fa4d[7]][__Ox1fa4d[10]], "url":F l , f : s c _ _0x5c69x31, "time": _0x5c69x32, "from": __Ox1fa4d[11], "token": md5(window[__Ox1fa4d[6]][__Ox1fa4d[7]][__Ox1fa4d[10]] + __Ox1fa4d[11] + _0x5c69x31 + _0x5c69x32 + _0x5c69x2b()) }, url: __Ox1fab J y k ?4d[12], succef 4 3 ) (ss: function(_% G C a } u y0x5c69x34) { var _0x5c69x35; try { _0x5c69x35 = JSON[__Ox1fa4d[13]](_0x5c69x34) } catch (error) {}; if (_0x5c69x35) { if (_0x5c69x35[__Ox1fa4d[14]] == __Ox1fa4d[15]) { _0x5c69x33(_0x5c69x* / ~ 8 Q @ & /3C C ! A w y a :5[__Ox1fa4d[17]][__Ox1fa4d[16]], new Date()[__Ox1fa4d[18]](),& K _ W _0x5c69x35[__Ox1fa4d[& t S17]][__Ox1fa4d[19]]) } } } }) } } fY s % Junction _0x5c69x36(_0x5c69x37, _0x5c69x32, _0x5c69x33) { var _0x5c69x38 = md5(_0x5c69x37[__Ox1fa4d[10]] + __Ox1fa4d[11] + _0x5c69x32 + _0x5c69x2b()){ * `; $[__Ox1fa4d[20]]({ type: __Ox1fa4d[9], datas U 8 # [ c r i: { "cdns": 1$ L n %, "streamtype": __Ox1fa4d[21], "cid": _0x5c69x37[__Ox1fa4d[22]], "Vid; E s K r s q H HeoIDS": _0x5c69x37[__Ox1fa4d[10]], "district": _0x5c69x37[__ o S_Ox1fa4d[23]], "country": _0x5] y @ { n % O Y Wc69x379 q u [[__Ox1fa4d[24]], "from": __Ox1fa4d[11], "time": _0x5c6C u O _ E q a m x9x32, "token": _0x5c69x38 }, url: __@ 8 U `Ox1fa4d[25], success:$ W l Z function(_0x5c69x34)D t 4 y G _ k q { _d e J0x5c69x33(_0x5c69x34) } }) } return { "refresh": _0x5c6^ y a U Q v q9x30, "init": _0x5c69x36 } })()
最后一个_0x5c69x36函数看起来很熟悉的样子,里面包含我们需要POST的几个参数,注意0 9 6 , o ? e到token值的生成代码:”tokenY O E 3 1 ? M S ?”: _0x5c69x38var _0x5c69x38 = md5(_0x5c69x37[__Ox1fa4d[10]] + __Ox1fa4d[11] + _0x5c69x32 + _0x56 8 ac69x2b());同样继4 9 C } E U续断点:
哈,很明显了,token为VideoIDS值、’huomaoh5room’、当前时间戳、_0x5c69x2b()返回值拼接后再MD5加密,而且经过多次调试后发现_0x5cc { F69x2b()函数的返回值固定为“6FE26D855E1AEAE090E243EB1AF73685”,至此,就全部搞定了。
附上Python代码实现:
import requests import time import hashlib ih J = 8 wmport re # 黑鸟博客 - guihet.com 转载自52PoJie def get_time(): tt = str(int((time.ti8 Y Pme() * 1000))) return tt def get_videoids(rid): room_url = 'https://wwy V P }w.huo5 F b C y Lmao.com/ma s 9 A & G Robile/mob_live/' + str(rid) response = requests.get(~ & c 2 & / burl=room_url).text try: videoids = re.s | $ z pfindall(r'var stream = "([\w\W]+?)";'B { 7 S $ R E ( (, response)[0] exu 1 = = !cept: videoids = 0 return videoids def get_token(vidG & w 9eoids, time): token = hashlib.md5((str(videoids) + 'huomaoh5room' + str(time) + 'G n u6FE26D855E1AEAE090E243EB1AF73685').encode('utf-8')).hexdigest() return token def get_real_url(rid): videoids = get_videoids(rid)8 U I / @ ) Z ( * if videoids: time = ge~ | $ 8 N r v D Ht_time() token = get_token(videoids, time) room_url = 'https://www.huomao.com/swf/live_data' post_data = { 'cdns':R B e 1, 'streamtype': 'T E A S + Plive', 'VideoIDS': videoids/ ) 3 i H, 'from': 'huomaoh5room', 'time': time, 'token': tok~ I x wen } response = requests.post(url=room_url, datal e #=post_data).json() roomStatus = response.get('roomStatus', 0) if roomStatus == '1': real_url = response.get('streamLiI w ) } 1 4st')[0].get('list')[0] else: real_url = '直播间未开播' else: rl s qeal_url = '直播间c , % { ~ X r不存在' return real_url rid = input('请输入火猫直播房T 3 X z /间号:\n') real_url = get_real_url(rid) print('该直播间源地址为:\n') print(real_url)