LotusRain 2025-09-29 17:59 上海
看雪论坛作者ID:LotusRain

🖼️ **图片接口参数解析与指纹生成:** 文章详细分析了Vaptcha图片接口的请求体,重点关注`vi`、`k`和`en`等关键参数。其中,`en`参数的生成涉及多个子变量,包括基于Canvas指纹(`GenerateFP`)的生成,以及通过`sent()`函数获取的特定值。Canvas指纹的生成过程通过`getComplexCanvasFingerprint`函数实现,利用Canvas绘制特定文本和图形后转换为Base64,再经过CRC32加密得到。文章强调了不同环境下的Canvas指纹可能存在差异,并提及了批量稳定绕过指纹的挑战。
⚙️ **Promise链与数据流追踪:** 在分析`en`参数生成过程中,文章深入追踪了JavaScript中Promise的执行流程。通过对`getImage`接口调用栈的回溯,揭示了Promise链式调用如何逐层传递参数,以及`_0x1e72d1`函数在其中扮演的关键角色。文章详细说明了Promise在不同状态下的处理逻辑,以及如何通过`onFulfilled`函数获取和处理中间结果,最终将这些结果用于构建`en`参数。这种细致的流程分析对于理解混淆代码的执行至关重要。
🔒 **验证接口参数与数据还原:** 对于验证接口,文章同样进行了深入分析,发现其`en`参数的生成逻辑与图片接口类似,但增加了更多与用户行为(如鼠标轨迹)相关的参数,如`dt`、`ch`、`cw`、`p`等。文章详细解析了这些参数的来源,包括时间差、Canvas尺寸、轨迹数据处理(`assemblyCoordData`)以及`globalPow`等。此外,文章还介绍了如何根据图片接口返回的`img_order`字段,利用`Decrypt`函数还原被乱序的验证图片,以及`vaptchanu`和`vaptchaut`等本地存储值在验证过程中的作用。
💡 **核心变量与加密函数分析:** 文章对构成`en`参数的各个变量进行了逐一梳理和分析,包括Canvas指纹、`sent()`函数返回值、MD5哈希计算(`hex_md5`)、以及通过`localStorage`获取的特定值。文章还提到了`uaDelExtra`、`compareDfu`等辅助函数的作用。对于`_0x101aa8`等复杂的匿名函数,文章通过追踪其内部属性的赋值过程,揭示了`ha`、`hb`、`globalMd5`等变量的生成逻辑,为理解整体加密机制提供了关键线索。
LotusRain 2025-09-29 17:59 上海
看雪论坛作者ID:LotusRain
Initiator中的Request call stack定位,如获取图片的接口。vi是固定的,应为网站标识。然后根据刚才的链路分析或者搜一下k参数的值可知k参数就是config接口返回的knock参数(这里是不同的两次请求,故图中的值不一样)接下来重点分析一下en参数的生成。先跟着调用栈进去看一下,找到请求体_0x45bdb3["data"]就是完整的请求体_0x45bdb3就是当前函数的入参跟着调用栈回溯看下_0x45bdb3是怎么生成的_0x45bdb3就是在这里组成的对象,其中data的值就等于_0x26b8e6,继续跟_0x1e0f55就是data的值,往上面看还能看到en就是对应_0xad7777,至此就可以专注分析en值的生成了。en参数分析跟一下en,也就是_0xad7777的生成逻辑_0xad7777的生成和_0x23221c有关,而_0x23221c也是由一堆其他变量相加得到的_0x23221c = _0x392e9d + _0xb049bd + _0x4eecbb + _0x1e45dc + _0xb0124 + _0x2d7772 + _0x1ac30b + _0xc3f820 + _0x1a6817 + _0x37ab28 + _0x101aa8["globalMd5"]["slice"](0, 5);
先来挨个分析这些变量的值是怎么生成的,最后再用encryFunc处理一下就行了。_0x354394["GenerateFP"](),看下这个函数是干啥的(根据函数名猜测和指纹有关)_0x1533a3["prototype"]["GenerateFP"] = function(_0x4d082f) {
var _0xfe3533 = this["getComplexCanvasFingerprint"](_0x4d082f);
return this["extractCRC32FromBase64"](_0xfe3533);
}
getComplexCanvasFingerprint这个函数_0x1533a3["prototype"]["getComplexCanvasFingerprint"] = function(_0xb1e678) {
if (_0xb1e678 === undefined) {
_0xb1e678 = '';
}
var _0x58de07 = "BrowserLeaks,com <canvas> 1.0" + _0xb1e678;
var _0x21cb9e = document["createElement"]("canvas");
_0x21cb9e["setAttribute"]("width", "220");
_0x21cb9e["setAttribute"]("height", "30");
var _0x3b1a5e = _0x21cb9e["getContext"]("2d");
_0x3b1a5e["textBaseline"] = "top";
_0x3b1a5e["font"] = "14px 'Arial'";
_0x3b1a5e["textBaseline"] = "alphabetic";
_0x3b1a5e["fillStyle"] = "#f60";
_0x3b1a5e["fillRect"](125, 1, 62, 20);
_0x3b1a5e["fillStyle"] = "#069";
_0x3b1a5e["fillText"](_0x58de07, 2, 15);
_0x3b1a5e["fillStyle"] = "rgba(102, 204, 0, 0.7)";
_0x3b1a5e["fillText"](_0x58de07, 4, 17);
return _0x21cb9e["toDataURL"]();
}
extractCRC32FromBase64函数,就是通过Canvas生成一段具有特征的base64,在进行加密处理生成最终的指纹值,其中Canvas绘图时还会根据入参_0xb1e678来生成不同的文本。不同设备(环境)的Canvas指纹一般是唯一的,在结合具体网站应用上,使用当前浏览器生成的指纹,或用node、playwright、python相关库之类的环境去模拟生成指纹去做请求,大多数情况下都是不稳定的甚至是完全没法用的,如何批量稳定的绕过这里暂且不讨论了这里的
extractCRC32FromBase64函数可以整体扣下来或转换为Python代码。_0x23367b["sent"](),跟一下之后遇到的处理流程中涉及sent的en参数的也和接下来要分析的流程类似,故只以当前流程为例进行详细分析其实现的位置为var _0x4bd611 = {
"label": 0x0,
"sent": function() {
if (_0x1df4cd[0] & 1)
throw _0x1df4cd[1];
return _0x1df4cd[1];
},
"trys": [],
"ops": []
}, _0x5d578d, _0x5a9fe5, _0x1df4cd, _0xe388ef;
sent中return语句,而sent中只有简单的取值,也就是说在调用sent之前,即走到case 1块之前,_0x1df4cd[1]的值就已经生成了,那先看一下这个东西是在哪赋值的。搜一下这个变量名,可以发现对其的赋值操作主要集中在_0x1e72d1这个函数中_0x1df4cd的值可能和_0x49bd55有关该函数主要围绕_0x49bd55这个入参,同时也会走下面的逻辑重新赋值_0x49bd55 = _0x41c1ce["call"](_0x160280, _0x4bd611);
这里的函数调用内容是会发生变化的,暂时只用关注当前_0xb049bd这个en参数的流程。可以刷新一下重新跟一下getImage流程,看下_0x49bd55或_0x1df4cd怎么来的getImage流程对应的函数返回的是经_0x52fdcb函数处理的一个值,稍微看一下这个函数可知最后它返回的是一个Promise对象然后_0x52fdcb的第四个函数参数返回的是一个经_0x5513de函数处理的值_0x1e72d1函数有关。继续跟(或者结合这些流程稍微梳理一下),就能看到_0x41c1ce["call"](_0x160280, _0x4bd611)的返回值,即_0x49bd55是_0x5513de函数的第二个函数参数中case 0块的返回值,即对应上述分析的第一个en参数的的处理逻辑所在的块。return [4, _0x298102["GenerateFP"](false, true)];
看一下_0x298102["GenerateFP"](false, true)_0x1e72d1函数的处理流程中,由于返回的列表第一个值是4,故走下面的逻辑_0x5513de的简单分析,这里走了next的执行逻辑,可以看到上面_0x1e72d1的返回值就是_0x4234aa函数的入参_0x4921b0,可以发现其主要围绕Promise的执行,并逐层传递Promise执行中产生的参数。_0x4234aa函数也是在一个Promise内,而上述提到的getImage对应的函数返回时也正是调用了返回这个Promise对象的_0x52fdcb函数。done被标记为true,则会取value给到_0x12a155,即resolve,否则会一直执行then,fulfilled时执行_0x910b2a,其参数简单来说就是Promise执行过程中resolve接收的值,reject时执行_0x447f35,这里主要关注Promise的onFulfilled函数,即_0x910b2a,逻辑如下。next最终还是要回去执行刚才分析的_0x1e72d1函数,来标记done的。这里的_0x243cf0,即resolve的值,会作为_0x1e72d1函数的列表类型的入参的第二个元素。继续跟_0x3edf5e函数,看一下_0x3edf5e的逻辑,主要是将传入的_0x48cfb7,也即resolve的值,包装成类似下面的形式{
"value": _0x50a149, // _0x48cfb7
"duration": _0x2b048b // 时间差
};
case 2块,根据_0x4b4666是否有值,再结合components(这里的compoents对象可以先扣下来固定下来),组成新的对象_0x1938e6,后面经过hashComponents得到_0x297a60_0x4d7c27就是当时的第二个入参,根据_0x298102["GenerateFP"](false, true)可知这里是true,也就是不需要切割,最后将处理好的_0x297a60交给Promise0的resolve根据上面的分析,这里的Promise0处于resolved(进入下一个状态)后,即在_0x1e72d1函数中执行完了_0x49bd55 = _0x41c1ce["call"](_0x160280, _0x4bd611),返回了[2],继续跟,走到default块。return {
"value": _0x49bd55[0] ? _0x49bd55[1] : undefined,
"done": true
};
done就标记为了true,继续跟,可以看到又执行了Promise0的外层Promise的then,即_0x4234aa所在的Promise,然后将resolve接收的参数交给then中的onFulfilled处理,即最终又回到了_0x1e72d1函数。sent中要用到的_0x1df4cd,接下来调用函数。getImage方法,跟进去case 1块,通过sent获取对应的值,而这里就是刚刚流程中Promise0的case 2块中产生的参数,即_0x592344["hashComponents"]处理后的值,可以把这个函数整体扣下来处理。至此,围绕_0x1e72d1函数的Promise过程就分析完了,后续涉及Promise的取值流程与此类似。_0x354394["GenerateFP"]和_0x298102["GenerateFP"]不是一个东西_0x354394["GenerateFP"]是前面分析的canvas指纹那套流程_0x298102["GenerateFP"]则是前面分析的Promise流程knock就是前置分析中config接口返回的所以_0x4eecbb就是额外加了knock参数来生成文本的canvas指纹生成逻辑得到的参数sent拿到的,那按照上述分析的只要关注上个流程,也就是case 1块中的返回值就可以了即[4, _0x298102["GenerateFP"](_0x2ac95b["knock"]["substr"](-5, 5))];_0x298102["GenerateFP"]返回的依旧是之前分析过的那个Promise0,第一个参数是切割后的knock,第二个参数为undefined,在函数内会转换为false那结合之前分析可知_0x1e45dc就是在components中额外加入了knock参数,再执行hashComponent,因为第二个参数是false,所以还要再切割一次得到最后的结果。_0x323ff4,定位一下,发现就在上面,是写死的那就直接把hex_md5扣下来算出_0xb0124就可以了_0x101aa8["ha"]影响,那先来看下_0x101aa8同样的,后面涉及_0x101aa8的参与en运算的参数也是跟这次分析差不多的流程,后面不再赘述_0x57c9c0,也是个函数,而在_0x101aa8函数内部有很多给_0x57c9c0属性赋值的地方,其中就包括上述提到的ha,也可以看到ha的初始值为空。其实可以同时看到紧接着_0x101aa8的下面的变量也是个立即执行的函数。_0x101aa8,而它返回的也是它内部的函数_0x5918e4,简单看一下_0x5918e4的逻辑可以发现它会调用_0x101aa8所以在_0x101aa8中不能只关注那些属性值的初始值,还要找到其他可能的二次赋值的地方对于ha,可疑的只有下图中的位置_0x582300也是通过sent得到,那看一下上一步返回的地方return [4, _0x4c9b3b["getImage"](_0x1cc39a)];
正是正在分析的获取图片的流程,那也就是说此时ha还是初始值空,走完图片获取流程才会给ha再次赋值那回到_0x2d7772这个参数的分析,根据判断逻辑,ha为空,那它就是一个固定值,至此该参数也分析完了_0x1ac30b等于_0x3d86c7_0x3d86c7赋值的地方有两个,取决于case 2块中的返回值hb不为空就会走到case 3,那_0x3d86c7就是_0x94b78b和sent的结果拼起来的,_0x94b78b就等于hb,sent对应的是上一步的返回值,即return [4, _0x298102["GenerateFP"](_0x101aa8["hb"])];
也就是处理后的canvas指纹值但根据上述_0x101aa8流程的分析可知hb此时是为空的,不会走到case 3,那_0x3d86c7也就是case 2中得到的固定值了,之后直接走到case 5,被赋给_0x1ac30b_0x397b35 = _0x17f508["canStorageUse"]();
_0xe75d98 = _0x2ac95b["dfu"],
_0x26f33d = _0x397b35 ? localStorage["getItem"]("vaptchanu") ? localStorage["getItem"]("vaptchanu")["split"](",")[0] : _0x101aa8["staticDfu"] : _0x101aa8["staticDfu"];
_0xc3f820 = _0x17f508["compareDfu"](_0xe75d98, _0x26f33d);
canStorageUsecanStorageUse在正常浏览器环境下返回的应该都是true,即_0x397b35为true回到_0xc3f820的生成逻辑继续往下看,_0x2ac95b是getImage对应函数的入参,定位一下传入的位置。loadFirstImg返回的函数中首次调用的getImage,入参为_0x1cc39a,主要用到的是this的属性,也就是_0x57c9c0的属性(又回到了_0x101aa8函数内的处理逻辑),这里主要看一下options赋值的地方。_0x57c9c0函数的入参就是对应后面的options,那调用栈往回看一下这个入参怎么生成的。下图中能看到这个入参是在验证码HTML页面渲染时绑定的时间监听中拿到的dfu能看到很像这个入参生成的地方。case 2中赋值的地方,其实对比一下逻辑,verify.xx.js中两处dfu赋值的地方的逻辑基本是一致的,至于走哪个分支里的赋值应该和缓存有一定的关系。用到的this['config']中的值也就是config接口返回的值,然后这里得到的newconfig就对应要找的入参。接着继续在verify.xx.js中看一下dfu生成逻辑中vaptchanu是在哪里设置的。setToken中将传入的参数切割后在localStorage中存成了vaptchanu,在这打断点没断住,那就是目前的流程不涉及verify.xx.js中的这个赋值流程,可以暂时不用管。也就是说在verify.xx.js目前走过的流程中,dfu就是空,那再回到_0xc3f820的生成逻辑继续往下看,自然的_0x26f33d也就只和_0x101aa8["staticDfu"]有关。定位一下_0x101aa8["staticDfu"]赋值的地方,发现在图片获取流程和验证流程中都存在赋值的地方,同时这两处也都有对vaptchanu和vaptchaut的赋值。目前只用关注图片获取流程中的处理逻辑即可staticDfu在图片接口的参数分析中可以理解为都是undefined,包括下面的staticDfuTrust目前也是undefined即_0xe75d98和_0x26f33d这两个参数都没有值,那看一下compareDfu的逻辑compareDfu简单分析下就是根据两个入参的长度来选择返回两个入参中的其中一个或返回一个固定值综上所述,_0xc3f820就是compareDfu中返回的那个固定值_0x1a6817 = _0x397b35 ? localStorage["getItem"]("vaptchaut") ? localStorage["getItem"]("vaptchaut") : _0x101aa8["staticDfuTrust"] ? _0x101aa8["staticDfuTrust"] : "0123456789qwertyuiopasdf87654321" : _0x101aa8["staticDfuTrust"] ? _0x101aa8["staticDfuTrust"] : "0123456789qwertyuiopasdf87654321";
跟上面_0x26f33d这个值的分析差不多,在getImage流程中取的就是一个固定值_0x260187 = _0xfa172["uaDelExtra"](navigator["userAgent"]) + location["host"] + _0x101aa8["secretC"]["substr"](0, 10);
_0x37ab28 = _0x23081c["hex_md5"](_0x260187)["slice"](0, 5);
uaDelExtra对应的函数为navigator["userAgent"],location["host"],_0x101aa8["secretC"]都相当于是定值,那拼出来的_0x260187也是定值,然后经过hex_md5处理再切割一下就得到了_0x37ab28globalMd5,看一下其对应的生成逻辑可以定位到两个地方先看第一个地方_0x101aa8内部的_0x57c9c0函数中,_0x4bcc6c是_0x57c9c0的入参,这个入参上面分析过了,这里直接看verify.xx.js搜索md5能看到很像这个入参生成的地方case 2中赋值的地方,对比一下逻辑,verify.xx.js中两处md5赋值的地方的逻辑也基本是一致的。用到的this['config']中的值也就是config接口返回的值,可以把md5生成中用到的hex_md5和splicingObj扣下来进行运算,这里的hex_md5和之前分析中出现的是一样的,那对应的globalMd5的值也就是这里md5的值。而定位到的另一处globalMd5赋值的地方是在getImage流程之后才会走到的,故getImage流程中不用管。图片获取及还原结合算出来的en值拼成请求体后请求拿到图片,得到的图片是乱序的,还需要根据图片接口返回的数据来还原图片的顺序。根据图片接口返回的字段,搜一下img_order,发现有两个地方,其中一个地方存在Decrypt函数,可以在那里断一下。_0x39a52f就是接口返回的数据,主要看一下_0xef75b5怎么来的其由_0x15d835、_0x11835f、parseInt(_0x57c9c0["secretC"])、_0x17f3de拼接而来,那接下来主要看一下这几个参数的赋值逻辑。ha字段且ha不为空,就再次给_0x15d835赋值可以把这里的hex2int函数扣下来,_0x354394["GenerateFP"]之前分析过,是涉及canvas指纹的地方,这里加了一个ha作为额外的文本内容来辅助生成canvas指纹sent,那就看一下上一步的逻辑判断接口中hb字段的情况,如果hb有值才会走到二次赋值的地方,二次赋值时主要关注这个返回值return [4, _0x298102["GenerateFP"](_0x39a52f["hb"])];
还是之前分析过的_0x298102["GenerateFP"],在components拼接的逻辑中额外加了_0x39a52f["hb"]),后面又经过了hashComponents和切割。_0x17f3de = _0x57c9c0["globalPow"];
所以要看一下globalPow是怎么生成的,这在下面_0x57c9c0中一起分析_0x101aa8函数内部定义的一个函数,其中存在很多给自己属性赋值的操作,那就看一下globalPow和secretC是哪里赋值的secretC之前定位过,是个定值,接下来主要看globalPow。定位到可疑的赋值位置_0x101aa8定位过去可以看到其实就是_0x57c9c0globalPow是在onmessage里赋值的,那对应的看一下postMessage_0x58df75参数,也就是pow对应的函数的入参,定位一下看下哪里调用的pow_0x57c9c0["prototype"]["insertCaptchaImage"]函数的处理逻辑中调用的,而这里刚好也是初始化globalPow的地方,这里的_0x39a52f也是这个函数的入参,定位一下可以发现就是图片接口返回的数据。回到postMessage,跟进去发现真实的处理逻辑在work2.js中pow函数扣下来,e.data.str就是上述图片接口返回的数据中的r参数,走到self.postMessage后就能进入刚刚onmessage的地方,精简下逻辑,即globalPow等于pow(r)综上得到_0xef75b5后就可以看下Decrypt函数function _0x2f0939(_0x5f38f0, _0x411a42) {
var _0x5f0d56 = '';
_0x5f0d56 = (parseInt(_0x5f38f0) - _0x411a42)["toString"]();
if (_0x5f0d56["length"] < 10) {
_0x5f0d56 = "0" + _0x5f0d56;
}
return _0x5f0d56;
}
_0x263810怎么来的_0x263810 = '' + _0x4a3f5d["dt"] + _0x4a3f5d["ch"] + _0x4a3f5d["cw"] + _0x1ce3a4["toString"]()["substr"](0, 5) + _0x2d4eff + _0x252e18 + _0x3992aa + _0x5063a0 + _0xcde9a6 + _0x277cc1 + _0x2133f8 + _0x1b799c + _0x101aa8["globalMd5"]["slice"](0, 5) + _0x4a3f5d["v"];
还是由一堆值拼接而来,继续一个个看verify对应函数的参数,和getImage中的_0x2ac95b分析流程类似,先看一下哪里调用的verify_0x57c9c0["prototype"]["validateVaptcha"]里,同时verify的入参也是_0x57c9c0["prototype"]["validateVaptcha"]的入参也可以看到入参_0x2a9d5a在_0x57c9c0["prototype"]["validateVaptcha"]中也增加了几个额外的参数先定位一下哪里调用了validateVaptcha,可以搜一下这个关键字或者调用栈往回找_0x57c9c0["prototype"]["canvasMouseUp"]里调用的,实际verify的部分入参也是在这里拼起来的,结合_0x57c9c0["prototype"]["validateVaptcha"]中增加的几个额外的参数,根据里面的逻辑来看一下几个关键的参数◆dtdt生成的逻辑如下_0x3b81b6 < 100 ? "00" + _0x3b81b6 : _0x3b81b6 < 1000 ? "0" + _0x3b81b6 : _0x3b81b6在上面就能看到_0x3b81b6的生成逻辑,是个时间差,带入上面的逻辑就能得到dtchcanvas画布的高度,定值(注意需要和实际的验证码区域区分一下)cwcanvas画布的宽度,定值(注意需要和实际的验证码区域区分一下)v对应_0x3b0f0512var _0x9a77c0 = this["drawPredicate"]();var _0x3b0f05 = _0x3dfad4["assemblyCoordData"](_0x9a77c0);_0x9a77c0就是处理后的轨迹坐标,_0x3dfad4["assemblyCoordData"]函数可以直接扣下来p对应_0x57c9c0["globalPow"],这个上面也分析过了,直接拿来用即可dfu对应this["options"]["dfu"],这个上面也分析了,在verify.xx.js中有相关生成逻辑,其中涉及到的vaptchanu也可以在相应的地方断一下,在这一步可以看到dfu最终得到的是空这几个参数弄清楚之后就可以带到en参数的生成逻辑中_0x1ce3a4 = _0x4a3f5d["p"]
就是上面刚分析的p参数_0x2d4eff = _0x354394["GenerateFP"]();
还是之前分析过的,和canvas指纹相关sent相关,那看一下上一步的返回值,也就是return [4, _0x298102["GenerateFP"](false, true)];
也是分析过的hashComponents那个流程_0x3992aa = _0x101aa8["ha"] === '' ? "0123456789qwe" : _0x101aa8["ha"] + _0x354394["GenerateFP"](_0x101aa8["ha"]);
和_0x101aa8["ha"]有关,这个ha也是之前分析过的,由于现在getImage流程走完了,所以可以看一下二次赋值的地方_0x582300就是图片接口返回的数据,那就按这边的逻辑挨个对应上就行了然后带入_0x3992aa的处理逻辑就能得到结果_0x5063a0就等于_0x3fbc4c,根据前面的分析这里也是个分支赋值,取决于_0x101aa8["hb"]的值,精简一下就是_0x5063a0 = _0x101aa8["hb"] === '' ? "0123456789qwe" : _0x101aa8["hb"] + _0x298102["GenerateFP"](_0x101aa8["hb"]);
这里的_0x298102["GenerateFP"]也就是hashComponents流程_0x2f01c2 = _0x4a3f5d["dfu"],
_0xb14203 = _0x55865d ? localStorage["getItem"]("vaptchanu") ? localStorage["getItem"]("vaptchanu")["split"](",")[0] : _0x101aa8["staticDfu"] : _0x101aa8["staticDfu"];
_0xcde9a6 = _0x17f508["compareDfu"](_0x2f01c2, _0xb14203);
vaptchanu的相关分析流程,在图片接口请求完成之后vaptchanu就会被赋值,对应的就是图片接口返回的响应体中的u参数和时间戳拼接而成的值。_0x277cc1 = _0x55865d ? localStorage["getItem"]("vaptchaut") ? localStorage["getItem"]("vaptchaut") : _0x101aa8["staticDfuTrust"] ? _0x101aa8["staticDfuTrust"] : "0123456789qwertyuiopasdf87654321" : _0x101aa8["staticDfuTrust"] ? _0x101aa8["staticDfuTrust"] : "0123456789qwertyuiopasdf87654321";
根据之前涉及vaptchaut的相关分析流程,在图片接口请求完成之后vaptchaut就会被赋值,对应的就是图片接口返回的响应体中的ut参数。如果在验证接口中给_0xcde9a6和_0x277cc1设置为固定值,则最后即使验证成功,返回的token也会变成000000000000000000000
_0xaffae = _0xfa172["uaDelExtra"](navigator["userAgent"]) + location["host"] + _0x101aa8["secretC"]["substr"](0, 10);
_0x2133f8 = _0x23081c["hex_md5"](_0xaffae)["slice"](0, 5);
_0x37ab28参数的分析一样_0x49090c = "61fecae0460";
_0x1b799c = _0x23081c["hex_md5"](_0x4a3f5d["knock"] + parseInt(_0x49090c)["toString"]())["slice"](0, 5);
_0x4a3f5d["knock"]还是config接口返回的那个值,其他就按上述分析的处理一下就行globalMd5的赋值在图片接口的_0x101aa8中分析过了,这里看第二处splicingObj的参数换一下,换成图片接口返回的data的值至此验证接口的en值需要用到的参数就分析完了,之后再经过_0xfa172["encryFunc"](_0xfa172["selectFrom"](3, 15), _0x263810)处理一下就是最终的en值。验证接口返回的code及其含义在官网和分析的js中都能找到,这里只列几个经常出现的看雪ID:LotusRain
*本文为看雪论坛精华文章,由 LotusRain 原创,转载请注明来自看雪社区
1.25折门票即将售罄
看雪·第九届安全开发者峰会(SDC 2025)
# 往期推荐
无"痕"加载驱动模块之傀儡驱动 (上)
为 CobaltStrike 增加 SMTP Beacon
隐蔽通讯常见种类介绍
buuctf-re之CTF分析
物理读写/无附加读写实验
AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。
鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑