Bootstrap

【中等】 猿人学web第一届 第2题 js混淆 动态cookie 1

调试干扰

进入题目正常加载数据后
打开调试工具,等待一会(2~3分钟) 刷新页面 cookie 失效以后会弹窗
删除 cookie 中的 m 字段再刷新页面也是一样的
在这里插入图片描述
点击确定后,页面自动刷新完会进入 无限 debugger
在这里插入图片描述
查看上一层堆栈
生成 debugger 的代码 是经过混淆的
在这里插入图片描述
手动解混淆后的代码
在这里插入图片描述

(function () {
    // function 中的代码并不会执行,debugger主要是靠 ['constructor'](('debugger'))['call']('action') 执行
}['constructor'](('debugger'))['call']('action'))

// function(){}['constructor'] 是 Function
// 上面的代码也也可以写成
Function.prototype.constructor('debugger')()

在这里插入图片描述

Hook Function

这个 debugger 是靠 Function 的构造器生成的
Hook Function.prototype.constructor 就可以过掉这个 debugger

let _Function = Function.prototype.constructor;
Function.prototype.constructor = function(Value){
    if (Value.indexOf('debugger') !== -1){
        return _Function.call(this, '')
    }
    return _Function.call(this, Value)
};

将代码在控制台运行就可以正常调试了
在这里插入图片描述

加密参数定位

数据接口在 https://match.yuanrenxue.cn/api/match 里
对应的请求参数为 page(页码)
在这里插入图片描述

加密参数在 cookie m字段在这里插入图片描述

hook Cookie

删除cookie中对应的 m 字段

在这里插入图片描述

hook cookie 找到 m字段加密的位置(加上 hook Function 的代码)

// Hook Function
let _Function = Function.prototype.constructor;
Function.prototype.constructor = function(Value){
    if (Value.indexOf('debugger') !== -1){
        return _Function.call(this, '')
    }
    return _Function.call(this, Value)
};

// Hook Cookie
(function () {
    let cookie_func = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')
    Object.defineProperty(document, 'cookie', {
        get() {
            return cookie_func.get.call(this, val);
        },
        set(val) {
            if (val.indexOf('m') !== -1){
                debugger
            }
            return cookie_func.set.call(this, val);
        }
    })
})();

在这里插入图片描述

hook 到 cookie 后,向上查看堆栈就能找到生成 cookie m参数的位置
在这里插入图片描述

AST 解混淆

每次请求返回的代码都不一样,但执行逻辑是一样的,所以将 2.html 文件替换,方便调试
在这里插入图片描述

js代码是在 2.html 文件里,script代码 是被 script标签 包裹的(只需要将被标签包裹住的代码还原即可)
在这里插入图片描述
将代码 copy 到本地
在这里插入图片描述

字符串解密

先看看混淆代码

document[$dbsm_0x4638('\x30\x78\x34\x38\x39', '\x28\x37\x28\x5a') + $dbsm_0x4638('\x30\x78\x34\x61', '\x29\x69\x38\x67')] = _0x5eed8e[$dbsm_0x4638('\x30\x78\x33\x61\x36', '\x7a\x6b\x34\x53') + '\x79\x62'](_0x5eed8e[$dbsm_0x4638('\x30\x78\x63\x36', '\x64\x79\x2a\x5d') + '\x79\x62'](_0x5eed8e[$dbsm_0x4638('\x30\x78\x34\x65\x33', '\x64\x75\x52\x62') + '\x79\x62'](_0x5eed8e[$dbsm_0x4638('\x30\x78\x31\x62\x33', '\x44\x21\x4c\x4b') + '\x79\x62'](_0x5eed8e[$dbsm_0x4638('\x30\x78\x34\x62\x38', '\x54\x45\x58\x6e') + '\x79\x62'](_0x5eed8e[$dbsm_0x4638('\x30\x78\x34\x32\x65', '\x29\x69\x38\x67') + '\x79\x62']('\x6d', _0x5eed8e[$dbsm_0x4638('\x30\x78\x32\x64\x38', '\x6f\x38\x4a\x47') + '\x67\x61'](_0x2fdc55)), '\x3d'), _0x5eed8e[$dbsm_0x4638('\x30\x78\x33\x38\x31', '\x39\x52\x36\x32') + '\x70\x6d'](_0x691b6d, _0x29c654)), '\x7c'), _0x29c654), _0x5eed8e[$dbsm_0x4638('\x30\x78\x37\x38', '\x72\x69\x63\x50') + '\x62\x5a']);
location['\x72\x65\x6c' + $dbsm_0x4638('\x30\x78\x31\x31\x63', '\x6e\x34\x54\x28')]();

// 解混淆后
document['cookie'] = (((((('m' + (_0x2fdc55())) + '=') + _0x691b6d(_0x29c654)) + '|') + _0x29c654) + '; path=/');
location['reload']();

还原解密函数

混淆的代码中有很多处字符串是 $dbsm_0x4638 函数生成的
查看 $dbsm_0x4638(解密函数)
在这里插入图片描述

解密函数依赖 $dbsm_0x23b3 数组
在这里插入图片描述

文件开头 $dbsm_0x23b3 是一个大数组 后经过一个自执行函数打乱排序
在这里插入图片描述
应在浏览器环境中先拿到 打乱排序后的数组 $dbsm_0x23b3在这里插入图片描述在这里插入图片描述
在断点处断住之后,copy大数组
在这里插入图片描述> 将 copy 到的数组拿到之后,替换到本地,(自执行函数就不需要了)
在这里插入图片描述

解密函数中 有很多 if 分支,在浏览器打上断点调试
这里大数组的值是对的,与浏览器相同
在这里插入图片描述
在这里插入图片描述
第一个 if 条件是通过的 通过以后进入了一个自执行函数 F9 或单机 在这里插入图片描述
进入这个自执行函数
在这里插入图片描述
首先会进入一个 try catch 块
在这里插入图片描述
查看 Function 里面的代码 在这里插入图片描述
执行这段代码后 浏览器返回的是 window (全局对象) / nodejs 返回的就是 global
在这里插入图片描述
在这里插入图片描述
atob在浏览器环境中是有的 但是在node中没有,node需要补上 atob 这个函数
true || true 不会执行后面的代码
在这里插入图片描述
后面的代码不会执行,所以 atob 还是一个系统函数 nitive code
在这里插入图片描述
在node中补 atob
atob = require(‘atob’); // npm installer atob
自执行函数执行完之后,给解密方法添加了一些属性之后,这个自执行函数就结束了
在这里插入图片描述

继续向下执行,查看这个 if 条件通过后的代码
打上断点后,F8 跳到这个断点或 单机在这里插入图片描述
在这里插入图片描述
前面都是定义,在执行方法处打上断点后直接跳到这个代码段,再单步调试查看这个函数执行了什么
在这里插入图片描述
做了一个 格式化检测
浏览器里的值是 true
在这里插入图片描述
在 node 值是 false,将 node 改写 写死为 true
在这里插入图片描述
在这里插入图片描述
上述的步骤做好后,解密函数就可以正常执行了,测试一下
在这里插入图片描述

AST 配合解密函数还原字符串

将代码拿到网站中查看对应的结构 AST explorer
在这里插入图片描述
需要遍历 CallExpression 类型的节点
并且 callee 属性为 Identifier 节点
Identifier 节点的 name 值为 $dbsm_0x4638
$dbsm_0x4638 是解密函数

// 安装 babel 库:  npm install @babel/core
const fs = require('fs')

const traverse = require('@babel/traverse').default  // 用于遍历 AST 节点
const types = require('@babel/types')  // 用于判断, 生成 AST 节点

const parser = require('@babel/parser')  // 将js代码解析成ast节点
const generator = require('@babel/generator').default  // 将ast节点转换成js代码

// 读取(路径记得改)
const ast_code = fs.readFileSync('demo.js', {
    encoding: 'utf-8'
})

let ast = parser.parse(ast_code)  // 将js代码解析成ast语法树

// 这里插入解析规则
///

// 解密函数中需要的 atob 函数
global['atob'] = require('atob');  // npm install atob
// 解密函数依赖的大数组
var $dbsm_0x23b3 = ["QjjDhA==", "IyQb", "552u776q5L6D", "eCvDoA==", "EHwT", "wpdVw6I=", "RArDvA==", "Hk8D", "MUvCnA==", "wotlw5k=", "w7xTwrU=", "wrLCvT0=", "w5LCvUc=", "w6hIwrY=", "w716Rw==", "L8OzwpI=", "MlMA", "Gm8r", "WcKVw44=", "W8KKw5s=", "w6bCgUE=", "TSnDpg==", "aEXCuw==", "HMOzwrc=", "wqs3Bg==", "KHsW", "AcOtwp4=", "N8KeIA==", "cifCig==", "wrBZw7M=", "AMKtw4g=", "FMOkwqA=", "WwEa", "DjzDqA==", "wo7CnAs=", "wpdoAQ==", "JsOfwp0=", "J8KRKA==", "ZsOCw58=", "wojCiAQ=", "w7vCuMKR", "ATY3", "ZyfCvQ==", "dCJD", "UMKpVg==", "O2US", "wqE3LA==", "SMOtwqk=", "w5PCh8Ki", "bMKyaA==", "S8OjEw==", "AcKGw68=", "wpVFw5M=", "fDvDpw==", "w7Brwqk=", "dGYb", "eC45", "AsOGwrE=", "w7fDhcKz", "YATDlA==", "DsK6w6A=", "wrNLw7U=", "biAN", "TxVF", "VzJ2", "wr3CrRc=", "wr0WEQ==", "YAvDrw==", "wqtZNg==", "K0QC", "Y8KBw6c=", "Q8KEw6E=", "wrUhKQ==", "CXfDjA==", "G34/", "esOcTQ==", "wpFiDA==", "w4xCaQ==", "Blo7", "w6vDvcKT", "eyFl", "BE8K", "w6HCvUs=", "wplqw6M=", "wqdOw5Y=", "wqzDr8KW", "XsKdcw==", "VMKsag==", "ecO9w58=", "EkcB", "wpJIw5U=", "JFrDiA==", "YsO7cg==", "eTvCiA==", "wojCuxc=", "WyXDmw==", "MUrDtg==", "w5XDhcKw", "fMKLcw==", "eMOhw5w=", "EGnCjA==", "RcKTYg==", "OALDvQ==", "HlE/", "Q8KGag==", "wpQpFA==", "wqg5wqw=", "ZsOqw4A=", "wp1Ewpk=", "wpkPwro=", "UT9O", "XsOmw7g=", "CFkm", "W0gI", "P8Ouwrw=", "eEMQ", "L8KSw7k=", "ecOvw4Y=", "WT9O", "J8KYfw==", "BiEH", "w7VnwpM=", "w6dxbg==", "wo/Ci8Os", "wqgpAg==", "wozCm8OB", "clHCjA==", "QsOsw6Y=", "woZew44=", "Zz7DnA==", "RgzDrg==", "XMKAVw==", "SwBb", "VMKCSg==", "Ryp1", "wr9Mw44=", "w4rDqMK7", "UMOiw6E=", "w6fDo1U=", "VMOEw4c=", "EcKew4c=", "c8KRZQ==", "WsOOUQ==", "wodyLA==", "e8KMUg==", "w5TDln0=", "GcKbw4s=", "BMK0w7Y=", "wpIewoU=", "R8Kcw6k=", "wobDuMOi", "BsO/wp4=", "VcOnw6w=", "w5t0wok=", "wqgPwpA=", "woTCu8Or", "fg3DvQ==", "L8KEw6g=", "wphswpI=", "woYgIg==", "AXgq", "VTLCqg==", "wrRww4Q=", "wqM1Ig==", "YCzDjQ==", "EVkx", "PWsV", "JWbDjw==", "DF4M", "WcObw54=", "DMKXw6w=", "EcKmOA==", "WsOJw58=", "ajsY", "SsK1w4Q=", "w4zDqMK0", "Gics", "UTkL", "w754wrA=", "IBw2", "wopkDA==", "NFEb", "EFHDig==", "W8Okw40=", "C8KpVg==", "EmnDsQ==", "VhvDmA==", "wqTCoMOV", "fcOfw6A=", "JsKkNw==", "ecOjKg==", "aSTDsA==", "woYfOg==", "YcOyYA==", "fMOtw4E=", "eMOSw5A=", "w7jCn8KA", "LGI2", "asO0Ow==", "f2cW", "egvDuA==", "GcOeGQ==", "w4NYQw==", "IMKvw68=", "wrfDpsO6", "BcKjJA==", "w6PDu2g=", "ayTDrA==", "B0kt", "QsKTVg==", "wpvCuMO1", "YsOHw6M=", "B1XCuA==", "B8Kjw5w=", "Q8Oqw6g=", "RMOAw4c=", "w4/DssK0", "w4rDm8KQ", "ScOwQg==", "YsOGw5s=", "RjbDjQ==", "SCLDpg==", "VcOVMQ==", "KnHCgQ==", "JMONwrU=", "WcO/Cw==", "YcKuRQ==", "wr0MCw==", "WAHDnw==", "esKuUg==", "wp8mNA==", "MMOAEw==", "bcOBw4w=", "w5LCl8K/", "KXk3", "agpl", "wprChSg=", "w5BmYw==", "S2zCrg==", "BXIv", "EMOUwpA=", "WcKvVg==", "WsKkw4I=", "w69iwqQ=", "e8KYVw==", "Y8Ojw6s=", "KUUk", "LcOYwq0=", "Xj/DvQ==", "RiXDkg==", "wrbDiMOj", "Ujd6", "cAc+", "dzt2", "QsO9w6w=", "Ghg3", "ccKkcA==", "fRvDkA==", "KcK4Og==", "H30u", "PMKyw4Y=", "YyrDtw==", "wpDCiMOh", "wqwowoc=", "wojCjDQ=", "wqHCj8OU", "w7HCm8KR", "XsOVw7Q=", "w47Cp8Kj", "w6LCnMKo", "GsKMbw==", "w5J0wrU=", "RCnDuA==", "wpfCgjE=", "wrMnBw==", "w7bDqsK/", "KEM4", "a8OKwrw=", "wpBlw5Q=", "MTAo", "X8K2w5I=", "WsOvFQ==", "Yz7DkQ==", "W8Ocw54=", "ahtQ", "D2vDrg==", "VsKcw4o=", "Fy/CkQ==", "JnAI", "MMOswrA=", "w4zDt8KI", "wrDCksOj", "GBcc", "fcO9Sg==", "w4HDgXY=", "MsKeHA==", "ccOBw4o=", "QsOgw4M=", "Q8OjBg==", "EMK5FQ==", "R8OCw6o=", "XS9D", "d8KfcA==", "wpbCmSE=", "w4XChn8=", "aMKieA==", "woVhGQ==", "wo7CnsOK", "AXwd", "dCAI", "worDhsOC", "V8Krw4A=", "VxHCvA==", "woFywrg=", "w4ZRaA==", "VMO5w6Q=", "wp1zHg==", "wqw/wqo=", "BMKRw58=", "wpxjw7U=", "McKEw4o=", "YyIF", "fkME", "wp1xw6o=", "Sg80", "HMKbAQ==", "HHoX", "MsK7Cg==", "woZWCw==", "GsOKwrE=", "P8KPGg==", "bBDDhw==", "ewLDng==", "TSMk", "wrbCrT4=", "w7tkRg==", "DDQv", "wrdpLw==", "wonDmsKK", "Tx8o", "WMODw7I=", "MXgT", "w6PCrUw=", "wobCg8OR", "Z8Odw6U=", "w55LwrA=", "O8ORwqU=", "w5vDo10=", "wq3Cl8OT", "asKMUQ==", "woBpPg==", "SnPCrA==", "wo7Dn8KG", "wqVtw54=", "wo9WNA==", "QMObNw==", "TMKAw4Y=", "eHEn", "w5rDqcKk", "wqRlw68=", "CxYO", "WcK2VA==", "wpgrAw==", "wpHCgw4=", "wrHCklU=", "BkIZ", "woh4wqM=", "wpBICg==", "AcORGg==", "wpd0NQ==", "w4HDqsKa", "YcKvew==", "wpvCusOs", "K8K5JA==", "w7LCrGU=", "XkUT", "XMOow6s=", "w7/DqcKj", "NsOdwqQ=", "VcOsw7Q=", "eXED", "McKbdA==", "AHXCow==", "K8KeQg==", "ZgMB", "Hm4g", "f8Oqwow=", "AHPDpA==", "wq4Mwq0=", "WsKeYg==", "fDjCog==", "wpY/PQ==", "V8K9cg==", "OlAN", "esO8Xw==", "GsKaJA==", "WgjDnQ==", "DW7CrA==", "f8K1Qg==", "eSw0", "RAIx", "Cls9", "FMOYwqM=", "w4bCvVE=", "wovDkMKK", "WsK/Tw==", "QRrDgw==", "wpV9w4o=", "wrXCmxA=", "wpXChik=", "wq5kw7g=", "wo5jPA==", "w5VgZQ==", "wr1Cw4o=", "wpBYw60=", "woVOwpw=", "wpB2Cg==", "cBlA", "wo52Cg==", "QcO/w58=", "w65UwrM=", "fyfCng==", "w6TCp2s=", "wrRWJQ==", "w7bCv8KW", "XsKyeQ==", "MWbDiQ==", "w4jDscK1", "d8K1w4U=", "C34+", "wprDt8O9", "VsKlw7E=", "w4JdfQ==", "wos1Jg==", "PE7DuA==", "w4bDnsKM", "w5XDq8KA", "JTIy", "w5LDpMKu", "YArDsQ==", "K8K9IQ==", "DsKmw7E=", "BMKxw7A=", "wrvDncKg", "dzrChQ==", "G1nCjg==", "YEYA", "OsKzJg==", "wrfCugs=", "XlvCkA==", "fcKDw54=", "e8OMw40=", "wpBDw68=", "w45CwoY=", "WsONwpw=", "BFDCiQ==", "w7VidA==", "Aloq", "w73Cq8KT", "IkE4", "wqN0Nw==", "dBLDmw==", "wqlRw44=", "w7lleQ==", "C1TCgQ==", "PsKPJQ==", "VcK0bg==", "XcOBwo4=", "VMOjZQ==", "w7pjXg==", "wrBvFw==", "cARj", "w4JSaQ==", "MsK4w4Y=", "acOeeQ==", "AsOQIQ==", "wqUDBQ==", "X1Zb", "RMKKaA==", "w6fDs8KB", "HsKzdw==", "V8OJLA==", "XMOFwqo=", "V8Kybw==", "w5zDhG4=", "wrFHNQ==", "RcOhw6s=", "w6Vhbg==", "XcOow48=", "w5bCi24=", "NkfDgw==", "AcOyHA==", "XUzClw==", "w5XCgGY=", "w5rDhVA=", "a1c3", "WnzCsw==", "wrvDncK4", "w7pUwqk=", "QT1j", "DmLCuA==", "w69tVA==", "w6bCvMK+", "cVUo", "dcO8wqc=", "cBlK", "w5zDhWc=", "wpt+w6w=", "w6lFwrI=", "wojDiMOS", "XcOZw78=", "UwhO", "wotmw4M=", "RC4Y", "w77CjU0=", "S8O3w6U=", "PGAG", "WsKowq8=", "wqTDmsOo", "Hlo8", "I8OuwqQ=", "c8OAKA==", "cl7Cmw==", "V3PCvA==", "DnM2", "wqQTGQ==", "WWYV", "wozDosOV", "w7fDisKb", "csO+w4A=", "IsKiPw==", "w75iQA==", "Ww7CgA==", "wqtrLA==", "fsKtw6c=", "DsKbw5M=", "w5fDgMKO", "wrcaIQ==", "S1c5", "wrMaOQ==", "AcKIcA==", "Cjww", "w6VWYA==", "OQom", "ZxjDjQ==", "wrMoNw==", "VQXDmA==", "d8KeYQ==", "BEs8", "J0k9", "wpEeEQ==", "wqAHFQ==", "w6/DicKx", "ScOiCg==", "YxXCtg==", "dsOiw4k=", "THjCqQ==", "HMK+AA==", "wpQhHw==", "wr7CvcOq", "K0bDiw==", "eMOAcg==", "w60rdg==", "L1IC", "woNlw60=", "K8KDw4k=", "wrpFDg==", "wpFEMw==", "w6fCrGw=", "wo0mCA==", "cUTCtQ==", "w7LCqMKX", "W8OiwoQ=", "QAvDqQ==", "AD03", "aDfDiQ==", "UTHDpQ==", "ZhMa", "w6bDrMKs", "AkvCuw==", "wo8yBQ==", "wo4IPQ==", "M3QK", "TwrDnw==", "wqFcDw==", "e8O7bA==", "PkHDlg==", "esOBwqk=", "eRFw", "ZyvCnw==", "w7PDtcKx", "wpQ1woA=", "WwFc", "XRsF", "BMOCPQ==", "SHHCjA==", "XcOew5w=", "wqhaKA==", "YynCvg==", "XS3Chg==", "BFI0", "wr9HDA==", "wpx7w5o=", "w6DDmHU=", "bA84", "I3AA", "w7jCn2s=", "BWPClw==", "wpbDt8O1", "wpsKYw==", "wq9jw5I=", "woFQwp4=", "wpI9Mw==", "B8KwEQ==", "DmYq", "CcKbAQ==", "TS49", "w6bDvWU=", "YsOVNw==", "dMKBRQ==", "NXg8", "wrBJwoI=", "KsKAYQ==", "EcKNdQ==", "ecO7OA==", "wrV6w7I=", "WMOSw6Y=", "wqV6wqI=", "VcKyUA==", "fcO4Sg==", "IXQl", "Z8KaXw==", "VnvCnQ==", "wr9qOg==", "w6PDiGs=", "QD0a", "wrzCm8OQ", "w6LCp1w=", "bMK+w6A=", "w7PDn24=", "T2LClg==", "woBJw7c=", "SiPDjQ==", "wqbChTI=", "Wj3Dpg==", "fxgU", "YhzCuA==", "ETsw", "W8OdCA==", "GcOxIg==", "Kxkw", "B2zCuA==", "OBER", "Cl4R", "wrLDpMK8", "wq/CnsOZ", "w5XDv8Kw", "dysc", "Y8KjVQ==", "fcOvw40=", "CWjDug==", "bMObNg==", "ScOEw4c=", "w6RTwqM=", "wpJLEw==", "BTw5", "ScKDw4c=", "XMKbw5o=", "TxjDhw==", "w5pOew==", "wpJawp0=", "ZsKwQQ==", "FGMO", "GMKRw7o=", "QMO+OA==", "wrtaMQ==", "TMOUMA==", "J3jDuA==", "D8OnwqA=", "w7zCgcKv", "VnLCmw==", "Z8OJw4I=", "bADDng==", "ccKCZg==", "wrIUJA==", "XCHDow==", "w6DCsV8=", "ZsKafw==", "w5J7fg==", "M8OMwps=", "w7DDt8KG", "W8OYXw==", "EHDDhw==", "w63ChsKU", "O8Kiw4k=", "wrlxDA==", "wrnCkcON", "wqFfHg==", "wovDsMKh", "w67CmMKk", "w75Pwq8=", "wq/DnMKX", "SyhS", "wp1uOA==", "wr3Dt8KG", "DnI2", "OWEf", "w5PDisKX", "wr3CuRE=", "YBJu", "wrxgw58=", "wrEEIQ==", "Uy53", "V2/CjQ==", "ecOjw6Q=", "SMKjw5s=", "X8O5w7Y=", "RsK3w50=", "wpA+wro=", "aynDjQ==", "ccO5w6E=", "ezjCjw==", "BMOPJQ==", "w7FFwq8=", "QsOnw6Y=", "w5VRQQ==", "HmkA", "f8Oewr0=", "dsO7w78=", "w7PDrcKT", "w4vCr3E=", "X8O6w7s=", "CRTDqQ==", "VcO8w54=", "KmjDrA==", "w4dSfQ==", "BG7DpQ==", "bMOvw54=", "bi5F", "VDjDpQ==", "w6HCiFo=", "aMOYCA==", "w5fDqE8=", "CXbCpg==", "FMKwIg==", "w4BxSQ==", "QTbDow==", "J2si", "MsOxwpI=", "IsOdHA==", "wojDlsKP", "Hn44", "bMOQRg==", "dMKCWg==", "w7rDnF4=", "B8K5w58=", "WSjDpg==", "XsO5w5g=", "QTo7", "wqUZwoM=", "ecK1aA==", "esKDUA==", "woFCwrE=", "woISwos=", "dsODEw==", "McOrOQ==", "JVTDmA==", "XcKxbw==", "wqZZBg==", "OsKjFg==", "UQTDkg==", "woh3w4A=", "w5FXwpM=", "wpJAw7w=", "Ongr", "w41zwos=", "N8OGDw==", "w6DDicKj", "UQ0U", "CsKCTw==", "fTnDhA==", "w6TDqHA=", "AloY", "CV4e", "DsKJbQ==", "LyoG", "OFnChA==", "NFsh", "w596fA==", "w6FsYA==", "Pm/Chg==", "wrZ1Ew==", "wprDmcKo", "C3QW", "wo7CqDM=", "woYANg==", "wq3Dl8Ok", "wp7DlcKp", "csKXeA==", "wqVyHA==", "wptxw6k=", "IMOIwpE=", "HcKkw78=", "XzXDsg==", "Q8KAw48=", "QMOOWg==", "V3TClA==", "woY5Pw==", "K2jCng==", "c8OewoY=", "w5zDqVY=", "Al/Cmg==", "w7TDp8Kg", "wpjCoiU=", "G8ONAA==", "w7rCjMKO", "RSjDsg==", "esODbg==", "EWcq", "NsK4BA==", "PcKeEQ==", "GcOpJw==", "cTpO", "wrzDl8Kv", "CcKSw7I=", "fhPDpw==", "wqcfLg==", "B8KiIQ==", "OcKQw78=", "SjHDug==", "w4vDvcKd", "wq8kGQ==", "HH8J", "DVbDsg==", "LXHDrA==", "WCpe", "N8OjGQ==", "MVrDjA==", "ZB/Dpg==", "w7xvwpE=", "WwjDvA==", "wo4cIQ==", "esOvEw==", "wpJRw7Y=", "TRNg", "wrZ0Ag==", "dcOLcQ==", "bsKAw6E=", "wqdoPg==", "XDrCgg==", "wosKPw==", "bwTDvw==", "XQAy", "wpAUwoU=", "dB4t", "wpFRNw==", "UMKwQQ==", "ecOlw48=", "w6TChMKP", "XxFP", "A8K5Pg==", "w5dbfg==", "woDCtcOn", "IE3Cqg==", "JUvCqg==", "HzYw", "ecKEaA==", "fQEi", "fQR3", "J8KsEQ==", "b8Ofw6U=", "MsK6Jg==", "w7bDsMKT", "wqxuwps=", "XxPCrg==", "JcKQbg==", "FsOtAw==", "RcOBw6U=", "YcOxUg==", "EnAz", "ci8a", "VcO9w6E=", "Qj7Dvg==", "YMKEeQ==", "wqLDiMKl", "w5xawoM=", "TMOow6k=", "eRjDpQ==", "DXjCgQ==", "wq87HA==", "w5jCrMKw", "YsKzVw==", "fcOrwq8=", "wpNxw40=", "BgIo", "YcOEw6Q=", "BsKkw7M=", "L1XDiQ==", "DMKeaQ==", "cT3DmA==", "WDtL", "HVQy", "YTzDow==", "TsOZw5A=", "wpLCnSI=", "Ri8m", "w4fDiU0=", "ah5R", "w4TCuEs=", "w6bDusKY", "dgDDow==", "RAx3", "w71XVg==", "X8Obwoo=", "wrfDi8Kd", "ZsO+w5o=", "cB9B", "BH4p", "USBR", "w4bDksKn", "dSXDmQ==", "YMKew4A=", "V8O9BQ==", "wooxGQ==", "VX/Csg==", "XsOEw6Y=", "wrofBg==", "wpUBBw==", "wq87Gg==", "w4HCo0E=", "wpnCrAw=", "asOGwok=", "wqTChyA=", "wr91KA==", "FsKSLg==", "w5LDrMK5", "UxTDqw==", "JCMb", "IlfDmg==", "a8ONYA==", "IMO/wqM=", "OsOMwoI=", "YnM7", "YcOhcA==", "ZgDDhw==", "fcOnwq8=", "QAJu", "METDqw==", "HMKYRQ==", "IsKBw4g=", "wq9Cw5Y=", "WsOZFw==", "wrZkw60=", "aTAu", "bzgc", "RcOPBw==", "wqhlMQ==", "eMOrw48=", "O8Kjw68=", "STbDjA==", "wqvDgsOf", "G8K0bw==", "DsKdfQ==", "w4HCgWY=", "bgHDvw==", "CXPDlg==", "woFJFQ==", "wqDDlcKF", "QADDtg==", "w7tkSQ==", "Vgo3", "BEUK", "wrN2DA==", "wrHDlcKk", "XMOiEQ==", "wq/CnCU=", "QcKUUw==", "ODRV", "wpJuwpc=", "w67DkXY=", "NMOwwr0=", "VD8w", "KG4V", "acOAwqg=", "LMKWKg==", "wrLDmsK7", "a8K3bw==", "w6nDlMKA", "Y8OJw4s=", "w7xjSQ==", "AMKOdg==", "ay9S", "woFUPg==", "DcKVbA==", "Q8ODw4Y=", "w6JkTw==", "wrx5Hg==", "wr/DhsKl", "wo9QMQ==", "bSXDrg==", "eMOrWA==", "GMKpw78=", "w6fDuns=", "wqnDuMKI", "I1rDug==", "IHsb", "wqJMHw==", "OMOdwoM=", "HW4u", "w6JFQQ==", "wrJHEg==", "wpZcw7U=", "wq1tGw==", "wol2wog=", "w6nCu0s=", "wpLDl8KP", "woPCusOl", "wr7CtMOG", "wofDgsO2", "wprCuys=", "cD7Dhg==", "BWMM", "GMKYPA==", "WMOOw44=", "w4VFXA==", "w7DDmk0=", "F8KDOg==", "wo8jCQ==", "bcKEw44=", "aCkH", "cV0v", "aMO9Dg==", "cMOjw5E=", "CiM0", "Sy0W", "dTPCug==", "FsOuwp4=", "BkAs", "ZnkQ", "w7oxw4I=", "WMOPw4w=", "wqvCvyI=", "SRbDow==", "YinCjQ==", "cz4p", "w6PCqsKV", "VgVq", "BCE2", "w5LDrV4=", "TcO2Jw==", "eyRA", "a8Ouw7o=", "J1jDog==", "QcO5w40=", "FkvDjA==", "GMKpLg==", "ZwTDsg==", "wqzCsMOJ", "YS7ClA==", "w4bCuk0=", "ZMOOIA==", "wo4fwpQ=", "S8K6Vg==", "QcObw6U=", "wq9DHQ==", "IXgZ", "FFwc", "wqhvOA==", "wqBnwrw=", "QsOfJg==", "NW8A", "RRPDow==", "VAIr", "D8Kaw4s=", "X8OcGQ==", "JGEU", "eMKTbg==", "Y8OYbA==", "XcKaRQ==", "FMOrAQ==", "fwjCoA==", "wqnDhMK7", "wqkVwq8=", "P8KUfQ==", "Yh7DpA==", "BAsm", "RMK2w50=", "PcOwKg==", "CcKbw6w=", "HsKWTw==", "eyrDmA==", "woDDi8KC", "A2fDjw==", "YRTDlg==", "UsOow64=", "LCsE", "wo4dOg==", "wphxwpE=", "woUcAA==", "wqMfAA==", "TMKAw4U=", "GsKDw7k=", "PTE8", "wrlPGA==", "wqPDn8OT", "ZcOBw60=", "wrjCuMOq", "W8Kmw5k=", "XMOaw7k=", "wqxzwpM=", "fhDCqg==", "QMO+w7E=", "DVgs", "w6lSwrg=", "VMOHw6g=", "P8Oowrg=", "w7zDqHk=", "wq4CAw==", "wqpTDw==", "bDpH", "QcOYw4M=", "SBkv", "worCicOp", "wo0hGQ==", "w5JgWA==", "YQ5g", "AsK+Xg==", "XMOEwoo=", "ZiAN", "IsKsBQ==", "w6PDpVw=", "wrrCjSY=", "TcK+w6M=", "wp/DkMKL", "fhwQ", "ZHcF", "VDXDqw==", "w7rDg8Kg", "w5pywpc=", "UH3Cqg==", "AMOJwpI=", "wpxwwrU=", "SsONwo0=", "Az8p", "U2fCnA==", "wrLDlcKB", "XSlH", "QcOhKA==", "LG7CnQ==", "w6LDlsKm", "w5hkYQ==", "wqvDi8OU", "wo7CqDE=", "fAvCgQ==", "G8Kzw7A=", "YVAg", "wo/CnSY=", "Dk7CgQ==", "RzzCmw==", "P8OdAA==", "wqFcDQ==", "K8KVSA==", "woVawp8=", "JnEi", "w67DmsKc", "w6JRTw==", "DMK9cA==", "aBhR", "Zi4W", "dhzDvw==", "RsO7wq4=", "ecOcw6E=", "JcOmwqY=", "EcKwVg==", "WsKXeg==", "Byo1", "ElYq", "BloJ", "XMO4Ew==", "wo5+w7g=", "Mkk8", "wqAhJw==", "bjjDuw==", "w7bCpsKR", "Z8O7aw==", "d3fCvw==", "wpbDpcOF", "ScK7w7I=", "CkfDjg==", "ecOafA==", "YMOBw4A=", "wo0dwq4=", "dsKWTQ==", "DcKQZA==", "IEvCpw==", "w7fDulQ=", "aXnCkg==", "woMpJg==", "fWQq", "NnPDkQ==", "USBV", "U2gZ", "RsKBZw==", "e8K/cg==", "WMK5w4s=", "wrFww5I=", "w5PDhHk=", "ZsOxwos=", "wp3DisKX", "w7DCmVg=", "w6x4Rg==", "LH4K", "O20W", "ZMOZw7U=", "PMKfaA==", "bRhn", "Izwv", "w4cfwqU=", "w4fCpG0=", "aBvDoA==", "RMKveA==", "QcOxSg==", "V8K7cw==", "J8KeQg==", "w4LDiX0=", "IsKSUQ==", "VQXDkw==", "LXMp", "IsKgw6w=", "TCU4", "ayl1", "w6TDksK+", "Zn0Q", "AHbDug==", "w7JSwpg=", "G8OpwoM=", "fS1h", "wrxxw4s=", "wogKAw==", "wpYvwqA=", "eWXCkw==", "U8Ofw70=", "e2sT", "woUBAw==", "w6LDjmw=", "a8OPw54=", "U8KHbw==", "HTA7", "wonDs8Kk", "BFQG", "w5PDolU=", "ciXDkA==", "NcOSwrg=", "fCTDow==", "woYuwpQ=", "alQl", "S8Kbw5U=", "woRaw7M=", "E34q", "O8KdJg==", "WAHDng==", "w6DCmnA=", "OkYH", "Y8KWRQ==", "w5VNwpk=", "I0HDpg==", "wrQSJA==", "aQ9P", "HcKBw6g=", "eQnDsA==", "wpAcOw==", "w5HDmsKC", "w5tWwrs=", "ecOcIQ==", "JcKvMA==", "bRh5", "cB0F", "VjTDgA==", "wptrw7s=", "WDnDrw==", "Rz09", "wpYdAA==", "wrpUwpM=", "DcKifg==", "wp/DusKm", "wqAoOg==", "a17Cmw==", "J2k1"];
// 解密函数
var $dbsm_0x4638 = function (_0x1e1b14, _0x23b316) {
    _0x1e1b14 = _0x1e1b14 - 0x0;
    var _0x4638d3 = $dbsm_0x23b3[_0x1e1b14];
    if ($dbsm_0x4638['lIzlCZ'] === undefined) {
        (function () {
            var _0x4b121c;
            try {
                var _0x1d5b59 = Function('return\x20(function()\x20' + '{}.constructor(\x22return\x20this\x22)(\x20)' + ');');
                _0x4b121c = _0x1d5b59();
            } catch (_0x4f5869) {
                _0x4b121c = window;
            }
            var _0x55f54d = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            _0x4b121c['atob'] || (_0x4b121c['atob'] = function (_0x2337bc) {
                    var _0x94736f = String(_0x2337bc)['replace'](/=+$/, '');
                    var _0x5e548f = '';
                    for (var _0x588d26 = 0x0, _0x5d3f20, _0x558d8e, _0x49832a = 0x0; _0x558d8e = _0x94736f['charAt'](_0x49832a++); ~_0x558d8e && (_0x5d3f20 = _0x588d26 % 0x4 ? _0x5d3f20 * 0x40 + _0x558d8e : _0x558d8e,
                    _0x588d26++ % 0x4) ? _0x5e548f += String['fromCharCode'](0xff & _0x5d3f20 >> (-0x2 * _0x588d26 & 0x6)) : 0x0) {
                        _0x558d8e = _0x55f54d['indexOf'](_0x558d8e);
                    }
                    return _0x5e548f;
                }
            );
        }());
        var _0x2ef3c5 = function (_0x49a1eb, _0x27f9fb) {
            var _0x26a837 = [], _0x90ed46 = 0x0, _0x1e184c, _0x229955 = '', _0x28a13b = '';
            _0x49a1eb = atob(_0x49a1eb);
            for (var _0x4237c8 = 0x0, _0x18c69a = _0x49a1eb['length']; _0x4237c8 < _0x18c69a; _0x4237c8++) {
                _0x28a13b += '%' + ('00' + _0x49a1eb['charCodeAt'](_0x4237c8)['toString'](0x10))['slice'](-0x2);
            }
            _0x49a1eb = decodeURIComponent(_0x28a13b);
            var _0x2c4f5b;
            for (_0x2c4f5b = 0x0; _0x2c4f5b < 0x100; _0x2c4f5b++) {
                _0x26a837[_0x2c4f5b] = _0x2c4f5b;
            }
            for (_0x2c4f5b = 0x0; _0x2c4f5b < 0x100; _0x2c4f5b++) {
                _0x90ed46 = (_0x90ed46 + _0x26a837[_0x2c4f5b] + _0x27f9fb['charCodeAt'](_0x2c4f5b % _0x27f9fb['length'])) % 0x100;
                _0x1e184c = _0x26a837[_0x2c4f5b];
                _0x26a837[_0x2c4f5b] = _0x26a837[_0x90ed46];
                _0x26a837[_0x90ed46] = _0x1e184c;
            }
            _0x2c4f5b = 0x0;
            _0x90ed46 = 0x0;
            for (var _0x4fe42c = 0x0; _0x4fe42c < _0x49a1eb['length']; _0x4fe42c++) {
                _0x2c4f5b = (_0x2c4f5b + 0x1) % 0x100;
                _0x90ed46 = (_0x90ed46 + _0x26a837[_0x2c4f5b]) % 0x100;
                _0x1e184c = _0x26a837[_0x2c4f5b];
                _0x26a837[_0x2c4f5b] = _0x26a837[_0x90ed46];
                _0x26a837[_0x90ed46] = _0x1e184c;
                _0x229955 += String['fromCharCode'](_0x49a1eb['charCodeAt'](_0x4fe42c) ^ _0x26a837[(_0x26a837[_0x2c4f5b] + _0x26a837[_0x90ed46]) % 0x100]);
            }
            return _0x229955;
        };
        $dbsm_0x4638['UYyCMO'] = _0x2ef3c5;
        $dbsm_0x4638['nMtFyB'] = {};
        $dbsm_0x4638['lIzlCZ'] = !![];
    }
    var _0x57b28f = $dbsm_0x4638['nMtFyB'][_0x1e1b14];
    if (_0x57b28f === undefined) {
        if ($dbsm_0x4638['DwWKuR'] === undefined) {
            var _0x9e4186 = function (_0x3712d5) {
                this['kHsRXo'] = _0x3712d5;
                this['nWOEyU'] = [0x1, 0x0, 0x0];
                this['tpblbK'] = function () {
                    return 'newState';
                }
                ;
                this['lAcsth'] = '\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*';
                this['foeeRg'] = '[\x27|\x22].+[\x27|\x22];?\x20*}';
            };
            _0x9e4186['prototype']['RuyyZP'] = function () {
                var _0x20d28 = new RegExp(this['lAcsth'] + this['foeeRg']);
                var _0x5e0e5f = true ? --this['nWOEyU'][0x1] : --this['nWOEyU'][0x0];
                return this['XVTLWU'](_0x5e0e5f);
            };
            _0x9e4186['prototype']['XVTLWU'] = function (_0x3ab8dc) {
                if (!Boolean(~_0x3ab8dc)) {
                    return _0x3ab8dc;
                }
                return this['HxFvMA'](this['kHsRXo']);
            }
            ;
            _0x9e4186['prototype']['HxFvMA'] = function (_0x13037d) {
                for (var _0x3bdd37 = 0x0, _0x49b603 = this['nWOEyU']['length']; _0x3bdd37 < _0x49b603; _0x3bdd37++) {
                    this['nWOEyU']['push'](Math['round'](Math['random']()));
                    _0x49b603 = this['nWOEyU']['length'];
                }
                return _0x13037d(this['nWOEyU'][0x0]);
            }
            ;
            new _0x9e4186($dbsm_0x4638)['RuyyZP']();
            $dbsm_0x4638['DwWKuR'] = !![];
        }
        _0x4638d3 = $dbsm_0x4638['UYyCMO'](_0x4638d3, _0x23b316);
        $dbsm_0x4638['nMtFyB'][_0x1e1b14] = _0x4638d3;
    } else {
        _0x4638d3 = _0x57b28f;
    }
    return _0x4638d3;
};
// 解密函数还原字符串规则
traverse(ast, {
    CallExpression(path) {  // 遍历 CallExpression 节点
        // callee 属性为 Identifier 类型
        // 且 name 属性为 $dbsm_0x4638 解密函数名
        if (types.isIdentifier(path.node.callee, {name: '$dbsm_0x4638'})) {
            console.log('遍历到的节点: ', path + '')
            // 取出对应的参数
            // 例: $dbsm_0x4638('\x30\x78\x32\x39', '\x72\x69\x63\x50')
            let callArg = path.node.arguments;  // 例 ['\x30\x78\x32\x39', '\x72\x69\x63\x50']
            let arg1 = callArg[0].type;  // 例 '\x30\x78\x32\x39'
            let arg2 = callArg[1].type;  // 例 '\x72\x69\x63\x50'

            // 将对应的参数取出后, 拿到 $dbsm_0x4638 解密函数执行
            let result = $dbsm_0x4638(callArg[0].value, callArg[1].value)

            // 将对应的节点替换成 解密函数执行后的结果
            // 例
            //    将节点:  $dbsm_0x4638('\x30\x78\x33\x66\x36', '\x68\x32\x25\x5e')
            //    替换成:  "hei"
            path.replaceWith(types.valueToNode(result));
            console.log('替换后的节点: ', path + '')
            console.log('==============================');
        }
    }
})

///

js_code = generator(ast).code  // 将ast节点转换成js代码

// 写入(路径记得改)
fs.writeFileSync('New_demo.js', js_code, {
    encoding: 'utf-8'
})

解析前的代码
在这里插入图片描述
解析后的代码
>

ASCII 编码字符串还原

还原思路在 1. js混淆-源码乱码 中有提到

// ASCII 码还原
traverse(ast, {
    StringLiteral(path) {
        if (path.node.extra) {
            console.log('ASCII码替换前: ', path.node.extra);
            path.node.extra.raw = `'${path.node.extra.rawValue}'`
            console.log('ASCII码替换后: ', path.node.extra);
            console.log('============================================================');
        }
    }
})

效果
在这里插入图片描述

字符串相加

demo.js

'a' + 'b' + 'c' + 'd';
'e' + 'f';

AST.js

// 字符串相加
function strConcat(path) {
    for (let i = 0; i <= 2; i++) {
        let node = path.node
        // left 节点为 StringLiteral 类型
        // right 节点为 StringLiteral 类型
        // operator 操作符属性为字符串 +
        if (types.isStringLiteral(node.left) && types.isStringLiteral(node.right) && node.operator === '+') {
            // 例 'e' + 'f'
            console.log('字符串相加前: ', path + '');

            // 例 'e' + 'f'
            let result = path.node.left.value + path.node.right.value;

            // 例: 'e' + 'f'
            // 替换成: 'ef'
            path.replaceWith(types.valueToNode(result));
            console.log('字符串相加后:  ', path + '');
            console.log('============================================================');
        } else {
            // 递归是针对多个字符串相加的
            // 例当前遍历到的节点: 'a' + 'b' + 'c' + 'd'
            // 这个节点在上面是不会处理的
            // path 对象的 traverse 方法是从当前节点继续遍历
            // 传入 strConcat 方法的节点就为:  'a' + 'b' + 'c' + 'd'
            // 调用过后还是会再次进入到 path.traverse 因为还是会有多个字符串相加
            // 上一次传入的节点被处理过了
            // 所以这一次传入的节点代码就为 'ab' + 'c' + 'd'
            // 一直递归到节点为 'abc' + 'd' 就会停止递归
            // 'abc' + 'd' 在 for 循环中会二次处理 (可以试着for循环只遍历一次看看效果
            path.traverse({
                BinaryExpression(path_) {
                    strConcat(path_)
                }
            })
        }
    }
}

traverse(ast, {
    BinaryExpression(path) {  // 遍历 BinaryExpression 节点
        strConcat(path)
    }
})

效果
在这里插入图片描述

花指令(对象)

demo.js

let obj = {};
obj['StringLiteral'] = 'abc';
obj['BinaryExpression'] = 'abc' + 'def';
obj['funcCallExpression1'] = function (a, b){
    return a(b);
}
obj['funcCallExpression2'] = function (a){
    return a();
}
obj['funcBinaryExpression'] = function(a, b){
    return a + b
}

let c = obj;
let d = c['StringLiteral'];
let e = c['BinaryExpression'];
function demo(){}
let f = c['funcCallExpression1'](demo, '123');
let g = c['funcCallExpression2'](demo);
let h = c['funcBinaryExpression']('1', '2');


AST.js

// 花指令
traverse(ast, {
    VariableDeclarator(path){  // 遍历 VariableDeclarator 节点
        if (types.isObjectExpression(path.node.init)){  // init 类型为 ObjectExpression 类型
            let objName = path.node.id.name;  // 获取对应的标识符
            let objBinding = path.scope.getBinding(objName);  // 获取标识符对应的引用
            let objRefer = objBinding.referencePaths;  // 获取标识符引用对应的数组
            let newObj = {}
            // 将给对象属性赋值的所有变量存入 newObj
            for (const refer in objRefer){  // refer 为索引值从 0 开始
                // objRefer[refer] 为 obj
                // objRefer[refer].parentPath 为 obj['str']
                // objRefer[refer].parentPath.parentPath 为 obj['str'] = 'abc'
                let grandPath = objRefer[refer].parentPath.parentPath;  // 获取该节点的整段代码

                // 该节点的类型为 AssignmentExpression 类型
                // 节点中 left 属性的类型为 MemberExpression 类型
                if (grandPath.isAssignmentExpression() && grandPath.get('left').isMemberExpression()){
                    // obj['str'] 中的 str 字符串
                    let key = grandPath.node.left.property.value;  // 获取 .property.value 的属性,作为新声明对象中的key
                    newObj[key] = grandPath.node.right;  // right为该属性对应的 node 节点,直接存入 newObj 对象即可
                }
            }


            for (const refer in objRefer.reverse()){
                let grandPath = objRefer[refer].parentPath;
                if (grandPath.isVariableDeclarator()){  // 该节点的类型应为 VariableDeclarator
                    // 例: c = obj
                    let identName = grandPath.node.id.name;  // 获取标识符中对应的 name 属性 (例中的 c)

                    // 例:
                    // let d = c['StringLiteral'];
                    // let e = c['BinaryExpression'];
                    // let f = c['funcCallExpression1'](demo, '123');
                    // let g = c['funcCallExpression2'](demo);
                    // let h = c['funcBinaryExpression']('1' + '2');
                    let identBinding = grandPath.scope.getBinding(identName);  // 获取标识符 c 对应的引用

                    // 例:
                    // [c, c, c, c, c]
                    let identRefer = identBinding.referencePaths;  // 获取标识符引用对应的数组

                    // 字符串花指令
                    for (const idenKey in identRefer) {
                        // identRefer[idenKey].parentPath
                        // c['StringLiteral']
                        // c['BinaryExpression']
                        // c['funcCallExpression1']
                        // c['funcCallExpression2']
                        // c['funcBinaryExpression']
                        let key = identRefer[idenKey].parentPath.node.property.value;  // 获取对应的属性值

                        // 获取 newObj[key]  // obj[属性值]
                        // newObj[key] 的属性值为 StringLiteral 或 BinaryExpression 节点
                        // StringLiteral 为字符串 'abc';
                        // BinaryExpression 为二项式 'abc' + 'def';
                        if (types.isStringLiteral(newObj[key]) || types.isBinaryExpression(newObj[key])){  // 还原字符串
                            console.log('花指令字符串替换前: ', identRefer[idenKey].parentPath + '')
                            identRefer[idenKey].parentPath.replaceWith(newObj[key])  // 获取 obj 中对应的 StringLiteral 节点
                            console.log('花指令字符串替换后: ', identRefer[idenKey].parentPath + '')
                            console.log('====================================')
                        }
                    }

                    // 数组翻转,从后向前遍历
                    for (const idenKey in identRefer.reverse()) {
                        // MemberExpression
                        // 为 let d = c['StringLiteral']; 中的 c['StringLiteral']
                        if (identRefer[idenKey].parentPath.isMemberExpression()){
                            // 获取对应调用的属性值 c['StringLiteral'] 中的 'StringLiteral'
                            let key = identRefer[idenKey].parentPath.node.property.value;

                            // 如果 newObj 对应属性值为 FunctionExpression 类型
                            if (types.isFunctionExpression(newObj[key])){
                                /*
                                function (){...}
                                 */

                                // 拿到 return 语句
                                let retState = newObj[key].body.body[0].argument;

                                // 二元运算还原
                                // 例: return a + b
                                if (types.isBinaryExpression(retState)){
                                    let operator = retState.operator;  // 拿到操作符 例: +

                                    // 拿到参数数组
                                    // c['funcBinaryExpression']('1', '2'); 中的 ['1', '2']
                                    let Arg = identRefer[idenKey].parentPath.parentPath.node.arguments;
                                    console.log('花指令二元替换前:  ', identRefer[idenKey].parentPath.parentPath + '')

                                    // replaceWith 将当前的节点替换
                                    // c['funcBinaryExpression']('1', '2');
                                    // 替换成
                                    // '1' + '2'
                                    identRefer[idenKey].parentPath.parentPath.replaceWith(types.binaryExpression(operator, Arg[0], Arg[1]));
                                    console.log('花指令二元替换后:  ', identRefer[idenKey].parentPath.parentPath + '')
                                    console.log('=========================')
                                }

                                // 函数调用还原
                                // 例: return a(b) / return a()
                                // 这两个的差别只有调用的参数,一个对应调用的参数为 2, 一个调用对应的参数为 1
                                // CallExpression
                                // 例: return a(b)
                                if (types.isCallExpression(retState)){
                                    // 获取该节点对应的参数
                                    // 例: c['funcCallExpression1'](demo, '123');
                                    // 中的
                                    // demo, '123'
                                    let Arg = identRefer[idenKey].parentPath.parentPath.node.arguments;
                                    console.log('花指令函数调用替换前:  ', identRefer[idenKey].parentPath.parentPath + '')

                                    // c['funcCallExpression'](demo, '123');
                                    // 替换成
                                    // demo('123');
                                    identRefer[idenKey].parentPath.parentPath.replaceWith(types.callExpression(types.identifier(Arg[0].name), Arg.slice(1)));

                                    console.log('花指令函数调用替换后:  ', identRefer[idenKey].parentPath.parentPath + '')
                                    console.log('=========================')
                                }

                            }
                        }
                    }
                }
            }
            // path.stop()
        }
    }
})

还原前

在这里插入图片描述

还原后

在这里插入图片描述

剔除无用代码

虚假 if

demo.js

if ('a' === 'a'){
    console.log("'a' === 'a' true");
}else{
    console.log("'a' === 'a' false");
}

if ('a' !== 'a'){
    console.log("'a' !== 'a' true");
}else{
    console.log("'a' !== 'a' false");
}

'a' === 'a' ? console.log("'a' === 'a' true") : console.log("'a' === 'a' false")
'a' !== 'a' ? console.log("'a' !== 'a' true") : console.log("'a' !== 'a' false")

AST.js

// 虚假 if
traverse(ast, {
    // IfStatement 为if判断语句
    // ConditionalExpression 为三元表达式
    "IfStatement|ConditionalExpression"(path){
        // 该节点中的判断条件应该为 二元表达式
        // left 节点应该为 StringLiteral 类型
        // right 节点应该为 StringLiteral 类型
        if(path.get('test').isBinaryExpression() && path.get('test.left').isStringLiteral() && path.get('test.right').isStringLiteral()){
            // 取出判断条件中对应的值
            // 例:  if ('a' === 'a') {  console.log("'a' === 'a' true");} else {  console.log("'a' === 'a' false");}

            let operator = path.node.test.operator;  // 取出操作符 例: ===
            let leftString = path.node.test.left.value;  // 左边的字符串 例: 'a'
            let rightString = path.node.test.right.value;  // 右边的字符串 例: === 'a'

            // 生成 eval 可判断的字符串
            let vmRun = `"${leftString}"  ${operator} "${rightString}"`;  // 例: 'a' === 'a'
            let result = eval(vmRun);
            console.log('虚假 if:  ' + (path + '').replaceAll('\n', ''))

            // 取出 if 与 else 中的代码块
            // path.node.consequent.body 为 if(){}else{}; 形式取值
            // path.node.consequent.arguments 为 statement ? true : false; 形式取值
            let ifTrue = path.node.consequent.body || path.node.consequent.arguments;
            let elFalse = path.node.alternate.body || path.node.alternate.arguments;

            // 判断 result 的执行结果,替换对应的代码块 if 或 else
            result ? path.replaceWithMultiple(ifTrue) : path.replaceWithMultiple(elFalse)
        }
    }
})

剔除无引用代码

// 剔除无引用代码
const refObj = {}
traverse(ast, {
    Identifier(path) {
        let name = path.node.name;
        if (!refObj[name]) {
            refObj[name] = '1';
            let binding = path.scope.getBinding(name);
            let refPath = binding && binding.referencePaths;
            if (refPath && refPath.length === 0) {
                path.parentPath.parentPath.isVariableDeclaration() && (console.log('删除的无用代码:  ', path.parentPath + ''), path.parentPath.remove())
            }
        }
    }
})

剔除无引用的对象

// 无引用的对象
traverse(ast, {
    VariableDeclarator(path) {  // 遍历 VariableDeclarator 节点
        if (types.isObjectExpression(path.node.init)) {  // init 类型为 ObjectExpression 类型
            let objName = path.node.id.name;  // 获取对应的标识符
            let objBinding = path.scope.getBinding(objName);  // 获取标识符对应的引用
            let objRefer = objBinding && objBinding.referencePaths;  // 获取标识符引用对应的数组
            let quoteObj = false;
            for (const index in objRefer) {
                let grandPath = objRefer[index].parentPath.parentPath;
                if (grandPath.isAssignmentExpression() && grandPath.get('left').isMemberExpression()) {
                    if (grandPath.get('left.object').isIdentifier() && grandPath.node.left.object.name === objName) {
                        console.log(grandPath + '');
                        console.log('==============================')
                    } else {
                        quoteObj = true
                    }
                }
            }
            if (!quoteObj) {
                for (const index in objRefer) {
                    let grandPath = objRefer[index].parentPath.parentPath;
                    grandPath.remove();
                }
            }

        }
    }
})

数值还原

// 数值还原
traverse(ast, {
    NumericLiteral(path){
        console.log('替换前: ', path.node.extra);
        delete path.node.extra.raw;
        console.log('替换后: ', path.node.extra);
        console.log('==============================');
    }
})

switch 还原

// 还原 switch
traverse(ast, {
    WhileStatement(path){
        if (path.node.test.prefix && path.get('body').isBlockStatement() && types.isSwitchStatement(path.node.body.body[0])){
            // 获取同级节点
            let sibling = path.getSibling(0)
            let whileIdx = (sibling.node.declarations[0].init.callee.object.value).split('|')
            let idxObj = {}
            let caseIdx = path.node.body.body[0].cases;
            for (const index in caseIdx){
                let key = caseIdx[index].test.value;
                idxObj[key] = caseIdx[index].consequent[0];
            }
            let newArray = []
            for (const index in whileIdx){
                newArray.push(idxObj[whileIdx[index]])
            }
            path.replaceWithMultiple(newArray);

            // 删除同级节点
            while(path.key--){
                path.getSibling(path.key).remove();
            }
        }
    }
})

还原前
在这里插入图片描述

还原后
在这里插入图片描述

完整的 AST 代码

代码

// 安装 babel 库:  npm install @babel/core
const fs = require('fs')

const traverse = require('@babel/traverse').default  // 用于遍历 AST 节点
const types = require('@babel/types')  // 用于判断, 生成 AST 节点

const parser = require('@babel/parser')  // 将js代码解析成ast节点
const generator = require('@babel/generator').default  // 将ast节点转换成js代码

// 读取(路径记得改)
const ast_code = fs.readFileSync('demo.js', {
    encoding: 'utf-8'
})

let ast = parser.parse(ast_code)  // 将js代码解析成ast语法树

// 这里插入解析规则
///

// 解密函数中需要的 atob 函数
global['atob'] = require('atob');  // npm install atob
// 解密函数依赖的大数组
var $dbsm_0x23b3 = ["QjjDhA==", "IyQb", "552u776q5L6D", "eCvDoA==", "EHwT", "wpdVw6I=", "RArDvA==", "Hk8D", "MUvCnA==", "wotlw5k=", "w7xTwrU=", "wrLCvT0=", "w5LCvUc=", "w6hIwrY=", "w716Rw==", "L8OzwpI=", "MlMA", "Gm8r", "WcKVw44=", "W8KKw5s=", "w6bCgUE=", "TSnDpg==", "aEXCuw==", "HMOzwrc=", "wqs3Bg==", "KHsW", "AcOtwp4=", "N8KeIA==", "cifCig==", "wrBZw7M=", "AMKtw4g=", "FMOkwqA=", "WwEa", "DjzDqA==", "wo7CnAs=", "wpdoAQ==", "JsOfwp0=", "J8KRKA==", "ZsOCw58=", "wojCiAQ=", "w7vCuMKR", "ATY3", "ZyfCvQ==", "dCJD", "UMKpVg==", "O2US", "wqE3LA==", "SMOtwqk=", "w5PCh8Ki", "bMKyaA==", "S8OjEw==", "AcKGw68=", "wpVFw5M=", "fDvDpw==", "w7Brwqk=", "dGYb", "eC45", "AsOGwrE=", "w7fDhcKz", "YATDlA==", "DsK6w6A=", "wrNLw7U=", "biAN", "TxVF", "VzJ2", "wr3CrRc=", "wr0WEQ==", "YAvDrw==", "wqtZNg==", "K0QC", "Y8KBw6c=", "Q8KEw6E=", "wrUhKQ==", "CXfDjA==", "G34/", "esOcTQ==", "wpFiDA==", "w4xCaQ==", "Blo7", "w6vDvcKT", "eyFl", "BE8K", "w6HCvUs=", "wplqw6M=", "wqdOw5Y=", "wqzDr8KW", "XsKdcw==", "VMKsag==", "ecO9w58=", "EkcB", "wpJIw5U=", "JFrDiA==", "YsO7cg==", "eTvCiA==", "wojCuxc=", "WyXDmw==", "MUrDtg==", "w5XDhcKw", "fMKLcw==", "eMOhw5w=", "EGnCjA==", "RcKTYg==", "OALDvQ==", "HlE/", "Q8KGag==", "wpQpFA==", "wqg5wqw=", "ZsOqw4A=", "wp1Ewpk=", "wpkPwro=", "UT9O", "XsOmw7g=", "CFkm", "W0gI", "P8Ouwrw=", "eEMQ", "L8KSw7k=", "ecOvw4Y=", "WT9O", "J8KYfw==", "BiEH", "w7VnwpM=", "w6dxbg==", "wo/Ci8Os", "wqgpAg==", "wozCm8OB", "clHCjA==", "QsOsw6Y=", "woZew44=", "Zz7DnA==", "RgzDrg==", "XMKAVw==", "SwBb", "VMKCSg==", "Ryp1", "wr9Mw44=", "w4rDqMK7", "UMOiw6E=", "w6fDo1U=", "VMOEw4c=", "EcKew4c=", "c8KRZQ==", "WsOOUQ==", "wodyLA==", "e8KMUg==", "w5TDln0=", "GcKbw4s=", "BMK0w7Y=", "wpIewoU=", "R8Kcw6k=", "wobDuMOi", "BsO/wp4=", "VcOnw6w=", "w5t0wok=", "wqgPwpA=", "woTCu8Or", "fg3DvQ==", "L8KEw6g=", "wphswpI=", "woYgIg==", "AXgq", "VTLCqg==", "wrRww4Q=", "wqM1Ig==", "YCzDjQ==", "EVkx", "PWsV", "JWbDjw==", "DF4M", "WcObw54=", "DMKXw6w=", "EcKmOA==", "WsOJw58=", "ajsY", "SsK1w4Q=", "w4zDqMK0", "Gics", "UTkL", "w754wrA=", "IBw2", "wopkDA==", "NFEb", "EFHDig==", "W8Okw40=", "C8KpVg==", "EmnDsQ==", "VhvDmA==", "wqTCoMOV", "fcOfw6A=", "JsKkNw==", "ecOjKg==", "aSTDsA==", "woYfOg==", "YcOyYA==", "fMOtw4E=", "eMOSw5A=", "w7jCn8KA", "LGI2", "asO0Ow==", "f2cW", "egvDuA==", "GcOeGQ==", "w4NYQw==", "IMKvw68=", "wrfDpsO6", "BcKjJA==", "w6PDu2g=", "ayTDrA==", "B0kt", "QsKTVg==", "wpvCuMO1", "YsOHw6M=", "B1XCuA==", "B8Kjw5w=", "Q8Oqw6g=", "RMOAw4c=", "w4/DssK0", "w4rDm8KQ", "ScOwQg==", "YsOGw5s=", "RjbDjQ==", "SCLDpg==", "VcOVMQ==", "KnHCgQ==", "JMONwrU=", "WcO/Cw==", "YcKuRQ==", "wr0MCw==", "WAHDnw==", "esKuUg==", "wp8mNA==", "MMOAEw==", "bcOBw4w=", "w5LCl8K/", "KXk3", "agpl", "wprChSg=", "w5BmYw==", "S2zCrg==", "BXIv", "EMOUwpA=", "WcKvVg==", "WsKkw4I=", "w69iwqQ=", "e8KYVw==", "Y8Ojw6s=", "KUUk", "LcOYwq0=", "Xj/DvQ==", "RiXDkg==", "wrbDiMOj", "Ujd6", "cAc+", "dzt2", "QsO9w6w=", "Ghg3", "ccKkcA==", "fRvDkA==", "KcK4Og==", "H30u", "PMKyw4Y=", "YyrDtw==", "wpDCiMOh", "wqwowoc=", "wojCjDQ=", "wqHCj8OU", "w7HCm8KR", "XsOVw7Q=", "w47Cp8Kj", "w6LCnMKo", "GsKMbw==", "w5J0wrU=", "RCnDuA==", "wpfCgjE=", "wrMnBw==", "w7bDqsK/", "KEM4", "a8OKwrw=", "wpBlw5Q=", "MTAo", "X8K2w5I=", "WsOvFQ==", "Yz7DkQ==", "W8Ocw54=", "ahtQ", "D2vDrg==", "VsKcw4o=", "Fy/CkQ==", "JnAI", "MMOswrA=", "w4zDt8KI", "wrDCksOj", "GBcc", "fcO9Sg==", "w4HDgXY=", "MsKeHA==", "ccOBw4o=", "QsOgw4M=", "Q8OjBg==", "EMK5FQ==", "R8OCw6o=", "XS9D", "d8KfcA==", "wpbCmSE=", "w4XChn8=", "aMKieA==", "woVhGQ==", "wo7CnsOK", "AXwd", "dCAI", "worDhsOC", "V8Krw4A=", "VxHCvA==", "woFywrg=", "w4ZRaA==", "VMO5w6Q=", "wp1zHg==", "wqw/wqo=", "BMKRw58=", "wpxjw7U=", "McKEw4o=", "YyIF", "fkME", "wp1xw6o=", "Sg80", "HMKbAQ==", "HHoX", "MsK7Cg==", "woZWCw==", "GsOKwrE=", "P8KPGg==", "bBDDhw==", "ewLDng==", "TSMk", "wrbCrT4=", "w7tkRg==", "DDQv", "wrdpLw==", "wonDmsKK", "Tx8o", "WMODw7I=", "MXgT", "w6PCrUw=", "wobCg8OR", "Z8Odw6U=", "w55LwrA=", "O8ORwqU=", "w5vDo10=", "wq3Cl8OT", "asKMUQ==", "woBpPg==", "SnPCrA==", "wo7Dn8KG", "wqVtw54=", "wo9WNA==", "QMObNw==", "TMKAw4Y=", "eHEn", "w5rDqcKk", "wqRlw68=", "CxYO", "WcK2VA==", "wpgrAw==", "wpHCgw4=", "wrHCklU=", "BkIZ", "woh4wqM=", "wpBICg==", "AcORGg==", "wpd0NQ==", "w4HDqsKa", "YcKvew==", "wpvCusOs", "K8K5JA==", "w7LCrGU=", "XkUT", "XMOow6s=", "w7/DqcKj", "NsOdwqQ=", "VcOsw7Q=", "eXED", "McKbdA==", "AHXCow==", "K8KeQg==", "ZgMB", "Hm4g", "f8Oqwow=", "AHPDpA==", "wq4Mwq0=", "WsKeYg==", "fDjCog==", "wpY/PQ==", "V8K9cg==", "OlAN", "esO8Xw==", "GsKaJA==", "WgjDnQ==", "DW7CrA==", "f8K1Qg==", "eSw0", "RAIx", "Cls9", "FMOYwqM=", "w4bCvVE=", "wovDkMKK", "WsK/Tw==", "QRrDgw==", "wpV9w4o=", "wrXCmxA=", "wpXChik=", "wq5kw7g=", "wo5jPA==", "w5VgZQ==", "wr1Cw4o=", "wpBYw60=", "woVOwpw=", "wpB2Cg==", "cBlA", "wo52Cg==", "QcO/w58=", "w65UwrM=", "fyfCng==", "w6TCp2s=", "wrRWJQ==", "w7bCv8KW", "XsKyeQ==", "MWbDiQ==", "w4jDscK1", "d8K1w4U=", "C34+", "wprDt8O9", "VsKlw7E=", "w4JdfQ==", "wos1Jg==", "PE7DuA==", "w4bDnsKM", "w5XDq8KA", "JTIy", "w5LDpMKu", "YArDsQ==", "K8K9IQ==", "DsKmw7E=", "BMKxw7A=", "wrvDncKg", "dzrChQ==", "G1nCjg==", "YEYA", "OsKzJg==", "wrfCugs=", "XlvCkA==", "fcKDw54=", "e8OMw40=", "wpBDw68=", "w45CwoY=", "WsONwpw=", "BFDCiQ==", "w7VidA==", "Aloq", "w73Cq8KT", "IkE4", "wqN0Nw==", "dBLDmw==", "wqlRw44=", "w7lleQ==", "C1TCgQ==", "PsKPJQ==", "VcK0bg==", "XcOBwo4=", "VMOjZQ==", "w7pjXg==", "wrBvFw==", "cARj", "w4JSaQ==", "MsK4w4Y=", "acOeeQ==", "AsOQIQ==", "wqUDBQ==", "X1Zb", "RMKKaA==", "w6fDs8KB", "HsKzdw==", "V8OJLA==", "XMOFwqo=", "V8Kybw==", "w5zDhG4=", "wrFHNQ==", "RcOhw6s=", "w6Vhbg==", "XcOow48=", "w5bCi24=", "NkfDgw==", "AcOyHA==", "XUzClw==", "w5XCgGY=", "w5rDhVA=", "a1c3", "WnzCsw==", "wrvDncK4", "w7pUwqk=", "QT1j", "DmLCuA==", "w69tVA==", "w6bCvMK+", "cVUo", "dcO8wqc=", "cBlK", "w5zDhWc=", "wpt+w6w=", "w6lFwrI=", "wojDiMOS", "XcOZw78=", "UwhO", "wotmw4M=", "RC4Y", "w77CjU0=", "S8O3w6U=", "PGAG", "WsKowq8=", "wqTDmsOo", "Hlo8", "I8OuwqQ=", "c8OAKA==", "cl7Cmw==", "V3PCvA==", "DnM2", "wqQTGQ==", "WWYV", "wozDosOV", "w7fDisKb", "csO+w4A=", "IsKiPw==", "w75iQA==", "Ww7CgA==", "wqtrLA==", "fsKtw6c=", "DsKbw5M=", "w5fDgMKO", "wrcaIQ==", "S1c5", "wrMaOQ==", "AcKIcA==", "Cjww", "w6VWYA==", "OQom", "ZxjDjQ==", "wrMoNw==", "VQXDmA==", "d8KeYQ==", "BEs8", "J0k9", "wpEeEQ==", "wqAHFQ==", "w6/DicKx", "ScOiCg==", "YxXCtg==", "dsOiw4k=", "THjCqQ==", "HMK+AA==", "wpQhHw==", "wr7CvcOq", "K0bDiw==", "eMOAcg==", "w60rdg==", "L1IC", "woNlw60=", "K8KDw4k=", "wrpFDg==", "wpFEMw==", "w6fCrGw=", "wo0mCA==", "cUTCtQ==", "w7LCqMKX", "W8OiwoQ=", "QAvDqQ==", "AD03", "aDfDiQ==", "UTHDpQ==", "ZhMa", "w6bDrMKs", "AkvCuw==", "wo8yBQ==", "wo4IPQ==", "M3QK", "TwrDnw==", "wqFcDw==", "e8O7bA==", "PkHDlg==", "esOBwqk=", "eRFw", "ZyvCnw==", "w7PDtcKx", "wpQ1woA=", "WwFc", "XRsF", "BMOCPQ==", "SHHCjA==", "XcOew5w=", "wqhaKA==", "YynCvg==", "XS3Chg==", "BFI0", "wr9HDA==", "wpx7w5o=", "w6DDmHU=", "bA84", "I3AA", "w7jCn2s=", "BWPClw==", "wpbDt8O1", "wpsKYw==", "wq9jw5I=", "woFQwp4=", "wpI9Mw==", "B8KwEQ==", "DmYq", "CcKbAQ==", "TS49", "w6bDvWU=", "YsOVNw==", "dMKBRQ==", "NXg8", "wrBJwoI=", "KsKAYQ==", "EcKNdQ==", "ecO7OA==", "wrV6w7I=", "WMOSw6Y=", "wqV6wqI=", "VcKyUA==", "fcO4Sg==", "IXQl", "Z8KaXw==", "VnvCnQ==", "wr9qOg==", "w6PDiGs=", "QD0a", "wrzCm8OQ", "w6LCp1w=", "bMK+w6A=", "w7PDn24=", "T2LClg==", "woBJw7c=", "SiPDjQ==", "wqbChTI=", "Wj3Dpg==", "fxgU", "YhzCuA==", "ETsw", "W8OdCA==", "GcOxIg==", "Kxkw", "B2zCuA==", "OBER", "Cl4R", "wrLDpMK8", "wq/CnsOZ", "w5XDv8Kw", "dysc", "Y8KjVQ==", "fcOvw40=", "CWjDug==", "bMObNg==", "ScOEw4c=", "w6RTwqM=", "wpJLEw==", "BTw5", "ScKDw4c=", "XMKbw5o=", "TxjDhw==", "w5pOew==", "wpJawp0=", "ZsKwQQ==", "FGMO", "GMKRw7o=", "QMO+OA==", "wrtaMQ==", "TMOUMA==", "J3jDuA==", "D8OnwqA=", "w7zCgcKv", "VnLCmw==", "Z8OJw4I=", "bADDng==", "ccKCZg==", "wrIUJA==", "XCHDow==", "w6DCsV8=", "ZsKafw==", "w5J7fg==", "M8OMwps=", "w7DDt8KG", "W8OYXw==", "EHDDhw==", "w63ChsKU", "O8Kiw4k=", "wrlxDA==", "wrnCkcON", "wqFfHg==", "wovDsMKh", "w67CmMKk", "w75Pwq8=", "wq/DnMKX", "SyhS", "wp1uOA==", "wr3Dt8KG", "DnI2", "OWEf", "w5PDisKX", "wr3CuRE=", "YBJu", "wrxgw58=", "wrEEIQ==", "Uy53", "V2/CjQ==", "ecOjw6Q=", "SMKjw5s=", "X8O5w7Y=", "RsK3w50=", "wpA+wro=", "aynDjQ==", "ccO5w6E=", "ezjCjw==", "BMOPJQ==", "w7FFwq8=", "QsOnw6Y=", "w5VRQQ==", "HmkA", "f8Oewr0=", "dsO7w78=", "w7PDrcKT", "w4vCr3E=", "X8O6w7s=", "CRTDqQ==", "VcO8w54=", "KmjDrA==", "w4dSfQ==", "BG7DpQ==", "bMOvw54=", "bi5F", "VDjDpQ==", "w6HCiFo=", "aMOYCA==", "w5fDqE8=", "CXbCpg==", "FMKwIg==", "w4BxSQ==", "QTbDow==", "J2si", "MsOxwpI=", "IsOdHA==", "wojDlsKP", "Hn44", "bMOQRg==", "dMKCWg==", "w7rDnF4=", "B8K5w58=", "WSjDpg==", "XsO5w5g=", "QTo7", "wqUZwoM=", "ecK1aA==", "esKDUA==", "woFCwrE=", "woISwos=", "dsODEw==", "McOrOQ==", "JVTDmA==", "XcKxbw==", "wqZZBg==", "OsKjFg==", "UQTDkg==", "woh3w4A=", "w5FXwpM=", "wpJAw7w=", "Ongr", "w41zwos=", "N8OGDw==", "w6DDicKj", "UQ0U", "CsKCTw==", "fTnDhA==", "w6TDqHA=", "AloY", "CV4e", "DsKJbQ==", "LyoG", "OFnChA==", "NFsh", "w596fA==", "w6FsYA==", "Pm/Chg==", "wrZ1Ew==", "wprDmcKo", "C3QW", "wo7CqDM=", "woYANg==", "wq3Dl8Ok", "wp7DlcKp", "csKXeA==", "wqVyHA==", "wptxw6k=", "IMOIwpE=", "HcKkw78=", "XzXDsg==", "Q8KAw48=", "QMOOWg==", "V3TClA==", "woY5Pw==", "K2jCng==", "c8OewoY=", "w5zDqVY=", "Al/Cmg==", "w7TDp8Kg", "wpjCoiU=", "G8ONAA==", "w7rCjMKO", "RSjDsg==", "esODbg==", "EWcq", "NsK4BA==", "PcKeEQ==", "GcOpJw==", "cTpO", "wrzDl8Kv", "CcKSw7I=", "fhPDpw==", "wqcfLg==", "B8KiIQ==", "OcKQw78=", "SjHDug==", "w4vDvcKd", "wq8kGQ==", "HH8J", "DVbDsg==", "LXHDrA==", "WCpe", "N8OjGQ==", "MVrDjA==", "ZB/Dpg==", "w7xvwpE=", "WwjDvA==", "wo4cIQ==", "esOvEw==", "wpJRw7Y=", "TRNg", "wrZ0Ag==", "dcOLcQ==", "bsKAw6E=", "wqdoPg==", "XDrCgg==", "wosKPw==", "bwTDvw==", "XQAy", "wpAUwoU=", "dB4t", "wpFRNw==", "UMKwQQ==", "ecOlw48=", "w6TChMKP", "XxFP", "A8K5Pg==", "w5dbfg==", "woDCtcOn", "IE3Cqg==", "JUvCqg==", "HzYw", "ecKEaA==", "fQEi", "fQR3", "J8KsEQ==", "b8Ofw6U=", "MsK6Jg==", "w7bDsMKT", "wqxuwps=", "XxPCrg==", "JcKQbg==", "FsOtAw==", "RcOBw6U=", "YcOxUg==", "EnAz", "ci8a", "VcO9w6E=", "Qj7Dvg==", "YMKEeQ==", "wqLDiMKl", "w5xawoM=", "TMOow6k=", "eRjDpQ==", "DXjCgQ==", "wq87HA==", "w5jCrMKw", "YsKzVw==", "fcOrwq8=", "wpNxw40=", "BgIo", "YcOEw6Q=", "BsKkw7M=", "L1XDiQ==", "DMKeaQ==", "cT3DmA==", "WDtL", "HVQy", "YTzDow==", "TsOZw5A=", "wpLCnSI=", "Ri8m", "w4fDiU0=", "ah5R", "w4TCuEs=", "w6bDusKY", "dgDDow==", "RAx3", "w71XVg==", "X8Obwoo=", "wrfDi8Kd", "ZsO+w5o=", "cB9B", "BH4p", "USBR", "w4bDksKn", "dSXDmQ==", "YMKew4A=", "V8O9BQ==", "wooxGQ==", "VX/Csg==", "XsOEw6Y=", "wrofBg==", "wpUBBw==", "wq87Gg==", "w4HCo0E=", "wpnCrAw=", "asOGwok=", "wqTChyA=", "wr91KA==", "FsKSLg==", "w5LDrMK5", "UxTDqw==", "JCMb", "IlfDmg==", "a8ONYA==", "IMO/wqM=", "OsOMwoI=", "YnM7", "YcOhcA==", "ZgDDhw==", "fcOnwq8=", "QAJu", "METDqw==", "HMKYRQ==", "IsKBw4g=", "wq9Cw5Y=", "WsOZFw==", "wrZkw60=", "aTAu", "bzgc", "RcOPBw==", "wqhlMQ==", "eMOrw48=", "O8Kjw68=", "STbDjA==", "wqvDgsOf", "G8K0bw==", "DsKdfQ==", "w4HCgWY=", "bgHDvw==", "CXPDlg==", "woFJFQ==", "wqDDlcKF", "QADDtg==", "w7tkSQ==", "Vgo3", "BEUK", "wrN2DA==", "wrHDlcKk", "XMOiEQ==", "wq/CnCU=", "QcKUUw==", "ODRV", "wpJuwpc=", "w67DkXY=", "NMOwwr0=", "VD8w", "KG4V", "acOAwqg=", "LMKWKg==", "wrLDmsK7", "a8K3bw==", "w6nDlMKA", "Y8OJw4s=", "w7xjSQ==", "AMKOdg==", "ay9S", "woFUPg==", "DcKVbA==", "Q8ODw4Y=", "w6JkTw==", "wrx5Hg==", "wr/DhsKl", "wo9QMQ==", "bSXDrg==", "eMOrWA==", "GMKpw78=", "w6fDuns=", "wqnDuMKI", "I1rDug==", "IHsb", "wqJMHw==", "OMOdwoM=", "HW4u", "w6JFQQ==", "wrJHEg==", "wpZcw7U=", "wq1tGw==", "wol2wog=", "w6nCu0s=", "wpLDl8KP", "woPCusOl", "wr7CtMOG", "wofDgsO2", "wprCuys=", "cD7Dhg==", "BWMM", "GMKYPA==", "WMOOw44=", "w4VFXA==", "w7DDmk0=", "F8KDOg==", "wo8jCQ==", "bcKEw44=", "aCkH", "cV0v", "aMO9Dg==", "cMOjw5E=", "CiM0", "Sy0W", "dTPCug==", "FsOuwp4=", "BkAs", "ZnkQ", "w7oxw4I=", "WMOPw4w=", "wqvCvyI=", "SRbDow==", "YinCjQ==", "cz4p", "w6PCqsKV", "VgVq", "BCE2", "w5LDrV4=", "TcO2Jw==", "eyRA", "a8Ouw7o=", "J1jDog==", "QcO5w40=", "FkvDjA==", "GMKpLg==", "ZwTDsg==", "wqzCsMOJ", "YS7ClA==", "w4bCuk0=", "ZMOOIA==", "wo4fwpQ=", "S8K6Vg==", "QcObw6U=", "wq9DHQ==", "IXgZ", "FFwc", "wqhvOA==", "wqBnwrw=", "QsOfJg==", "NW8A", "RRPDow==", "VAIr", "D8Kaw4s=", "X8OcGQ==", "JGEU", "eMKTbg==", "Y8OYbA==", "XcKaRQ==", "FMOrAQ==", "fwjCoA==", "wqnDhMK7", "wqkVwq8=", "P8KUfQ==", "Yh7DpA==", "BAsm", "RMK2w50=", "PcOwKg==", "CcKbw6w=", "HsKWTw==", "eyrDmA==", "woDDi8KC", "A2fDjw==", "YRTDlg==", "UsOow64=", "LCsE", "wo4dOg==", "wphxwpE=", "woUcAA==", "wqMfAA==", "TMKAw4U=", "GsKDw7k=", "PTE8", "wrlPGA==", "wqPDn8OT", "ZcOBw60=", "wrjCuMOq", "W8Kmw5k=", "XMOaw7k=", "wqxzwpM=", "fhDCqg==", "QMO+w7E=", "DVgs", "w6lSwrg=", "VMOHw6g=", "P8Oowrg=", "w7zDqHk=", "wq4CAw==", "wqpTDw==", "bDpH", "QcOYw4M=", "SBkv", "worCicOp", "wo0hGQ==", "w5JgWA==", "YQ5g", "AsK+Xg==", "XMOEwoo=", "ZiAN", "IsKsBQ==", "w6PDpVw=", "wrrCjSY=", "TcK+w6M=", "wp/DkMKL", "fhwQ", "ZHcF", "VDXDqw==", "w7rDg8Kg", "w5pywpc=", "UH3Cqg==", "AMOJwpI=", "wpxwwrU=", "SsONwo0=", "Az8p", "U2fCnA==", "wrLDlcKB", "XSlH", "QcOhKA==", "LG7CnQ==", "w6LDlsKm", "w5hkYQ==", "wqvDi8OU", "wo7CqDE=", "fAvCgQ==", "G8Kzw7A=", "YVAg", "wo/CnSY=", "Dk7CgQ==", "RzzCmw==", "P8OdAA==", "wqFcDQ==", "K8KVSA==", "woVawp8=", "JnEi", "w67DmsKc", "w6JRTw==", "DMK9cA==", "aBhR", "Zi4W", "dhzDvw==", "RsO7wq4=", "ecOcw6E=", "JcOmwqY=", "EcKwVg==", "WsKXeg==", "Byo1", "ElYq", "BloJ", "XMO4Ew==", "wo5+w7g=", "Mkk8", "wqAhJw==", "bjjDuw==", "w7bCpsKR", "Z8O7aw==", "d3fCvw==", "wpbDpcOF", "ScK7w7I=", "CkfDjg==", "ecOafA==", "YMOBw4A=", "wo0dwq4=", "dsKWTQ==", "DcKQZA==", "IEvCpw==", "w7fDulQ=", "aXnCkg==", "woMpJg==", "fWQq", "NnPDkQ==", "USBV", "U2gZ", "RsKBZw==", "e8K/cg==", "WMK5w4s=", "wrFww5I=", "w5PDhHk=", "ZsOxwos=", "wp3DisKX", "w7DCmVg=", "w6x4Rg==", "LH4K", "O20W", "ZMOZw7U=", "PMKfaA==", "bRhn", "Izwv", "w4cfwqU=", "w4fCpG0=", "aBvDoA==", "RMKveA==", "QcOxSg==", "V8K7cw==", "J8KeQg==", "w4LDiX0=", "IsKSUQ==", "VQXDkw==", "LXMp", "IsKgw6w=", "TCU4", "ayl1", "w6TDksK+", "Zn0Q", "AHbDug==", "w7JSwpg=", "G8OpwoM=", "fS1h", "wrxxw4s=", "wogKAw==", "wpYvwqA=", "eWXCkw==", "U8Ofw70=", "e2sT", "woUBAw==", "w6LDjmw=", "a8OPw54=", "U8KHbw==", "HTA7", "wonDs8Kk", "BFQG", "w5PDolU=", "ciXDkA==", "NcOSwrg=", "fCTDow==", "woYuwpQ=", "alQl", "S8Kbw5U=", "woRaw7M=", "E34q", "O8KdJg==", "WAHDng==", "w6DCmnA=", "OkYH", "Y8KWRQ==", "w5VNwpk=", "I0HDpg==", "wrQSJA==", "aQ9P", "HcKBw6g=", "eQnDsA==", "wpAcOw==", "w5HDmsKC", "w5tWwrs=", "ecOcIQ==", "JcKvMA==", "bRh5", "cB0F", "VjTDgA==", "wptrw7s=", "WDnDrw==", "Rz09", "wpYdAA==", "wrpUwpM=", "DcKifg==", "wp/DusKm", "wqAoOg==", "a17Cmw==", "J2k1"];
// 解密函数
var $dbsm_0x4638 = function (_0x1e1b14, _0x23b316) {
    _0x1e1b14 = _0x1e1b14 - 0x0;
    var _0x4638d3 = $dbsm_0x23b3[_0x1e1b14];
    if ($dbsm_0x4638['lIzlCZ'] === undefined) {
        (function () {
            var _0x4b121c;
            try {
                var _0x1d5b59 = Function('return\x20(function()\x20' + '{}.constructor(\x22return\x20this\x22)(\x20)' + ');');
                _0x4b121c = _0x1d5b59();
            } catch (_0x4f5869) {
                _0x4b121c = window;
            }
            var _0x55f54d = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            _0x4b121c['atob'] || (_0x4b121c['atob'] = function (_0x2337bc) {
                    var _0x94736f = String(_0x2337bc)['replace'](/=+$/, '');
                    var _0x5e548f = '';
                    for (var _0x588d26 = 0x0, _0x5d3f20, _0x558d8e, _0x49832a = 0x0; _0x558d8e = _0x94736f['charAt'](_0x49832a++); ~_0x558d8e && (_0x5d3f20 = _0x588d26 % 0x4 ? _0x5d3f20 * 0x40 + _0x558d8e : _0x558d8e,
                    _0x588d26++ % 0x4) ? _0x5e548f += String['fromCharCode'](0xff & _0x5d3f20 >> (-0x2 * _0x588d26 & 0x6)) : 0x0) {
                        _0x558d8e = _0x55f54d['indexOf'](_0x558d8e);
                    }
                    return _0x5e548f;
                }
            );
        }());
        var _0x2ef3c5 = function (_0x49a1eb, _0x27f9fb) {
            var _0x26a837 = [], _0x90ed46 = 0x0, _0x1e184c, _0x229955 = '', _0x28a13b = '';
            _0x49a1eb = atob(_0x49a1eb);
            for (var _0x4237c8 = 0x0, _0x18c69a = _0x49a1eb['length']; _0x4237c8 < _0x18c69a; _0x4237c8++) {
                _0x28a13b += '%' + ('00' + _0x49a1eb['charCodeAt'](_0x4237c8)['toString'](0x10))['slice'](-0x2);
            }
            _0x49a1eb = decodeURIComponent(_0x28a13b);
            var _0x2c4f5b;
            for (_0x2c4f5b = 0x0; _0x2c4f5b < 0x100; _0x2c4f5b++) {
                _0x26a837[_0x2c4f5b] = _0x2c4f5b;
            }
            for (_0x2c4f5b = 0x0; _0x2c4f5b < 0x100; _0x2c4f5b++) {
                _0x90ed46 = (_0x90ed46 + _0x26a837[_0x2c4f5b] + _0x27f9fb['charCodeAt'](_0x2c4f5b % _0x27f9fb['length'])) % 0x100;
                _0x1e184c = _0x26a837[_0x2c4f5b];
                _0x26a837[_0x2c4f5b] = _0x26a837[_0x90ed46];
                _0x26a837[_0x90ed46] = _0x1e184c;
            }
            _0x2c4f5b = 0x0;
            _0x90ed46 = 0x0;
            for (var _0x4fe42c = 0x0; _0x4fe42c < _0x49a1eb['length']; _0x4fe42c++) {
                _0x2c4f5b = (_0x2c4f5b + 0x1) % 0x100;
                _0x90ed46 = (_0x90ed46 + _0x26a837[_0x2c4f5b]) % 0x100;
                _0x1e184c = _0x26a837[_0x2c4f5b];
                _0x26a837[_0x2c4f5b] = _0x26a837[_0x90ed46];
                _0x26a837[_0x90ed46] = _0x1e184c;
                _0x229955 += String['fromCharCode'](_0x49a1eb['charCodeAt'](_0x4fe42c) ^ _0x26a837[(_0x26a837[_0x2c4f5b] + _0x26a837[_0x90ed46]) % 0x100]);
            }
            return _0x229955;
        };
        $dbsm_0x4638['UYyCMO'] = _0x2ef3c5;
        $dbsm_0x4638['nMtFyB'] = {};
        $dbsm_0x4638['lIzlCZ'] = !![];
    }
    var _0x57b28f = $dbsm_0x4638['nMtFyB'][_0x1e1b14];
    if (_0x57b28f === undefined) {
        if ($dbsm_0x4638['DwWKuR'] === undefined) {
            var _0x9e4186 = function (_0x3712d5) {
                this['kHsRXo'] = _0x3712d5;
                this['nWOEyU'] = [0x1, 0x0, 0x0];
                this['tpblbK'] = function () {
                    return 'newState';
                }
                ;
                this['lAcsth'] = '\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*';
                this['foeeRg'] = '[\x27|\x22].+[\x27|\x22];?\x20*}';
            };
            _0x9e4186['prototype']['RuyyZP'] = function () {
                var _0x20d28 = new RegExp(this['lAcsth'] + this['foeeRg']);
                var _0x5e0e5f = true ? --this['nWOEyU'][0x1] : --this['nWOEyU'][0x0];
                return this['XVTLWU'](_0x5e0e5f);
            };
            _0x9e4186['prototype']['XVTLWU'] = function (_0x3ab8dc) {
                if (!Boolean(~_0x3ab8dc)) {
                    return _0x3ab8dc;
                }
                return this['HxFvMA'](this['kHsRXo']);
            }
            ;
            _0x9e4186['prototype']['HxFvMA'] = function (_0x13037d) {
                for (var _0x3bdd37 = 0x0, _0x49b603 = this['nWOEyU']['length']; _0x3bdd37 < _0x49b603; _0x3bdd37++) {
                    this['nWOEyU']['push'](Math['round'](Math['random']()));
                    _0x49b603 = this['nWOEyU']['length'];
                }
                return _0x13037d(this['nWOEyU'][0x0]);
            }
            ;
            new _0x9e4186($dbsm_0x4638)['RuyyZP']();
            $dbsm_0x4638['DwWKuR'] = !![];
        }
        _0x4638d3 = $dbsm_0x4638['UYyCMO'](_0x4638d3, _0x23b316);
        $dbsm_0x4638['nMtFyB'][_0x1e1b14] = _0x4638d3;
    } else {
        _0x4638d3 = _0x57b28f;
    }
    return _0x4638d3;
};
// 解密函数还原字符串规则
traverse(ast, {
    CallExpression(path) {  // 遍历 CallExpression 节点
        // callee 属性为 Identifier 类型
        // 且 name 属性为 $dbsm_0x4638 解密函数名
        if (types.isIdentifier(path.node.callee, {name: '$dbsm_0x4638'})) {

            // 取出对应的参数
            // 例: $dbsm_0x4638('\x30\x78\x32\x39', '\x72\x69\x63\x50')
            let callArg = path.node.arguments;  // 例 ['\x30\x78\x32\x39', '\x72\x69\x63\x50']
            let arg1 = callArg[0].type;  // 例 '\x30\x78\x32\x39'
            let arg2 = callArg[1].type;  // 例 '\x72\x69\x63\x50'

            // 将对应的参数取出后, 拿到 $dbsm_0x4638 解密函数执行
            let result = $dbsm_0x4638(callArg[0].value, callArg[1].value)

            // 将对应的节点替换成 解密函数执行后的结果
            // 例
            //    将节点:  $dbsm_0x4638('\x30\x78\x33\x66\x36', '\x68\x32\x25\x5e')
            //    替换成:  "hei"
            console.log('解密函数执行前的节点: ', path + '')
            path.replaceWith(types.valueToNode(result));
            console.log('解密函数还原后的节点: ', path + '')
            console.log('==============================');
        }
    }
})

// ASCII 码还原
traverse(ast, {
    StringLiteral(path) {
        if (path.node.extra) {
            console.log('ASCII码替换前: ', path.node.extra);
            path.node.extra.raw = `'${path.node.extra.rawValue}'`
            console.log('ASCII码替换后: ', path.node.extra);
            console.log('============================================================');
        }
    }
})


// 字符串相加
function strConcat(path) {
    for (let i = 0; i <= 2; i++) {
        let node = path.node
        // left 节点为 StringLiteral 类型
        // right 节点为 StringLiteral 类型
        // operator 操作符属性为字符串 +
        if (types.isStringLiteral(node.left) && types.isStringLiteral(node.right) && node.operator === '+') {
            // 例 'e' + 'f'
            console.log('字符串相加前: ', path + '');

            // 例 'e' + 'f'
            let result = path.node.left.value + path.node.right.value;

            // 例: 'e' + 'f'
            // 替换成: 'ef'
            path.replaceWith(types.valueToNode(result));
            console.log('字符串相加后:  ', path + '');
            console.log('============================================================');
        } else {
            // 递归是针对多个字符串相加的
            // 例当前遍历到的节点: 'a' + 'b' + 'c' + 'd'
            // 这个节点在上面是不会处理的
            // path 对象的 traverse 方法是从当前节点继续遍历
            // 传入 strConcat 方法的节点就为:  'a' + 'b' + 'c' + 'd'
            // 调用过后还是会再次进入到 path.traverse 因为还是会有多个字符串相加
            // 上一次传入的节点被处理过了
            // 所以这一次传入的节点代码就为 'ab' + 'c' + 'd'
            // 一直递归到节点为 'abc' + 'd' 就会停止递归
            // 'abc' + 'd' 在 for 循环中会二次处理 (可以试着for循环只遍历一次看看效果
            path.traverse({
                BinaryExpression(path_) {
                    strConcat(path_)
                }
            })
        }
    }
}

traverse(ast, {
    BinaryExpression(path) {  // 遍历 BinaryExpression 节点
        strConcat(path)
    }
})


// 花指令
traverse(ast, {
    VariableDeclarator(path){  // 遍历 VariableDeclarator 节点
        if (types.isObjectExpression(path.node.init)){  // init 类型为 ObjectExpression 类型
            let objName = path.node.id.name;  // 获取对应的标识符
            let objBinding = path.scope.getBinding(objName);  // 获取标识符对应的引用
            let objRefer = objBinding.referencePaths;  // 获取标识符引用对应的数组
            let newObj = {}
            // 将给对象属性赋值的所有变量存入 newObj
            for (const refer in objRefer){  // refer 为索引值从 0 开始
                // objRefer[refer] 为 obj
                // objRefer[refer].parentPath 为 obj['str']
                // objRefer[refer].parentPath.parentPath 为 obj['str'] = 'abc'
                let grandPath = objRefer[refer].parentPath.parentPath;  // 获取该节点的整段代码

                // 该节点的类型为 AssignmentExpression 类型
                // 节点中 left 属性的类型为 MemberExpression 类型
                if (grandPath.isAssignmentExpression() && grandPath.get('left').isMemberExpression()){
                    // obj['str'] 中的 str 字符串
                    let key = grandPath.node.left.property.value;  // 获取 .property.value 的属性,作为新声明对象中的key
                    newObj[key] = grandPath.node.right;  // right为该属性对应的 node 节点,直接存入 newObj 对象即可
                }
            }


            for (const refer in objRefer.reverse()){
                let grandPath = objRefer[refer].parentPath;
                if (grandPath.isVariableDeclarator()){  // 该节点的类型应为 VariableDeclarator
                    // 例: c = obj
                    let identName = grandPath.node.id.name;  // 获取标识符中对应的 name 属性 (例中的 c)

                    // 例:
                    // let d = c['StringLiteral'];
                    // let e = c['BinaryExpression'];
                    // let f = c['funcCallExpression1'](demo, '123');
                    // let g = c['funcCallExpression2'](demo);
                    // let h = c['funcBinaryExpression']('1' + '2');
                    let identBinding = grandPath.scope.getBinding(identName);  // 获取标识符 c 对应的引用

                    // 例:
                    // [c, c, c, c, c]
                    let identRefer = identBinding.referencePaths;  // 获取标识符引用对应的数组

                    // 字符串花指令
                    for (const idenKey in identRefer) {
                        // identRefer[idenKey].parentPath
                        // c['StringLiteral']
                        // c['BinaryExpression']
                        // c['funcCallExpression1']
                        // c['funcCallExpression2']
                        // c['funcBinaryExpression']
                        let key = identRefer[idenKey].parentPath.node.property.value;  // 获取对应的属性值

                        // 获取 newObj[key]  // obj[属性值]
                        // newObj[key] 的属性值为 StringLiteral 或 BinaryExpression 节点
                        // StringLiteral 为字符串 'abc';
                        // BinaryExpression 为二项式 'abc' + 'def';
                        if (types.isStringLiteral(newObj[key]) || types.isBinaryExpression(newObj[key])){  // 还原字符串
                            console.log('花指令字符串替换前: ', identRefer[idenKey].parentPath + '')
                            identRefer[idenKey].parentPath.replaceWith(newObj[key])  // 获取 obj 中对应的 StringLiteral 节点
                            console.log('花指令字符串替换后: ', identRefer[idenKey].parentPath + '')
                            console.log('====================================')
                        }
                    }

                    // 数组翻转,从后向前遍历
                    for (const idenKey in identRefer.reverse()) {
                        // MemberExpression
                        // 为 let d = c['StringLiteral']; 中的 c['StringLiteral']
                        if (identRefer[idenKey].parentPath.isMemberExpression()){
                            // 获取对应调用的属性值 c['StringLiteral'] 中的 'StringLiteral'
                            let key = identRefer[idenKey].parentPath.node.property.value;

                            // 如果 newObj 对应属性值为 FunctionExpression 类型
                            if (types.isFunctionExpression(newObj[key])){
                                /*
                                function (){...}
                                 */

                                // 拿到 return 语句
                                let retState = newObj[key].body.body[0].argument;

                                // 二元运算还原
                                // 例: return a + b
                                if (types.isBinaryExpression(retState)){
                                    let operator = retState.operator;  // 拿到操作符 例: +

                                    // 拿到参数数组
                                    // c['funcBinaryExpression']('1', '2'); 中的 ['1', '2']
                                    let Arg = identRefer[idenKey].parentPath.parentPath.node.arguments;
                                    console.log('花指令二元替换前:  ', identRefer[idenKey].parentPath.parentPath + '')

                                    // replaceWith 将当前的节点替换
                                    // c['funcBinaryExpression']('1', '2');
                                    // 替换成
                                    // '1' + '2'
                                    identRefer[idenKey].parentPath.parentPath.replaceWith(types.binaryExpression(operator, Arg[0], Arg[1]));
                                    console.log('花指令二元替换后:  ', identRefer[idenKey].parentPath.parentPath + '')
                                    console.log('=========================')
                                }

                                // 函数调用还原
                                // 例: return a(b) / return a()
                                // 这两个的差别只有调用的参数,一个对应调用的参数为 2, 一个调用对应的参数为 1
                                // CallExpression
                                // 例: return a(b)
                                if (types.isCallExpression(retState)){
                                    // 获取该节点对应的参数
                                    // 例: c['funcCallExpression1'](demo, '123');
                                    // 中的
                                    // demo, '123'
                                    let Arg = identRefer[idenKey].parentPath.parentPath.node.arguments;
                                    console.log('花指令函数调用替换前:  ', identRefer[idenKey].parentPath.parentPath + '')

                                    // c['funcCallExpression'](demo, '123');
                                    // 替换成
                                    // demo('123');
                                    identRefer[idenKey].parentPath.parentPath.replaceWith(types.callExpression(types.identifier(Arg[0].name), Arg.slice(1)));

                                    console.log('花指令函数调用替换后:  ', identRefer[idenKey].parentPath.parentPath + '')
                                    console.log('=========================')
                                }

                            }
                        }
                    }
                }
            }
            // path.stop()
        }
    }
})


// 虚假 if
traverse(ast, {
    // IfStatement 为if判断语句
    // ConditionalExpression 为三元表达式
    "IfStatement|ConditionalExpression"(path){
        // 该节点中的判断条件应该为 二元表达式
        // left 节点应该为 StringLiteral 类型
        // right 节点应该为 StringLiteral 类型
        if(path.get('test').isBinaryExpression() && path.get('test.left').isStringLiteral() && path.get('test.right').isStringLiteral()){
            // 取出判断条件中对应的值
            // 例:  if ('a' === 'a') {  console.log("'a' === 'a' true");} else {  console.log("'a' === 'a' false");}

            let operator = path.node.test.operator;  // 取出操作符 例: ===
            let leftString = path.node.test.left.value;  // 左边的字符串 例: 'a'
            let rightString = path.node.test.right.value;  // 右边的字符串 例: === 'a'

            // 生成 eval 可判断的字符串
            let vmRun = `"${leftString}"  ${operator} "${rightString}"`;  // 例: 'a' === 'a'
            let result = eval(vmRun);
            console.log('虚假 if:  ' + (path + '').replaceAll('\n', ''))

            // 取出 if 与 else 中的代码块
            // path.node.consequent.body 为 if(){}else{}; 形式取值
            // path.node.consequent.arguments 为 statement ? true : false; 形式取值
            let ifTrue = path.node.consequent.body || path.node.consequent.arguments;
            let elFalse = path.node.alternate.body || path.node.alternate.arguments;

            // 判断 result 的执行结果,替换对应的代码块 if 或 else
            result ? path.replaceWithMultiple(ifTrue) : path.replaceWithMultiple(elFalse)
        }
    }
})


// 剔除无引用代码
const refObj = {}
traverse(ast, {
    Identifier(path) {
        let name = path.node.name;
        if (!refObj[name]) {
            refObj[name] = '1';
            let binding = path.scope.getBinding(name);
            let refPath = binding && binding.referencePaths;
            if (refPath && refPath.length === 0) {
                path.parentPath.parentPath.isVariableDeclaration() && (console.log('删除的无用代码:  ', path.parentPath + ''), path.parentPath.remove())
            }
        }
    }
})

// 无引用的对象
traverse(ast, {
    VariableDeclarator(path) {  // 遍历 VariableDeclarator 节点
        if (types.isObjectExpression(path.node.init)) {  // init 类型为 ObjectExpression 类型
            let objName = path.node.id.name;  // 获取对应的标识符
            let objBinding = path.scope.getBinding(objName);  // 获取标识符对应的引用
            let objRefer = objBinding && objBinding.referencePaths;  // 获取标识符引用对应的数组
            let quoteObj = false;
            for (const index in objRefer) {
                let grandPath = objRefer[index].parentPath.parentPath;
                if (grandPath.isAssignmentExpression() && grandPath.get('left').isMemberExpression()) {
                    if (grandPath.get('left.object').isIdentifier() && grandPath.node.left.object.name === objName) {
                        console.log(grandPath + '');
                        console.log('==============================')
                    } else {
                        quoteObj = true
                    }
                }
            }
            if (!quoteObj) {
                for (const index in objRefer) {
                    let grandPath = objRefer[index].parentPath.parentPath;
                    grandPath.remove();
                }
            }

        }
    }
})


// 数值还原
traverse(ast, {
    NumericLiteral(path){
        console.log('替换前: ', path.node.extra);
        delete path.node.extra.raw;
        console.log('替换后: ', path.node.extra);
        console.log('==============================');
    }
})


// 还原 switch
traverse(ast, {
    WhileStatement(path){
        if (path.node.test.prefix && path.get('body').isBlockStatement() && types.isSwitchStatement(path.node.body.body[0])){
            // 获取同级节点
            let sibling = path.getSibling(1)
            let whileIdx = (sibling.node.declarations[0].init.callee.object.value).split('|')
            let idxObj = {}
            let caseIdx = path.node.body.body[0].cases;
            for (const index in caseIdx){
                let key = caseIdx[index].test.value;
                idxObj[key] = caseIdx[index].consequent[0];
            }
            let newArray = []
            for (const index in whileIdx){
                newArray.push(idxObj[whileIdx[index]])
            }
            path.replaceWithMultiple(newArray);

            // 删除同级节点
            while(path.key--){
                console.log('还原switch删除的节点:  ', path.getSibling(path.key) + '');
                path.getSibling(path.key).remove();
            }
        }
    }
})
///

js_code = generator(ast, {
    compact: false,  // 是否压缩,默认 false
}).code  // 将ast节点转换成js代码

// 写入(路径记得改)
fs.writeFileSync('New_demo.js', js_code, {
    encoding: 'utf-8',
})

还原前的代码量 在这里插入图片描述

还原后的代码量在这里插入图片描述

注意

转换好的代码直接放浏览器上会卡死,因为有格式化检测

方法1: 在编译成 js 代码时开启压缩 compact: true

js_code = generator(ast, {
    compact: true,  // 是否压缩,默认 false
}).code  // 将ast节点转换成js代码

方法2: 全局搜索 test,将格式化检测的位置全部改成 true
在这里插入图片描述

AST转换后的代码还是会有debugger
这里是生成 debugger 的位置 $dbsm_0x36da24 函数时生成 debugger 的
在这里插入图片描述
将 debugger 字符串删除即可
在这里插入图片描述

还原加密

将处理好的代码替换到 2.html 文件中
在 document[‘cookie’] 处打上断点
在这里插入图片描述
刷新页面开始调试
在这里插入图片描述
查看上一层堆栈
传进来的 _0x29c654 参数是 Date[“parse”](new Date()); 生成的
在这里插入图片描述
回到加密点 _0x2fdc55() 方法返回空字符串(不用管)
在这里插入图片描述

_0x691b6d() 方法返回的是加密值, 所以只要扣这个方法就可以了
在这里插入图片描述
点击 vm 进入这个方法
在这里插入图片描述
在这里插入图片描述
因为 _0x4a2ede, _0x47e4dd 永远都是undefined,所以 return 可以改写成
return _0x4a2ede ? _0x47e4dd ? _0x42d816(_0x4a2ede, _0x2de515) : y(_0x4a2ede, _0x2de515) : _0x47e4dd ? _0x2985eb(_0x2de515) : _0x396668(_0x2de515);
结果是一样的
在这里插入图片描述
再接着往上 缺啥补啥就可以了

补完运行时会报 qz is not defined(这是一个条件判断)
在这里插入图片描述
浏览器中的 qz 是一个 大数组 是执行 setInterval 后生成的 所以只要将 if 代码块中的代码放出来就可以了
在这里插入图片描述

扣完以后校验一下是否正确即可
在这里插入图片描述

请求代码

python

import requests
import execjs
import time


def call_js(file_name, func_name, *args):
    with open(file_name, mode='r', encoding='utf-8') as f:
        js_code = execjs.compile(f.read())
    return js_code.call(func_name, *args)

headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
}
cookies = {
    "sessionid": "你的sessionid"
}


def get_data(page):
    url = "https://match.yuanrenxue.cn/api/match/2"
    time_ = int(str(int(time.time() * 1000))[:10] + '000')
    cookies['m'] = f"{call_js('2.js', '_0x691b6d', time_)}|{time_}"
    print(cookies)
    params = {
        "page": f'{page}'
    }
    response = requests.get(url, headers=headers, cookies=cookies, params=params)
    print(response.json())


if __name__ == '__main__':
    get_data(1)

javascript

function _0x691b6d(_0x2de515, _0x4a2ede, _0x47e4dd) {
    return _0x396668(_0x2de515);
}

function _0x396668(_0xa25649) {
    return _0xef0b5b(_0x2985eb(_0xa25649));
}

function _0x2985eb(_0x2f966f) {
    return _0x513ef6(_0x130879(_0x2f966f));
}

function _0x130879(_0x1b540c) {
    var _0x553c57 = {};
    return unescape(encodeURIComponent(_0x1b540c));
}

function _0x513ef6(_0x2957b6) {
    var _0x4c198e = {};
    return _0x1fd78f(_0x1e5972(_0x32960f(_0x2957b6), 8 * _0x2957b6["length"]));
}

function _0xef0b5b(_0x10bf06) {
    var _0x2c2190,
        _0x20ca0c,
        _0x18d0e1 = "0123456789abcdef",
        _0xedd57d = '';
    for (_0x20ca0c = 0; _0x20ca0c < _0x10bf06["length"]; _0x20ca0c += 1) _0x2c2190 = _0x10bf06["charCodeAt"](_0x20ca0c), _0xedd57d += _0x18d0e1["charAt"](_0x2c2190 >>> 4 & 15) + _0x18d0e1["charAt"](15 & _0x2c2190);
    return _0xedd57d;
}

function _0x1e5972(_0x132f3d, _0x23ca08) {
    var _0x323bcd = {};
    _0x132f3d[_0x23ca08 >> 5] |= 128 << _0x23ca08 % 32, _0x132f3d[14 + (_0x23ca08 + 64 >>> 9 << 4)] = _0x23ca08;
    var _0x1ee0c6,
        _0x1e8f34,
        _0x429ecb,
        _0x5c3723,
        _0xde6a8e,
        _0x4f8eee = 1732584193,
        _0x12b681 = -271733879,
        _0x34e741 = -1732584194,
        _0x4aa794 = 271733878;
    for (_0x1ee0c6 = 0; _0x1ee0c6 < _0x132f3d["length"]; _0x1ee0c6 += 16) _0x1e8f34 = _0x4f8eee, _0x429ecb = _0x12b681, _0x5c3723 = _0x34e741, _0xde6a8e = _0x4aa794, _0x4f8eee = _0x5655af(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6], 7, -680876936), _0x4aa794 = _0x5655af(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 1], 12, -389564586), _0x34e741 = _0x5655af(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 2], 17, 606105819), _0x12b681 = _0x5655af(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 3], 22, -1044525330), _0x4f8eee = _0x5655af(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 4], 7, -176418897), _0x4aa794 = _0x5655af(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 5], 12, 1200080426), _0x34e741 = _0x5655af(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 6], 17, -1473231341), _0x12b681 = _0x5655af(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 7], 22, -45705983), _0x4f8eee = _0x5655af(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 8], 7, 1770010416), _0x4aa794 = _0x5655af(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 9], 12, -1958414417), _0x34e741 = _0x5655af(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 10], 17, -42063), _0x12b681 = _0x5655af(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 11], 22, -1990404162), _0x4f8eee = _0x5655af(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 12], 7, 1804603682), _0x4aa794 = _0x5655af(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 13], 12, -40341101), _0x34e741 = _0x5655af(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 14], 17, -1502882290), _0x12b681 = _0x5655af(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 15], 22, 1236535329), _0x4f8eee = _0xafe18(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 1], 5, -165796510), _0x4aa794 = _0xafe18(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 6], 9, -1069501632), _0x34e741 = _0xafe18(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 11], 14, 643717713), _0x12b681 = _0xafe18(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6], 20, -373897302), _0x4f8eee = _0xafe18(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 5], 5, -701558691), _0x4aa794 = _0xafe18(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 10], 9, 38016083), _0x34e741 = _0xafe18(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 15], 14, -660478335), _0x12b681 = _0xafe18(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 4], 20, -405537848), _0x4f8eee = _0xafe18(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 9], 5, 568446438), _0x4aa794 = _0xafe18(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 14], 9, -1019803690), _0x34e741 = _0xafe18(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 3], 14, -187363961), _0x12b681 = _0xafe18(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 8], 20, 1163531501), _0x4f8eee = _0xafe18(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 13], 5, -1444681467), _0x4aa794 = _0xafe18(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 2], 9, -51403784), _0x34e741 = _0xafe18(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 7], 14, 1735328473), _0x12b681 = _0xafe18(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 12], 20, -1926607734), _0x4f8eee = _0x57cdb6(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 5], 4, -378558), _0x4aa794 = _0x57cdb6(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 8], 11, -2022574463), _0x34e741 = _0x57cdb6(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 11], 16, 1839030562), _0x12b681 = _0x57cdb6(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 14], 23, -35309556), _0x4f8eee = _0x57cdb6(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 1], 4, -1530992060), _0x4aa794 = _0x57cdb6(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 4], 11, 1272893353), _0x34e741 = _0x57cdb6(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 7], 16, -155497632), _0x12b681 = _0x57cdb6(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 10], 23, -1094730640), _0x4f8eee = _0x57cdb6(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 13], 4, 681279174), _0x4aa794 = _0x57cdb6(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6], 11, -358537222), _0x34e741 = _0x57cdb6(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 3], 16, -722521979), _0x12b681 = _0x57cdb6(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 6], 23, 76029189), _0x4f8eee = _0x57cdb6(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 9], 4, -640364487), _0x4aa794 = _0x57cdb6(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 12], 11, -421815835), _0x34e741 = _0x57cdb6(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 15], 16, 530742520), _0x12b681 = _0x57cdb6(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 2], 23, -995338651), _0x4f8eee = _0x2ba84c(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6], 6, -198630844), _0x4aa794 = _0x2ba84c(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 7], 10, 1126891415), _0x34e741 = _0x2ba84c(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 14], 15, -1416354905), _0x12b681 = _0x2ba84c(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 5], 21, -57434055), _0x4f8eee = _0x2ba84c(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 12], 6, 1700485571), _0x4aa794 = _0x2ba84c(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 3], 10, -1894986606), _0x34e741 = _0x2ba84c(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 10], 15, -1051523), _0x12b681 = _0x2ba84c(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 1], 21, -2054922799), _0x4f8eee = _0x2ba84c(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 8], 6, 1873313359), _0x4aa794 = _0x2ba84c(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 15], 10, -30611744), _0x34e741 = _0x2ba84c(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 6], 15, -1560198380), _0x12b681 = _0x2ba84c(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 13], 21, 1309151649), _0x4f8eee = _0x2ba84c(_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794, _0x132f3d[_0x1ee0c6 + 4], 6, -145523070), _0x4aa794 = _0x2ba84c(_0x4aa794, _0x4f8eee, _0x12b681, _0x34e741, _0x132f3d[_0x1ee0c6 + 11], 10, -1120210379), _0x34e741 = _0x2ba84c(_0x34e741, _0x4aa794, _0x4f8eee, _0x12b681, _0x132f3d[_0x1ee0c6 + 2], 15, 718787259), _0x12b681 = _0x2ba84c(_0x12b681, _0x34e741, _0x4aa794, _0x4f8eee, _0x132f3d[_0x1ee0c6 + 9], 21, -343485441), _0x4f8eee = _0x564a36(_0x4f8eee, _0x1e8f34), _0x12b681 = _0x564a36(_0x12b681, _0x429ecb), _0x34e741 = _0x564a36(_0x34e741, _0x5c3723), _0x4aa794 = _0x564a36(_0x4aa794, _0xde6a8e);
    return [_0x4f8eee, _0x12b681, _0x34e741, _0x4aa794];
}

function _0xafe18(_0x59972b, _0x357d2b, _0x37f1e6, _0x40c0ec, _0x457a54, _0x27a208, _0x1291f9) {
    return _0x93484(_0x357d2b & _0x40c0ec | _0x37f1e6 & ~_0x40c0ec, _0x59972b, _0x357d2b, _0x457a54, _0x27a208, _0x1291f9);
}

function _0x2ba84c(_0x25c369, _0x2fa4cf, _0x10bc95, _0x133659, _0x3e51d8, _0x4a9786, _0x5ad3d9) {
    return _0x93484(_0x10bc95 ^ (_0x2fa4cf | ~_0x133659), _0x25c369, _0x2fa4cf, _0x3e51d8, _0x4a9786, _0x5ad3d9);
}

function _0x57cdb6(_0x24e055, _0x43d7e3, _0x11af5a, _0xde9c8, _0x3f9877, _0x3e6fd3, _0x45d799) {
    return _0x93484(_0x43d7e3 ^ _0x11af5a ^ _0xde9c8, _0x24e055, _0x43d7e3, _0x3f9877, _0x3e6fd3, _0x45d799);
}

function _0x3243aa(_0xdd939c, _0x39e4e0) {
    return _0xdd939c << _0x39e4e0 | _0xdd939c >>> 32 - _0x39e4e0;
}

function _0x564a36(_0x3c4e40, _0x45890c) {
    var _0x1e7f33 = {};
    var _0x474c37 = (65535 & _0x3c4e40) + (65535 & _0x45890c);
    return (_0x3c4e40 >> 16) + (_0x45890c >> 16) + (_0x474c37 >> 16) << 16 | 65535 & _0x474c37;
}

function _0x93484(_0x1f657e, _0x172cfb, _0x14882e, _0x31dde3, _0x16e397, _0x330a90) {
    return _0x564a36(_0x3243aa(_0x564a36(_0x564a36(_0x172cfb, _0x1f657e), _0x564a36(_0x31dde3, _0x330a90)), _0x16e397), _0x14882e);
}

function _0x5655af(_0x5ec922, _0x49f6b4, _0x357fa0, _0x1558be, _0x3b2d74, _0x5bb480, _0x36aa69) {
    return _0x93484(_0x49f6b4 & _0x357fa0 | ~_0x49f6b4 & _0x1558be, _0x5ec922, _0x49f6b4, _0x3b2d74, _0x5bb480, _0x36aa69);
}

function _0x32960f(_0x2752b7) {
    var _0x1e1be5,
        _0x5928bd = [];
    for (_0x5928bd[(_0x2752b7["length"] >> 2) - 1] = void 0, _0x1e1be5 = 0; _0x1e1be5 < _0x5928bd["length"]; _0x1e1be5 += 1) _0x5928bd[_0x1e1be5] = 0;
    var _0x2e5130 = 8 * _0x2752b7["length"];
    for (_0x1e1be5 = 0; _0x1e1be5 < _0x2e5130; _0x1e1be5 += 8) _0x5928bd[_0x1e1be5 >> 5] |= (255 & _0x2752b7["charCodeAt"](_0x1e1be5 / 8)) << _0x1e1be5 % 32;
    return _0x5928bd;
}

function _0x1fd78f(_0x461924) {
    var _0x51955d,
        _0x47ef66 = '',
        _0x264aa7 = 32 * _0x461924["length"];
    for (_0x51955d = 0; _0x51955d < _0x264aa7; _0x51955d += 8) _0x47ef66 += String["fromCharCode"](_0x461924[_0x51955d >> 5] >>> _0x51955d % 32 & 255);
    return _0x47ef66;
}

// console.log(_0x691b6d(1723380724000));
// '75bcb82b08198abbec49a4248c6aae02|1723380724000'
;