简单探究某站指纹参数算法
近期较忙,这个是6月的最后一篇文章啦。后续要写什么我还需要好好思考。
本文仅供学习交流,因使用本文内容而产生的任何风险及后果,作者不承担任何责任,一起学习吧
目标接口: 个人主页info
接口情况如下:
确认逆向参数
dm_img_str
dm_cover_img_str
dm_img_inter
w_webid
w_rid
wts
本文的重点是dm_img_str
和dm_cover_img_str
,w_rid
现在网络上有不少文章相信你一定可以读懂的,所以就不将重点放在这个参数上。接下来,请跟着我一步步去分析,看看遇到一个逆向参数问题,我是如何思考的。
逆向“搜”当先
面对复杂的参数,先不要慌张,直接搜索片段,看看它是否能够被搜到。它可能来源于其他包,有可能就是一个简单的固定值,不要因为长而乱就自乱阵脚。
通过搜索,我们发现w_webid
就是主页HTML返回的
很好,那我们可以打上断点看看,到底是个什么情况。
<script id="__RENDER_DATA__" type="application/json">那串乱码</script>
<script type="text/javascript">var element = document.getElementById("__RENDER_DATA__"); var innerText = element ? element.innerText : "{}"; window._render_data_ = JSON.parse(decodeURIComponent(innerText)); setTimeout(function() {window.location.reload(true);}, 86395 * 1000);</script>
简单分析我们可以知道,它将这段乱码通过JSON.parse(decodeURIComponent())
函数赋值给了window._render_data_
那么这个参数我们就搞定了。接下来看看dm_img_str
参数分析
还是一样,先搜后看堆栈。
搜索结果如下:
不知道对不对,先进去打上断点。逆向永远是在试错的路上
这里我们可以发现,这些参数均来自
[s,c,l,u] = window.__biliUserFp__.queryUserLog({
...i,
target: a
});
在这里打上断点,刷新。向下步入。欸,我们进入了
看文件名字,基本上就知道是这个没错了。让我们找到函数的出口,向上看。
在函数出口(return)处打上断点,看看我们找到位置是否正确,同时向上看思考更加清晰明确。
很好,基本确定是这里。接下来就是简单的函数扣取和函数简化。
function fp(_0x645cbb) {
var _0x504ef3 = _0x24be7c // 如果你对ob混淆很熟悉,那么这个还原会很简单。
, _0x2d5ecc = _0x645cbb[_0x504ef3(0x11e)]
, _0x268943 = _0x645cbb['startTime']
, _0x366fc6 = _0x645cbb['endTime']
, _0x44234a = _0x645cbb[_0x504ef3(0xbc)];
if (!this[_0x504ef3(0xaf)]) {
var _0x398e6b = window[_0x504ef3(0xb9)];
this[_0x504ef3(0x10a)](_0x398e6b || {});
}
var _0x45e018 = function(_0x5c3c27) {
var _0xd43606 = _0x504ef3
, _0x1a00cf = _0x5c3c27[_0xd43606(0x8c)](function(_0x436c1d, _0x1c4ea4) {
var _0x2f1045 = _0xd43606
, _0x489e4e = _0x436c1d['x']
, _0x3168c2 = void 0x0 === _0x489e4e ? 0x0 : _0x489e4e
, _0x45fa28 = _0x436c1d['y']
, _0x384e98 = void 0x0 === _0x45fa28 ? 0x0 : _0x45fa28
, _0x510a04 = _0x436c1d[_0x2f1045(0xa2)]
, _0x5ce436 = _0x436c1d[_0x2f1045(0x113)]
, _0x8a367f = _0x436c1d[_0x2f1045(0x104)];
return _0x3e1d8f(_0x3168c2, _0x384e98, _0x510a04, _0x5ce436, _0x1c4ea4, _0x8a367f);
})
, _0x532efb = _0x1a00cf['map'](function(_0x2d90b5) {
return {
'x': _0x2d90b5[0x0],
'y': _0x2d90b5[0x1],
'z': _0x2d90b5[0x2],
'timestamp': _0x2d90b5[0x3],
'k': _0x2d90b5[0x4],
'type': _0x2d90b5[0x5]
};
});
try {
return JSON[_0xd43606(0x129)](_0x532efb);
} catch (_0x8d1795) {
return console[_0xd43606(0x97)](_0x8d1795),
'';
}
}(_0x2d5ecc ? this[_0x504ef3(0xaf)][_0x504ef3(0xe2)](_0x2d5ecc) : this[_0x504ef3(0xaf)]['getLog'](_0x268943, _0x366fc6));
return [_0x45e018, _0x28b679(this[_0x504ef3(0xaf)]['webglStr']), _0x28b679(this['instance'][_0x504ef3(0x9a)]), this['instance']['getActiveFeaturesStr'](_0x44234a)];
}
还是一样,缺什么补什么,这里仁者见仁智者见智,你可以缺的扣,也可以直接改写函数。但是最重要的还是你自己去跟
_0x504ef3
:这个就是字符串还原。我们从下面往上分析代码,发现这个函数返回值不关心前面部分。
var _0x504ef3 = _0x24be7c
, _0x2d5ecc = _0x645cbb[_0x504ef3(0x11e)]
, _0x268943 = _0x645cbb['startTime']
, _0x366fc6 = _0x645cbb['endTime']
, _0x44234a = _0x645cbb[_0x504ef3(0xbc)];
if (!this[_0x504ef3(0xaf)]) {
var _0x398e6b = window[_0x504ef3(0xb9)];
this[_0x504ef3(0x10a)](_0x398e6b || {});
}
那么分析重点就是_0x45e018
,这个是一个自执行函数的返回值,还是一样,直接去找函数出口(return),JSON['stringify'](_0x532efb);
,就是这样一步步向上找,分析。最后你会发现这个就是个空列表,那么这甚至不用写成函数。接着看剩下三个,还原算法不算难,这里我只放几个关键图片,大家自己去动手分析(也为了防止伸手党)。
小结
这个指纹算法确实不算难,大家认真分析绝对是没啥问题的。这段时间太忙了,简单水个文章哈哈哈