JS 不可逆加密后半部分,去混淆还原代码。

第二篇

第四段 去混淆(解密后的代码,又一段新的历程)

接下来的代码行数以解密后的 jiemi.js 文件为基准

第一段是一个定时器,定时器以 4000ms 的间隔调用一个 _0x10c488 方法,
里面定义了一个 Object,这个方式在后面会多次出现。
即定义一个对象,里面定义几个方法,将参数返回出来。

比如这个,gHwtC 方法里面就是调用参数一,简化后为:

setInterval(function () {
    _0x10c488();
}, 4e3);

往后找一下,定义方法的地方,在第 278 行:
依然定义了一个对象 _0x5d1305 ,然后定义了一个 _0x3e0578 方法,先不管,继续往后找。
一个 try 结构,判断 _0x43c6a1 也就是参数一是否有值,这里调用没有传参,直接走 else 流程。
调用了 _0x5d1305.Nktyo 方法,传递 _0x3e0578 进入。
找到 Nktyo 的定义,只是把参数二放入参数一执行,然后回头看下这个方法 _0x3e0578 怎么去混淆

第一个 if 是判断 _0x5d1305.ExxTQ(typeof _0x53a0e4, _0x5d1305.jgffP) ,找到刚才的定义,分别理解。
只是一个判断参数一是否为字符串而已,现在找到调用这个 对象属性的地方,挨个替换回来,其他的也是一样方法替换。
整个大方法处理完以后,可以把最上面的对象删除了,结果如下:

function _0x10c488(_0x43c6a1) {
    function _0x3e0578(_0x53a0e4) {
        if (typeof _0x53a0e4 === "string") {
            var _0x3d9b38 = function () {
                while (!![]) { }
            };
            return _0x3d9b38();
        } else {
            if ((("" + (_0x53a0e4 / _0x53a0e4))["length"] !== 1) || ((_0x53a0e4 % 20) === 0)) {
                debugger;
            } else {
                debugger;
            }
        }
        _0x3e0578(++_0x53a0e4);
    }
    try {
        if (_0x43c6a1) {
            return _0x3e0578;
        } else {
            _0x3e0578(0);
        }
    } catch (_0x29e1b1) { }
}

可以看到,这个方法是一个反调试,直接删除即可,开头的定时器也可以一并删除了。
回到开头,看第二段代,一个大的 try, 里面定义了一个字符串拆散为数组,并死循环 switch
最终目的其实就是将 switch 里面的代码按照 _0xd94d8c 定义的顺序执行一遍而已,我们直接提取结果出来看下:

// case "2":
var _0x1d8312 = ["domain", "split", "reverse", "join", "search", "hr" + "ef", "random", !0];
// case "0":
var _0x1dd019 = document[_0x1d8312[0]];
// case "4":
var _0x3f8779 = function (_0x2e5797) {
    return _0x2e5797[_0x1d8312[1]]("")[_0x1d8312[2]]()[_0x1d8312[3]]("");
};
// case "3":
var _0x5a0580 = function (_0xc98a64, _0x503b08) {
    var _0x1dda52 = {
        Scjbh: "function *\( *\)",
        odYDy: "\+\+ *(?:_0x(?:[a-f0-9]){4,6}|(?:\b|\d)[a-z0-9]{1,4}(?:\b|\d))",
        oKrUQ: function _0x2206d5(_0x42cced, _0x535344) {
            return _0x42cced(_0x535344);
        },
        ZyHof: "init",
        hoEKc: function _0x1b7042(_0x219f40, _0x2085aa) {
            return _0x219f40 + _0x2085aa;
        },
        DtRMS: "chain",
        ITLzH: "input",
        TMYBP: function _0x4c778b(_0x5c060e, _0x4090f3) {
            return _0x5c060e(_0x4090f3);
        },
        arjnp: function _0xa52a54(_0x57076d) {
            return _0x57076d();
        },
        OcNch: function _0x36a26e(_0x1cc753, _0x475023, _0x5f1b96) {
            return _0x1cc753(_0x475023, _0x5f1b96);
        },
        XRkCn: function _0x2ccfd7(_0x13e206, _0x2235db) {
            return _0x13e206 === _0x2235db;
        },
        yWahq: function _0x425b13(_0x12e926, _0x4f260f) {
            return _0x12e926(_0x4f260f);
        }
    };
    var _0xceb034 = function () {
        var _0x4236ae = !![];
        return function (_0x4e3ff6, _0xc225f7) {
            var _0x3d1152 = _0x4236ae ? function () {
                if (_0xc225f7) {
                    var _0x23d38f = _0xc225f7.apply(_0x4e3ff6, arguments);
                    _0xc225f7 = null;
                    return _0x23d38f;
                }
            } : function () { };
            _0x4236ae = ![];
            return _0x3d1152;
        };
    }();
    (function () {
        _0x1dda52.OcNch(_0xceb034, this, function () {
            var _0x66effa = new RegExp(_0x1dda52.Scjbh);
            var _0x5b9f27 = new RegExp(_0x1dda52.odYDy, "i");
            var _0x2755c6 = _0x1dda52.oKrUQ(_0x10c488, _0x1dda52.ZyHof);
            if (!_0x66effa.test(_0x1dda52.hoEKc(_0x2755c6, _0x1dda52.DtRMS)) || !_0x5b9f27.test(_0x1dda52.hoEKc(_0x2755c6, _0x1dda52.ITLzH))) {
                _0x1dda52.TMYBP(_0x2755c6, "0");
            } else {
                _0x1dda52.arjnp(_0x10c488);
            }
        })();
    })();
    return _0x1dda52.XRkCn(_0x1dda52.yWahq(_0x3f8779, _0xc98a64)[_0x1d8312[4]](_0x503b08), 0);
};
// case "1":
if (!(_0x5a0580(_0x1dd019, "moc.udiab.tset") || _0x5a0580(_0x1dd019, "nc.gnatnait"))) {
    while (_0x1d8312[7]) {
        location[_0x1d8312[5]] = location[_0x1d8312[5]] + "?" + Math[_0x1d8312[6]]();
    }
}

依然又看到 case "3": 部分和上面是同样的计俩,替换之,然后 _0x1d8312 相关对应的数组也替换一下,
替换到 _0x5a0580 时,本来想继续这个的,到一半发现调用了刚才的 _0x10c488 反调试的代码,直接跳过,依然是反调试的混淆。
核心代码,最后一行 return qs_reverse_str(_0xc98a64).search(_0x503b08) === 0; 翻转字符串并搜索。
找到调用参数 "moc.udiab.tset" 并尝试翻转 test.baidu.com, 这是我写的限制域名的,此段代码可以直接删除了。

// case "2":
var _0x1d8312 = ["domain", "split", "reverse", "join", "search", "href", "random", !0];
// case "0":
var qs_domain /*_0x1dd019*/ = document.domain;
// case "4":
var qs_reverse_str /* _0x3f8779 */ = function (qs_str /*_0x2e5797*/) {
    return qs_str.split("").reverse().join("");
};
// case "3":
var _0x5a0580 = function (_0xc98a64, _0x503b08) {
    var _0xceb034 = function () {
        var _0x4236ae = !![];
        return function (_0x4e3ff6, _0xc225f7) {
            var _0x3d1152 = _0x4236ae ? function () {
                if (_0xc225f7) {
                    var _0x23d38f = _0xc225f7.apply(_0x4e3ff6, arguments);
                    _0xc225f7 = null;
                    return _0x23d38f;
                }
            } : function () { };
            _0x4236ae = ![];
            return _0x3d1152;
        };
    }();
    (function () {
        _0xceb034(this, function () {
            var _0x66effa = new RegExp("function *\( *\)");
            var _0x5b9f27 = new RegExp("\+\+ *(?:_0x(?:[a-f0-9]){4,6}|(?:\b|\d)[a-z0-9]{1,4}(?:\b|\d))", "i");
            var _0x2755c6 = _0x10c488("init");
            if (!_0x66effa.test((_0x2755c6 + "chain")) || !_0x5b9f27.test((_0x2755c6 + "input"))) {
                _0x2755c6("0");
            } else {
                _0x10c488();
            }
        })();
    })();
    return qs_reverse_str(_0xc98a64).search(_0x503b08) === 0;
};
// case "1":
if (!(_0x5a0580(qs_domain, "moc.udiab.tset") || _0x5a0580(qs_domain, "nc.gnatnait"))) {
    while (!0) {
        location["href"] = location["href"] + "?" + Math["random"]();
    }
}

然后就剩下一大段的匿名函数,其实这个才是我一开始加密的代码。
依然看到开始定义了对象,和刚才的方法一样,替换之,同时看到了熟悉的 "1|2|0|3|4|5|6" 和死循环 switch
老样子,直接处理掉吧。

这里遇到一个新结构,这个结构折腾了很久,返回了两次对象,最终目的就是为了用参数二进行 apply

var _0x4df744 = function () {
    var _0x10f531 = !![];
    return function (_0x1602b0, _0x1836ce) {
        var _0x183ad8 = _0x10f531 ? function () {
            if (_0x1836ce) {
                var _0x49cae0 = _0x1836ce.apply(_0x1602b0, arguments);
                _0x1836ce = null;
                return _0x49cae0;
            }
        } : function () { };
        _0x10f531 = ![];
        return _0x183ad8;
    };
}();

最终结果为

var _0x4df744 = function (_0x1602b0, _0x1836ce) {
    _0x1836ce.apply(_0x1602b0, arguments);
}

而定义的 _0x4aa006 方法主要目的为覆盖系统的 console

然后 console 对象所有的方法失效,主要目的依然为了反调试。

整段代码又可以删除了,(case "4" 之前的)

最后结果就只剩下这么几行了

(function (_0x503c1c, _0x5cde2d) {
    // case "4":
    _0x503c1c.info = "这是一个一系列js操作。";
    // case "5":
    _0x5cde2d.adinfo = "站长接高级 “JS加密” 和 “JS解密” ,保卫你的 js。";
    // case "6":
    _0x5cde2d.warning = "如果您的JS里嵌套了PHP,JSP标签,等等其他非JavaScript的代码,请提取出来再加密。这个工具不能加密php、jsp等模版内容";
})(window, document);

后面还有一个 不能删除sojson.v5 我想你懂得,我就不说了~~~

这就是解析的全部了,由于这次写的匆忙,过程中随心所欲的删除,就没有留下过程文件。

大家随意理解下就好了...

本文也是我一边查资料一边写的,又发现写 JS 真的要上 AST 语法树,破解这玩意真的贼容易。

特别是替换对象属性的那段,很适合,有时间学习下。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Vue2中实现不可逆加密的功能,你可以使用crypto-js这个第三方库来实现。下面是一个示例的代码: 首先,你需要安装crypto-js依赖。你可以使用npm或cnpm来进行安装,命令如下: npm install crypto-js 或 cnpm install crypto-js 其次,你需要创建一个js文件,并将下面的代码复制到文件中: ```javascript // 导入crypto-js库 import CryptoJS from 'crypto-js' export default { // 加密方法 set(word, keyStr) { keyStr = keyStr || 'abcdef0123456789' // 16位的密钥,自己定义,和下面的密钥要相同 var srcs = CryptoJS.enc.Utf8.parse(word) // 将字符串转换成WordArray,用于加密 var key = CryptoJS.enc.Utf8.parse(keyStr) // 将字符串转换成WordArray,用于加密的密钥 // 使用AES算法进行加密 var encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, // 加密模式为ECB模式 padding: CryptoJS.pad.Pkcs7 // 填充方式为Pkcs7 }) return encrypted.toString() // 将加密后的结果转换为字符串并返回 }, // 解密方法 get(word, keyStr) { keyStr = keyStr || 'abcdef0123456789' // 16位的密钥,自己定义,和上面的密钥要相同 var key = CryptoJS.enc.Utf8.parse(keyStr) // 将字符串转换成WordArray,用于解密 // 使用AES算法进行解密 var decrypt = CryptoJS.AES.decrypt(word, key, { mode: CryptoJS.mode.ECB, // 解密模式为ECB模式 padding: CryptoJS.pad.Pkcs7 // 填充方式为Pkcs7 }) return CryptoJS.enc.Utf8.stringify(decrypt).toString() // 将解密后的结果转换为字符串并返回 } } ``` 最后,你可以在需要使用加密功能的地方调用这些方法。例如: ```javascript import Crypto from 'path/to/crypto.js' // 加密 var encryptedText = Crypto.set('hello', 'myKey') // 解密 var decryptedText = Crypto.get(encryptedText, 'myKey') ``` 这段代码会将"hello"进行加密,并将加密后的结果保存在encryptedText变量中。然后,将encryptedText作为参数传给解密方法,再传入相同的密钥"myKey",即可得到解密后的文本,保存在decryptedText变量中。 希望这个例子对你有帮助。如果你有其他问题,请随时提问。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [vue中使用crypto-js实现加密解密](https://blog.csdn.net/weixin_47424753/article/details/126331686)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值