火猫直播间视频源真实地址分析

很早就想采集一波火猫直播源,但官网随便点击一个分类都是只剩聊聊数个直播间开播着,目测比战旗还惨淡,就作罢。今天看到一篇分析抓取该网站直播间真实地址的帖子,受益良多。

火猫直播间视频源真实地址分析
火猫直播,估计看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&amp 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)