逆向目标:请求参数_sn
打开F12
,出现无限debugger
,跟踪堆栈,发现是通过constructor
方式进行拦截,因此通过以下hook代码片段进行hook:
let _constructor = constructor; Function.prototype.constructor = function(arg){ if(arg == "debugger"){ return null; } return _constructor(arg); }
过掉无限debugger
后,全局搜索_sn
,发现无法找到相关信息,由于其请求方式为xhr
,可通过跟踪堆栈的方式来去找相关参数的加密位置。
通过跟踪堆栈发现,其参数生成的位置如下:
点进CA
函数,并在该函数的h = i[j](c, d, e)
打下断点,可以发现,第三次执行该函数时,参数c
中有_sn
的参数值。
进入i[j]
函数,可以发现"_ts"
是通过时间戳的方式生成,而_sn
则通过以下位置生成。
点进函数_0xe7fex35
,下断点调试,可以定位到生成位置:
其中,_0xe7fex34
为固定值:"c9d6618dbc657b41a66eb0af952906f1"
,__Ox2133f[48]
值为slice
,参数生成的过程为先将Object对象_0xe7fex39
通过JSON.stringify
变为字符串,然后拼接上固定参数,再用_0xe7fex2[__Ox2133f[40]]
函数进行加密,最后从生成的字符串中第二位开始截取10位。
点进_0xe7fex2[__Ox2133f[40]]
函数,确定了加密位置如下:
跟入相关函数,发现其特征值与MD5
相同,并通过deepseek
分析,该函数为标准的MD5
加密:
最后,扣下以下代码,对MD5
加密后的数据进行处理,即可获得_sn
参数
_0xe7fexf = function(_0xe7fex1d) { var _0xe7fex16 = __Ox2133f[24], _0xe7fex24; for (_0xe7fex24 = 0; _0xe7fex24 < 4; _0xe7fex24 += 1) { _0xe7fex16 += _0xe7fexe[(_0xe7fex1d >> (_0xe7fex24 * 8 + 4)) & 0x0f] + _0xe7fexe[(_0xe7fex1d >> (_0xe7fex24 * 8)) & 0x0f] } ;return _0xe7fex16 } , _0xe7fex10 = function(_0xe7fex15) { var _0xe7fex1c; for (_0xe7fex1c = 0; _0xe7fex1c < _0xe7fex15[__Ox2133f[4]]; _0xe7fex1c += 1) { _0xe7fex15[_0xe7fex1c] = _0xe7fexf(_0xe7fex15[_0xe7fex1c]) } ;return _0xe7fex15[__Ox2133f[25]](__Ox2133f[24]) }