utf8 发表于 2025-4-27 15:36

AI与JSVMP的初次结合-深入浅出的逆向JSVMP

# AI与JSVMP的初次结合-深入浅出的逆向JSVMP

关键词:jr头条vmp逆向,a_bogus,jsvmp,插桩,ai

> 目标接口:aHR0cHM6Ly93d3cudG91dGlhby5jb20vYXBpL3BjL2xpc3QvZmVlZA==

***本文仅供学习交流,因使用本文内容而产生的任何风险及后果,作者不承担任何责任,一起学习吧***

***代码均脱敏,如有侵权,请及时联系作者删除***

***因为部分原因,本文章仅做算法逆向分析,不提供任何完整代码分享。感谢理解***

打开主页就行,上面这个是接口。就是个下拉列表详情接口。

## 逆向目标 -- a_bogus 仅对这个分析其他参数不做讲解

通过xhr断点即可进入目标文件`bdms.js`,一眼便知这是一个jsvmp,但是它和我们之前分析的某音的jsvmp大有不同,他的分支不明确而且很冗杂。如果我们手动分析,需要解大量的三元表达式,这对我们来说可能会累死。

但是大人,时代变了。面对这种重复性操作,我们可以基于ai,来达到快速插桩。我们只需要将我们需要操作的代码和明确的执行目的。我们就可以得到一份完美的插桩文件。ai nice!

但是插桩不是一次就完成的,这里你可以看看我之前文章讲的插桩思路和方法。这里我们第一次插桩,先重点在于apply函数,看看它这一整个流程。
```js
/* === 我们关心的 apply === */
console.log('[调用 apply]', { 函数: String(s), 上下文: b, 参数: JSON.stringify(u) });
            d = s.apply(b, u);
            console.log('[返回值]', d);
            p[++l] = d;
```

简单打出日志,让我们观察一下。
```log
bdms.js:10808 传入参数b-->null 传入参数u--> 调用函数s-->   输出结果d-->-1
[参数] (6) 
[调用函数]
bdms.js:10452 传入参数b-->undefined 传入参数u-->[{"_Ax":"0X21"},"_Ax"] 调用函数s-->   输出结果d-->undefined
bdms.js:10452 传入参数b-->undefined 传入参数u-->[] 调用函数s-->   输出结果d-->{value: '0X21', writable: false, enumerable: true, configurable: true}
bdms.js:10452 传入参数b-->{"reg":,"chunk":[],"size":0} 传入参数u-->["channel_id=0&max_behot_time=1744957399&offset=0&category=pc_profile_recommend&aid=24&app_name=toutiao_web&msToken=xmhFMI7s9bvxLn2gl79OMXsLigSxL7hwCMWLehsVYfrDRWLS2cJKwKcPOAF3TUiwKF6a_ttDryIK8uK8bqA-zJKxtHF-MNyoMbLPXl5VRDPiBDgtRGktEA%3D%3Dcus"] 调用函数s-->   输出结果d-->t {reg: Array(8), chunk: Array(0), size: 0}
bdms.js:10452 传入参数b-->{"reg":,"chunk":[],"size":0} 传入参数u-->[] 调用函数s-->   输出结果d-->(32) 
bdms.js:10452 传入参数b-->{"reg":,"chunk":[],"size":0} 传入参数u-->["cus"] 调用函数s-->ƒ (t, a) {
                  var n = r
                      , c = e;
                  t && (this(),
                  this.write(t)),
                  this();… 输出结果d-->(32) 
bdms.js:10452 传入参数b-->{"reg":,"chunk":[],"size":0} 传入参数u-->[] 调用函数s-->ƒ (t, a) {
                  var n = r
                      , c = e;
                  t && (this(),
                  this.write(t)),
                  this();… 输出结果d-->(32) 
bdms.js:10452 传入参数b-->"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0" 传入参数u-->[] 调用函数s-->ƒ trim() { } 输出结果d-->(32) 
bdms.js:10452 传入参数b-->undefined 传入参数u-->] 调用函数s-->ƒ apply() { } 输出结果d-->(3) 
bdms.js:10452 传入参数b-->null 传入参数u-->["\u0000\u0001\f","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"] 调用函数s-->ƒ e() {
                                    var r = e._v;
                                    return (0,
                                    e._u)(r, arguments, r, r, this)
                   … 输出结果d-->:–þþ¢ŠP§˜‚r$K·Úàœ©›öãê°?Ãa¥&’æ¼=¥²^ƒÜáBDf8>Þ+ªxð(ÀËa„ÄçäCZ¡6pMCg^`-£§Ü
sF¨ûصI$^ƒÈGÙ¸@j74M½€4alùžÉ냉®æñvtß F®
bdms.js:9992 传入参数b-->":–þþ\u001d¢ŠP§˜‚r$\u0012\u0019K·Úàœ©›öãê°?Ãa¥&’æ¼=¥²^ƒÜáBDf8>Þ+ªxð(ÀËa„Äç\u0015äCZ¡6pMCg^`-£§Ü\nsF¨û\u000fصI$^ƒÈ\u0019GÙ¸\u001e@j74M½\u0014€4\u0018alùžÉ\u001e냉®æ\u001bñvtß F®" 传入参数u--> 调用函数s-->ƒ charCodeAt() { } 输出结果d-->undefined
bdms.js:9992 传入参数b-->":–þþ\u001d¢ŠP§˜‚r$\u0012\u0019K·Úàœ©›öãê°?Ãa¥&’æ¼=¥²^ƒÜáBDf8>Þ+ªxð(ÀËa„Äç\u0015äCZ¡6pMCg^`-£§Ü\nsF¨û\u000fصI$^ƒÈ\u0019GÙ¸\u001e@j74M½\u0014€4\u0018alùžÉ\u001e냉®æ\u001bñvtß F®" 传入参数u--> 调用函数s-->ƒ charCodeAt() { } 输出结果d-->58
bdms.js:9992 传入参数b-->":–þþ\u001d¢ŠP§˜‚r$\u0012\u0019K·Úàœ©›öãê°?Ãa¥&’æ¼=¥²^ƒÜáBDf8>Þ+ªxð(ÀËa„Äç\u0015äCZ¡6pMCg^`-£§Ü\nsF¨û\u000fصI$^ƒÈ\u0019GÙ¸\u001e@j74M½\u0014€4\u0018alùžÉ\u001e냉®æ\u001bñvtß F®" 传入参数u--> 调用函数s-->ƒ charCodeAt() { } 输出结果d-->150
bdms.js:9992 传入参数b-->"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->254
bdms.js:9992 传入参数b-->"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->/
bdms.js:9992 传入参数b-->"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->T
bdms.js:9992 传入参数b-->"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->+
bdms.js:9992 传入参数b-->":–þþ\u001d¢ŠP§˜‚r$\u0012\u0019K·Úàœ©›öãê°?Ãa¥&’æ¼=¥²^ƒÜáBDf8>Þ+ªxð(ÀËa„Äç\u0015äCZ¡6pMCg^`-£§Ü\nsF¨û\u000fصI$^ƒÈ\u0019GÙ¸\u001e@j74M½\u0014€4\u0018alùžÉ\u001e냉®æ\u001bñvtß F®" 传入参数u--> 调用函数s-->ƒ charCodeAt() { } 输出结果d-->C
bdms.js:9992 传入参数b-->":–þþ\u001d¢ŠP§˜‚r$\u0012\u0019K·Úàœ©›öãê°?Ãa¥&’æ¼=¥²^ƒÜáBDf8>Þ+ªxð(ÀËa„Äç\u0015äCZ¡6pMCg^`-£§Ü\nsF¨û\u000fصI$^ƒÈ\u0019GÙ¸\u001e@j74M½\u0014€4\u0018alùžÉ\u001e냉®æ\u001bñvtß F®" 传入参数u--> 调用函数s-->ƒ charCodeAt() { } 输出结果d-->254
bdms.js:9992 传入参数b-->":–þþ\u001d¢ŠP§˜‚r$\u0012\u0019K·Úàœ©›öãê°?Ãa¥&’æ¼=¥²^ƒÜáBDf8>Þ+ªxð(ÀËa„Äç\u0015äCZ¡6pMCg^`-£§Ü\nsF¨û\u000fصI$^ƒÈ\u0019GÙ¸\u001e@j74M½\u0014€4\u0018alùžÉ\u001e냉®æ\u001bñvtß F®" 传入参数u--> 调用函数s-->ƒ charCodeAt() { } 输出结果d-->29
bdms.js:9992 传入参数b-->"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->162
bdms.js:9992 传入参数b-->"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->e
bdms.js:9992 传入参数b-->"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->i
bdms.js:9992 传入参数b-->"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->9

这里我省略重复日志

bdms.js:10452 传入参数b-->"1.0.1.7" 传入参数u-->["."] 调用函数s-->   输出结果d-->(32) 
bdms.js:10452 传入参数b-->["1","0","1","7"] 传入参数u--> 调用函数s-->   输出结果d-->(4) ['1', '0', '1', '7']
[参数] (3) ['1', 0, Array(4)]
[调用函数]
[返回值] 1
[参数] (3) ['0', 1, Array(4)]
[调用函数]
[返回值] 0
[参数] (3) ['1', 2, Array(4)]
[调用函数]
[返回值] 1
[参数] (3) ['7', 3, Array(4)]
[调用函数]
[返回值] 7

这里是环境检测

bdms.js:10452 传入参数b-->"1912|954|1914|1026|1283|-357|8828|8828|1920|1032|1920|1080|1897|10234|24|24|Win32" 传入参数u--> 调用函数s-->   输出结果d-->undefined
bdms.js:10452 传入参数b-->[] 传入参数u--> 调用函数s-->   输出结果d-->49
bdms.js:10452 传入参数b-->"1912|954|1914|1026|1283|-357|8828|8828|1920|1032|1920|1080|1897|10234|24|24|Win32" 传入参数u--> 调用函数s-->   输出结果d-->1
bdms.js:10452 传入参数b--> 传入参数u--> 调用函数s-->   输出结果d-->57
bdms.js:10452 传入参数b-->"1912|954|1914|1026|1283|-357|8828|8828|1920|1032|1920|1080|1897|10234|24|24|Win32" 传入参数u--> 调用函数s-->   输出结果d-->2
bdms.js:10452 传入参数b--> 传入参数u--> 调用函数s-->   输出结果d-->49
bdms.js:10452 传入参数b-->"1912|954|1914|1026|1283|-357|8828|8828|1920|1032|1920|1080|1897|10234|24|24|Win32" 传入参数u--> 调用函数s-->   输出结果d-->3
bdms.js:10452 传入参数b--> 传入参数u--> 调用函数s-->   输出结果d-->50
bdms.js:10452 传入参数b-->"1912|954|1914|1026|1283|-357|8828|8828|1920|1032|1920|1080|1897|10234|24|24|Win32" 传入参数u--> 调用函数s-->   输出结果d-->4
bdms.js:10452 传入参数b--> 传入参数u--> 调用函数s-->   输出结果d-->124
bdms.js:10452 传入参数b-->"1912|954|1914|1026|1283|-357|8828|8828|1920|1032|1920|1080|1897|10234|24|24|Win32" 传入参数u--> 调用函数s-->   输出结果d-->5
bdms.js:10452 传入参数b--> 传入参数u--> 调用函数s-->   输出结果d-->57
bdms.js:10452 传入参数b-->"1912|954|1914|1026|1283|-357|8828|8828|1920|1032|1920|1080|1897|10234|24|24|Win32" 传入参数u--> 调用函数s-->   输出结果d-->6
bdms.js:10452 传入参数b--> 传入参数u--> 调用函数s-->   输出结果d-->53
生成环境数组
bdms.js:10452 传入参数b--> 传入参数u--> 调用函数s-->   输出结果d-->50
bdms.js:10452 传入参数b-->undefined 传入参数u-->[] 调用函数s-->   输出结果d-->81
bdms.js:10452 传入参数b-->undefined 传入参数u-->[[]] 调用函数s-->   输出结果d-->(81) 
bdms.js:10452 传入参数b--> 传入参数u-->[,[],] 调用函数s-->   输出结果d-->[]
bdms.js:10452 传入参数b-->{} 传入参数u-->[] 调用函数s-->   输出结果d-->(126) 
bdms.js:10452 传入参数b-->undefined 传入参数u--> 调用函数s-->   输出结果d-->0.5259586534477843
bdms.js:10452 传入参数b-->{} 传入参数u-->[] 调用函数s-->   输出结果d-->‹<
bdms.js:10452 传入参数b-->undefined 传入参数u--> 调用函数s-->   输出结果d-->0.2646494500107772
bdms.js:10452 传入参数b-->{} 传入参数u-->[] 调用函数s-->   输出结果d-->T
再次加密
bdms.js:9992 传入参数b-->"‹\u0003\u0005<\u0003T\n\u0000£\u0005\u0005\u0007iäB„çI9Ó ZÑ7ݸ<\u0001gñ$©JDöÜúÓÛø¤ÐùQ‚M0Ɗ“Ɔ[ê0Ñ‘x©;Ì¯µ1yPÕÁf8o‡\"EMôôÎi/!jqt³O\u0000ÎØ/d\u0016]û²Ë`\u0016ßÎ¥MœU÷¿ƒ\u0003{'²lQá\fôæ:\u0001ÚLsªdö\u001be\u0006ݲ@dÿЩÉÕ" 传入参数u--> 调用函数s-->ƒ charCodeAt() { } 输出结果d-->169
bdms.js:9992 传入参数b-->"‹\u0003\u0005<\u0003T\n\u0000£\u0005\u0005\u0007iäB„çI9Ó ZÑ7ݸ<\u0001gñ$©JDöÜúÓÛø¤ÐùQ‚M0Ɗ“Ɔ[ê0Ñ‘x©;Ì¯µ1yPÕÁf8o‡\"EMôôÎi/!jqt³O\u0000ÎØ/d\u0016]û²Ë`\u0016ßÎ¥MœU÷¿ƒ\u0003{'²lQá\fôæ:\u0001ÚLsªdö\u001be\u0006ݲ@dÿЩÉÕ" 传入参数u--> 调用函数s-->ƒ charCodeAt() { } 输出结果d-->201
bdms.js:9992 传入参数b-->"Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->213
bdms.js:9992 传入参数b-->"Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->O
bdms.js:9992 传入参数b-->"Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->W
bdms.js:9992 传入参数b-->"Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe" 传入参数u--> 调用函数s-->ƒ charAt() { } 输出结果d-->q
bdms.js:10409 [返回值] xj8hMD06dEdNkf6Z5W/LfY3qV3q3YhPv0t9bMDhqSVVTVL39HMP39exLyMwvELyjxT/2ICYjy4hbO3KkrQC781wf7Who/2CZmLX0tM3/5VSi5qhyuySDrzEF4k4UCaBBRk-lrOX0qh1HFb8pAnAn-h2UbfryGNYk9LJrOo392962H-sD4MefOWqX
bdms.js:10808 传入参数b-->{} 传入参数u-->["a_bogus","xj8hMD06dEdNkf6Z5W/LfY3qV3q3YhPv0t9bMDhqSVVTVL39HMP39exLyMwvELyjxT/2ICYjy4hbO3KkrQC781wf7Who/2CZmLX0tM3/5VSi5qhyuySDrzEF4k4UCaBBRk-lrOX0qh1HFb8pAnAn-h2UbfryGNYk9LJrOo392962H-sD4MefOWqX"] 调用函数s-->ƒ append() { } 输出结果d-->xj8hMD06dEdNkf6Z5W/LfY3qV3q3YhPv0t9bMDhqSVVTVL39HMP39exLyMwvELyjxT/2ICYjy4hbO3KkrQC781wf7Who/2CZmLX0tM3/5VSi5qhyuySDrzEF4k4UCaBBRk-lrOX0qh1HFb8pAnAn-h2UbfryGNYk9LJrOo392962H-sD4MefOWqX
bdms.js:10808 传入参数b-->[{"args":["GET","https://www.toutiao.com/api/pc/list/feed?channel_id=0&max_behot_time=1744957399&offset=0&category=pc_profile_recommend&aid=24&app_name=toutiao_web&msToken=xmhFMI7s9bvxLn2gl79OMXsLigSxL7hwCMWLehsVYfrDRWLS2cJKwKcPOAF3TUiwKF6a_ttDryIK8uK8bqA-zJKxtHF-MNyoMbLPXl5VRDPiBDgtRGktEA%3D%3D&a_bogus=xj8hMD06dEdNkf6Z5W%2FLfY3qV3q3YhPv0t9bMDhqSVVTVL39HMP39exLyMwvELyjxT%2F2ICYjy4hbO3KkrQC781wf7Who%2F2CZmLX0tM3%2F5VSi5qhyuySDrzEF4k4UCaBBRk-lrOX0qh1HFb8pAnAn-h2UbfryGNYk9LJrOo392962H-sD4MefOWqX",true]},{"args":["Accept","application/json, text/plain, */*"]}] 传入参数u--> 调用函数s-->ƒ forEach() { } 输出结果d-->undefined
```

这个日志就很清晰了,我们大体上了解到了这个参数是如何生成的

这里我们会发现我们的请求链接,ua,还有一个随机盐值,均通过了一个函数生成了一个数组,而且这个数组还同样经历了一次这个加密,生成了最后的结果。这个函数,我们直接进入,发现不是一个vmp,我们简单的把他抠出来,本文暂不讲解这里的扣取方法。如果问的多,我在考虑处一篇文章专门讲解。

然后我们的ua又进入到了一个vmp中进行了一段不为人知的加密,变成了一段乱码,这个乱码又通过一个字符串变成了一个新的字符串。

他还检测了我们的环境生成了一个环境数组,还有一个不为人知的小数组。二者拼接成为了一个大数组(少一位),然后这个数组又变成了乱码,这个乱码又和一个字符串进行不为人知的计算。最后生成了我们的加密参数。

整体流程我们大体上搞清楚了。我们接下来就是,把一个大的逆向流程,不断地拆分为很多个小流程。

## 乱码生成
为了了解乱码生成,日志是必不可少的。结合我之前讲过的方法,我们需要对常规的运算和apply进行插桩。这一步,我们还是交给ai来做。

生成的日志如下:

``` log
[加法] 0 + 0
[结果] 0
[取模] 0 % 3
[结果] 0
[调用 apply] {函数: 'charCodeAt', 上下文: '\x00\x01\x0E', 参数: ''}
0
[加法] 0 + 0
[结果] 0
[取模] 0 % 256
[结果] 0
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,0,0,"",256,0] 键: 8 原始值: 0
[结果: 自增前值] 0 新值: 1
[小于比较] 1 < 256
[结果] true

// 最开始是加法运算 i = 0,arr =
// arr + arr = 0--> 结果1
// '\x00\x01\x0E'.charCodeAt(i % 3)=0--> 结果2
// 结果1 + 结果2 = 0--> 结果3
// 结果3 % 256 = 0--> 结果4
// arr = 结果4
// arr[结果4] = 原来的arr
// arr =

[加法] 0 + 1
[结果] 1
[取模] 1 % 3
[结果] 1
[调用 apply] {函数: 'charCodeAt', 上下文: '\x00\x01\x0E', 参数: ''}
1
[加法] 1 + 1
[结果] 2
[取模] 2 % 256
[结果] 2
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,2,1,"",256,1] 键: 8 原始值: 1
[结果: 自增前值] 1 新值: 2
[小于比较] 2 < 256
[结果] true

// 第二轮加法运算 i = 1arr =
// arr + arr = 1--> 结果1// 猜想
// '\x00\x01\x0E'.charCodeAt(i % 3)=1--> 结果2
// 结果1 + 结果2 = 2--> 结果3
// 结果3 % 256 = 2--> 结果4
// arr = 结果4 = 2
// arr[结果4] = 原来的arr
// arr =

[加法] 2 + 1
[结果] 3
[取模] 2 % 3
[结果] 2
[调用 apply] {函数: 'charCodeAt', 上下文: '\x00\x01\x0E', 参数: ''}
14
[加法] 3 + 14
[结果] 17
[取模] 17 % 256
[结果] 17
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,17,1,"",256,2] 键: 8 原始值: 2
[结果: 自增前值] 2 新值: 3
[小于比较] 3 < 256
[结果] true

// 这里开始验证猜想
// 第三轮加法运算 i = 2arr =
// arr + arr = 3--> 结果1   正确这里其实不太对arr是上一轮的结果
// '\x00\x01\x0E'.charCodeAt(i % 3)=14--> 结果2正确
// 结果1 + 结果2 = 17--> 结果3
// 结果3 % 256 = 17--> 结果4
// arr = 结果4 = 17
// arr[结果4] = 原来的arr
// arr =


[加法] 17 + 3
[结果] 20
[取模] 3 % 3
[结果] 0
[调用 apply] {函数: 'charCodeAt', 上下文: '\x00\x01\x0E', 参数: ''}
0
[加法] 20 + 0
[结果] 20
[取模] 20 % 256
[结果] 20
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,20,3,"",256,3] 键: 8 原始值: 3
[结果: 自增前值] 3 新值: 4
[小于比较] 4 < 256
[结果] true

// 这里开始验证猜想
// 第四轮加法运算 i = 3arr =
// arr + arr = 20--> 结果1   正确这里其实不太对arr是上一轮的结果
// '\x00\x01\x0E'.charCodeAt(i % 3)=0--> 结果2正确
// 结果1 + 结果2 = 20--> 结果3
// 结果20 % 256 = 20--> 结果4
// arr = 结果4 = 20
// arr[结果4] = 原来的arr
// arr =

[加法] 20 + 4
[结果] 24
[取模] 4 % 3
[结果] 1
[调用 apply] {函数: 'charCodeAt', 上下文: '\x00\x01\x0E', 参数: ''}
1
[加法] 24 + 1
[结果] 25
[取模] 25 % 256
[结果] 25
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,25,4,"",256,4] 键: 8 原始值: 4
[结果: 自增前值] 4 新值: 5

// 这里开始验证猜想
// 第四轮加法运算 i = 4arr =
// arr + arr = 24--> 结果1   正确这里其实不太对arr是上一轮的结果
// '\x00\x01\x0E'.charCodeAt(i % 3)=1--> 结果2正确
// 结果1 + 结果2 = 25--> 结果3
// 25 % 256 = 25--> 结果4
// arr = 结果4 = 25
// arr[结果4] = 原来的arr
// arr =
// 没问题

还原代码如下:
```js
function transformArray() {
    const arr = Array.from({ length: 256 }, (_, i) => i);
    const key = "\x00\x01\x0E";
    let acc = 0;

    for (let i = 0; i < 256; i++) {
      const index = i % 3;
      const charCode = key.charCodeAt(index); // 每轮根据下标取key的charCode
      acc = (acc + arr + charCode) % 256;
      const tmp = arr;
      arr = arr; // 交换 acc 和 i 的值
      arr = tmp;
      console.log(arr + '')
      console.log('\n')
    }
    return arr;
}
console.log(transformArray())
```


最后运算的数组位:


[加法] 0 + 1
[结果] 1
[取模] 1 % 256
[结果] 1
[加法] 0 + 218
[结果] 218
[取模] 218 % 256
[结果] 218
[调用 apply] {函数: 'charCodeAt', 上下文: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…cko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0', 参数: ''}
77
[加法] 2 + 218
[结果] 220
[取模] 220 % 256
[结果] 220
[异或] 77 ^ 216
[结果] 149
[调用 apply] {函数: 'fromCharCode', 上下文: 'function String() { }', 参数: ''}

[加法] "" + "•"
[结果] "•"
[赋值] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,218,218,"",256,256,1,0] 键: 6 值: •
[结果] •
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,218,218,"•",256,256,1,0] 键: 10 原始值: 0
[结果: 自增前值] 0 新值: 1
[小于比较] 1 < 125
[结果] true

最开始
tmp = 0
// 猜想开始 i = 0
// (i + 1) % 256 --> (0 + 1) % 256 = 1结果1
// (arr + arr[结果1]) % 256 --> (0 + 218) % 256 = 218 结果2(这里记录 tmp = 218)
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0".charCodeAt(i)= 77 --> 结果3

// arr[结果1](arr = 218) 和 arr[结果2](arr = 2) 互换位置,变成如下数组
变化
// 变化位置的二者相加mod256   (2 + 218) % 256 = 220
// 结果3 ^ arr = 149
// String.fromCharCode(149)



[加法] 1 + 1
[结果] 2
[取模] 2 % 256
[结果] 2
[加法] 218 + 17
[结果] 235
[取模] 235 % 256
[结果] 235
[调用 apply] {函数: 'charCodeAt', 上下文: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…cko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0', 参数: ''}
111
[加法] 127 + 17
[结果] 144
[取模] 144 % 256
[结果] 144
[异或] 111 ^ 233
[结果] 134
[调用 apply] {函数: 'fromCharCode', 上下文: 'function String() { }', 参数: ''}

[加法] "•" + "†"
[结果] "•†"
[赋值] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,235,17,"•",256,256,2,1] 键: 6 值: •†
[结果] •†
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,235,17,"•†",256,256,2,1] 键: 10 原始值: 1
[结果: 自增前值] 1 新值: 2
[小于比较] 2 < 125
[结果] true



tmp = 218
// 验证猜想 i = 1
// (i + 1) % 256 --> (1 + 1) % 256 = 2结果1
// (tmp + arr[结果1]) % 256 --> (218 + 17) % 256 = 235 结果2 (这里记录tmp=235)
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0".charCodeAt(i)= 111 --> 结果3

// arr[结果1](arr = 17) 和 arr(arr = 127) 互换位置,变成如下数组

// 变化位置的二者相加mod256   (17 + 127) % 256 = 144
// 结果3 ^ arr = 134
// String.fromCharCode(134)
// 这里基本就可以确定有两个数组相互配合了

[加法] 2 + 1
[结果] 3
[取模] 3 % 256
[结果] 3
[加法] 235 + 20
[结果] 255
[取模] 255 % 256
[结果] 255
[调用 apply] {函数: 'charCodeAt', 上下文: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…cko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0', 参数: ''}
122
[加法] 149 + 20
[结果] 169
[取模] 169 % 256
[结果] 169
[异或] 122 ^ 238
[结果] 148
[调用 apply] {函数: 'fromCharCode', 上下文: 'function String() { }', 参数: ''}

[加法] "•†" + "”"
[结果] "•†”"
[赋值] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,255,20,"•†",256,256,3,2] 键: 6 值: •†”
[结果] •†”
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,255,20,"•†”",256,256,3,2] 键: 10 原始值: 2
[结果: 自增前值] 2 新值: 3
[小于比较] 3 < 125
[结果] true



tmp = 235
// 再次验证猜想 i = 2
// (i + 1) % 256 --> (2 + 1) % 256 = 3结果1
// (tmp + arr[结果1]) % 256 --> (235 + 20) % 256 = 255 结果2 (tmp = 255)
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0".charCodeAt(i)= 122 --> 结果3

// arr[结果1](arr = 20) 和 arr(arr = 149) 互换位置,变成如下数组

// 变化位置的二者相加mod256   (20 + 149) % 256 = 169
// 结果3 ^ arr = 148
// String.fromCharCode(148)


[加法] 3 + 1
[结果] 4
[取模] 4 % 256
[结果] 4
[加法] 255 + 25
[结果] 280
[取模] 280 % 256
[结果] 24
[调用 apply] {函数: 'charCodeAt', 上下文: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…cko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0', 参数: ''}
105
[加法] 213 + 25
[结果] 238
[取模] 238 % 256
[结果] 238
[异或] 105 ^ 148
[结果] 253
[调用 apply] {函数: 'fromCharCode', 上下文: 'function String() { }', 参数: ''}
ý
[加法] "•†”" + "ý"
[结果] "•†”ý"
[赋值] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,24,25,"•†”",256,256,4,3] 键: 6 值: •†”ý
[结果] •†”ý
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,24,25,"•†”ý",256,256,4,3] 键: 10 原始值: 3
[结果: 自增前值] 3 新值: 4
[小于比较] 4 < 125
[结果] true


[加法] 4 + 1
[结果] 5
[取模] 5 % 256
[结果] 5
[加法] 24 + 23
[结果] 47
[取模] 47 % 256
[结果] 47
[调用 apply] {函数: 'charCodeAt', 上下文: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…cko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0', 参数: ''}
108
[加法] 62 + 23
[结果] 85
[取模] 85 % 256
[结果] 85
[异或] 108 ^ 195
[结果] 175
[调用 apply] {函数: 'fromCharCode', 上下文: 'function String() { }', 参数: ''}
¯
[加法] "•†”ý" + "¯"
[结果] "•†”ý¯"
[赋值] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,47,23,"•†”ý",256,256,5,4] 键: 6 值: •†”ý¯
[结果] •†”ý¯
[自增] 对象: [{"0":"\u0000\u0001\u000e","1":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"},"\u0000\u0001\u000e","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",,47,23,"•†”ý¯",256,256,5,4] 键: 10 原始值: 4
[结果: 自增前值] 4 新值: 5
[小于比较] 5 < 125
[结果] true

这里乱码逆向就完成了
```

接着根据最初的日志去定位乱码还原,这个地方其实就是一个魔改的base64。根据日志可以还原

```log
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 149
[按位与] 149 & 255
[结果] 149
[左移] 149 << 16
[结果] 9764864
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 134
[按位与] 134 & 255
[结果] 134
[左移] 134 << 8
[结果] 34304
[按位或] 9764864 | 34304
[结果] 9799168
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 148
[按位与] 148 & 255
[结果] 148
[按位或] 9799168 | 148
[结果] 9799316
[按位与] 9799316 & 16515072
[结果] 9699328
[右移] 9699328 >> 18
[结果] 37
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] b
[加法]+ b
[结果] b

[按位与] 9799316 & 258048
[结果] 98304
[右移] 98304 >> 12
[结果] 24
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] R
[加法] b + R
[结果] bR
[按位与] 9799316 & 4032
[结果] 1664
[右移] 1664 >> 6
[结果] 26
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] 5
[加法] bR + 5
[结果] bR5
[按位与] 9799316 & 63
[结果] 20
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] 6
[加法] bR5 + 6
[结果] bR56
[加法] 3 + 3
[结果] 6
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 253
[按位与] 253 & 255
[结果] 253
[左移] 253 << 16
[结果] 16580608
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 175
[按位与] 175 & 255
[结果] 175
[左移] 175 << 8
[结果] 44800
[按位或] 16580608 | 44800
[结果] 16625408
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 228
[按位与] 228 & 255
[结果] 228
[按位或] 16625408 | 228
[结果] 16625636
[按位与] 16625636 & 16515072
[结果] 16515072
[右移] 16515072 >> 18
[结果] 63
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] e
[加法] bR56 + e
[结果] bR56e
[按位与] 16625636 & 258048
[结果] 106496
[右移] 106496 >> 12
[结果] 26
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] 5
[加法] bR56e + 5
[结果] bR56e5
[按位与] 16625636 & 4032
[结果] 4032
[右移] 4032 >> 6
[结果] 63
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] e
[加法] bR56e5 + e
[结果] bR56e5e
[按位与] 16625636 & 63
[结果] 36
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] L
[加法] bR56e5e + L
[结果] bR56e5eL
[加法] 6 + 3
[结果] 9
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 16
[按位与] 16 & 255
[结果] 16
[左移] 16 << 16
[结果] 1048576
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 167
[按位与] 167 & 255
[结果] 167
[左移] 167 << 8
[结果] 42752
[按位或] 1048576 | 42752
[结果] 1091328
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 49
[按位与] 49 & 255
[结果] 49
[按位或] 1091328 | 49
[结果] 1091377
[按位与] 1091377 & 16515072
[结果] 1048576
[右移] 1048576 >> 18
[结果] 4
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] 1
[加法] bR56e5eL + 1
[结果] bR56e5eL1
[按位与] 1091377 & 258048
[结果] 40960
[右移] 40960 >> 12
[结果] 10
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] U
[加法] bR56e5eL1 + U
[结果] bR56e5eL1U
[按位与] 1091377 & 4032
[结果] 1792
[右移] 1792 >> 6
[结果] 28
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] W
[加法] bR56e5eL1U + W
[结果] bR56e5eL1UW
[按位与] 1091377 & 63
[结果] 49
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] J
[加法] bR56e5eL1UW + J
[结果] bR56e5eL1UWJ
[加法] 9 + 3
[结果] 12
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 30
[按位与] 30 & 255
[结果] 30
[左移] 30 << 16
[结果] 1966080
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 217
[按位与] 217 & 255
[结果] 217
[左移] 217 << 8
[结果] 55552
[按位或] 1966080 | 55552
[结果] 2021632
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 44
[按位与] 44 & 255
[结果] 44
[按位或] 2021632 | 44
[结果] 2021676
[按位与] 2021676 & 16515072
[结果] 1835008
[右移] 1835008 >> 18
[结果] 7
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] Z
[加法] bR56e5eL1UWJ + Z
[结果] bR56e5eL1UWJZ
[按位与] 2021676 & 258048
[结果] 184320
[右移] 184320 >> 12
[结果] 45
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] z
[加法] bR56e5eL1UWJZ + z
[结果] bR56e5eL1UWJZz
[按位与] 2021676 & 4032
[结果] 2304
[右移] 2304 >> 6
[结果] 36
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] L
[加法] bR56e5eL1UWJZz + L
[结果] bR56e5eL1UWJZzL
[按位与] 2021676 & 63
[结果] 44
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] u
[加法] bR56e5eL1UWJZzL + u
[结果] bR56e5eL1UWJZzLu
[加法] 12 + 3
[结果] 15
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 109
[按位与] 109 & 255
[结果] 109
[左移] 109 << 16
[结果] 7143424
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 64
[按位与] 64 & 255
[结果] 64
[左移] 64 << 8
[结果] 16384
[按位或] 7143424 | 16384
[结果] 7159808
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 196
[按位与] 196 & 255
[结果] 196
[按位或] 7159808 | 196
[结果] 7160004
[按位与] 7160004 & 16515072
[结果] 7077888
[右移] 7077888 >> 18
[结果] 27
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] +
[加法] bR56e5eL1UWJZzLu + +
[结果] bR56e5eL1UWJZzLu+
[按位与] 7160004 & 258048
[结果] 81920
[右移] 81920 >> 12
[结果] 20
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] 6
[加法] bR56e5eL1UWJZzLu+ + 6
[结果] bR56e5eL1UWJZzLu+6
[按位与] 7160004 & 4032
[结果] 192
[右移] 192 >> 6
[结果] 3
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] p
[加法] bR56e5eL1UWJZzLu+6 + p
[结果] bR56e5eL1UWJZzLu+6p
[按位与] 7160004 & 63
[结果] 4
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] 1
[加法] bR56e5eL1UWJZzLu+6p + 1
[结果] bR56e5eL1UWJZzLu+6p1
[加法] 15 + 3
[结果] 18
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 155
[按位与] 155 & 255
[结果] 155
[左移] 155 << 16
[结果] 10158080
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 175
[按位与] 175 & 255
[结果] 175
[左移] 175 << 8
[结果] 44800
[按位或] 10158080 | 44800
[结果] 10202880
[调用 apply] {函数: 'function charCodeAt() { }', 上下文: "\x95\x86\x94ý¯ä\x10§1\x1EÙ,m@Ä\x9B¯]g`\x17zVé\x9CöÀ\x80\x14\x17ÎcOåÿýÎç\x02\x02\x8A<7Ъà'µpK…~\x1Eù\x9Eèx\x173nÓÈ\x9F¥ÊBC¤\x15k^­pµyÑØ\x92=\tdc\x14jÌüzvg\x05\x1C\x9C]\nÀRâ\x93B\x00", 参数: ''}
[返回值] 93
[按位与] 93 & 255
[结果] 93
[按位或] 10202880 | 93
[结果] 10202973
[按位与] 10202973 & 16515072
[结果] 9961472
[右移] 9961472 >> 18
[结果] 38
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] o
[加法] bR56e5eL1UWJZzLu+6p1 + o
[结果] bR56e5eL1UWJZzLu+6p1o
[按位与] 10202973 & 258048
[结果] 237568
[右移] 237568 >> 12
[结果] 58
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] D
[加法] bR56e5eL1UWJZzLu+6p1o + D
[结果] bR56e5eL1UWJZzLu+6p1oD
[按位与] 10202973 & 4032
[结果] 3904
[右移] 3904 >> 6
[结果] 61
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] t
[加法] bR56e5eL1UWJZzLu+6p1oD + t
[结果] bR56e5eL1UWJZzLu+6p1oDt
[按位与] 10202973 & 63
[结果] 29
[调用 apply] {函数: 'function charAt() { }', 上下文: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe', 参数: ''}
[返回值] Q
[加法] bR56e5eL1UWJZzLu+6p1oDt + Q
[结果] bR56e5eL1UWJZzLu+6p1oDtQ

```

可以还原出如下代码:

```js
function base64(encrypted,key) {
    const alphabet = key
    let out = '';
    let i = 0;

    /* -------- 每 3 字节 -> 4 字符 -------- */
    for (; i + 2 < encrypted.length; i += 3) {
      const v =(encrypted.charCodeAt(i)   & 0xff) << 16 |
                   (encrypted.charCodeAt(i + 1) & 0xff) << 8|
                   (encrypted.charCodeAt(i + 2) & 0xff);

      out += alphabet[(v >> 18) & 0x3f];
      out += alphabet[(v >> 12) & 0x3f];
      out += alphabet[(v >>6) & 0x3f];
      out += alphabet[ v      & 0x3f];
    }

    /* -------- 余数处理 -------- */
    const rem = encrypted.length - i;
    if (rem === 2) {
      const v = ((encrypted.charCodeAt(i) & 0xff) << 16) |
                  ((encrypted.charCodeAt(i + 1) & 0xff) << 8);

      out += alphabet[(v >> 18) & 0x3f];
      out += alphabet[(v >> 12) & 0x3f];
      out += alphabet[(v >>6) & 0x3f];
      out += '=';                     // 只补 1 个 '='
    } else if (rem === 1) {
      const v = (encrypted.charCodeAt(i) & 0xff) << 16;

      out += alphabet[(v >> 18) & 0x3f];
      out += alphabet[(v >> 12) & 0x3f];
      out += '==';                   // 补 2 个 '='
    }
    return out;
}
```
那么基本上加密的算法我们就解决了,最难的部分就是这个小数组的生成。这个数组因为部分原因暂时无法开源。我会把插桩放到这里,大家根据这个插桩日志可以还原。

本文的关键在于你通过ai去解决原先认为耗时,且易错的地方,你甚至可以将日志喂给ai让他帮你还原处算法,当你分析遇到瓶颈的时候,不妨去问问ai。因为这个算法的敏感性,我暂时无法提供完整代码只能给大伙提供思路和日志。

资料在附件。

涛之雨 发表于 2025-4-28 22:21

AI本身就是一个智能化的工具,
工具的上限取决于使用的人的上限。

utf8 发表于 2026-3-1 10:06

不苦小和尚 发表于 2026-2-27 20:32
没学会怎么用ai分析

其实就是让AI给你总结流程,一般来说就是在大量日志中让AI给你提供可能的思路,你可以顺着这个思路向下走。每个人用AI的手段和提问都不一样,你可以尝试找一下自己的那个平衡点。

feiyu361 发表于 2025-4-27 16:23

很不错的学习资源, 仔细的看看, 学习了

BrutusScipio 发表于 2025-4-27 18:29

哪个模型对于这种问题准确性高?

utf8 发表于 2025-4-27 18:42

BrutusScipio 发表于 2025-4-27 18:29
哪个模型对于这种问题准确性高?

我4o就够用了

YYSUNFENG 发表于 2025-4-27 21:56


这思路可以,学习了

chaogui701 发表于 2025-4-28 00:03

AI可以写出反二进制 插桩 代码,就能防住此种方法

linix 发表于 2025-4-28 09:28

学习了,感觉一头雾水。。

utf8 发表于 2025-4-28 09:56

linix 发表于 2025-4-28 09:28
学习了,感觉一头雾水。。

这个算法比较敏感,我不太敢发详细的讲解。

kookook 发表于 2025-4-28 12:24

虽然没看懂,但是还是要感谢分享

cavell2008 发表于 2025-4-28 17:02

研究一下
页: [1] 2 3 4
查看完整版本: AI与JSVMP的初次结合-深入浅出的逆向JSVMP