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

news/2024/10/22 18:42:46/

第二篇

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

接下来的代码行数以解密后的 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 语法树,破解这玩意真的贼容易。

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


http://www.ppmy.cn/news/665231.html

相关文章

Python 入坑之路软件安装(二)

Python 学习(二) Python 开发环境配置 安装 requests 请求库,windows使用管理员打开cmd命令窗口,执行命令 C:\WINDOWS\system32>pip3 install requests Collecting requestsUsing cached https://files.pythonhosted.org/packages/f1/ca/10332a30c…

车载电子瞬态浪涌保护用瞬态抑制TVS二极管,如何正确选型?

“多功能化”、“小型化”、“高密度化”等成为了当今半导体器件的代表关键词,尤其是在汽车电子控制系统应用中,表现地淋漓尽致。众所知周,汽车电子系统中的半导体器件极其容易受到多种瞬态浪涌的干扰、威胁。为此,汽车电子瞬态浪…

发那科数据服务器文件名,FANUC传输参数设置

1 FANUC系统传输参数 有关”SETTING”的参数0020 I/O通道:选择输入/输出设备或选择前台的输入/输出设备下列参数可以在”SETTING”画面里输入.[数据类型]字节型[数据范围]0~35 I/O通道:选择输入/输出设备。为了和外部输入/输出设备或主计算机进行数据传输…

HDU 5198 /BC 36A Strange Class

1.判断长度能否除3 2判断每一段内部是否相同 3不同段之间不能相同 #include<iostream> #include<cstdio> #include<cstring> #include<cctype> #include<cmath> #include<vector> #include<queue> #include<map> #include&l…

hp36A/88A注意点

最近好多朋友在对hp36a/88a硒鼓加粉时&#xff0c;都不同程度的出现了打印淡的问题。现对这个问题做如下解释&#xff0c;供大家参考&#xff1a; hp36a/88a硒鼓这两款硒鼓(主要是鼓芯&#xff09;对碳粉是特别挑剔的。市面上大好多的专用粉在加上后打印都发淡&#xff0c; 大家…

Cuvée的新型低压高电流LED驱动器为工业、医疗和娱乐应用提供高达36A的电流

这种独特的即用型驱动器可用于150W的超高功率LED&#xff0c;而无需自己开发。 加州圣何塞--(美国商业资讯)--Cuve Systems宣布推出专为低电压、大电流应用而设计的LVHC系列LED驱动器&#xff0c;常用于娱乐、工业和医疗照明解决方案。该驱动器额定功率150瓦&#xff0c;支持高…

cc36a_demo_c++关系操作符和逻辑操作符_逻辑运算符_txwtech

/* cc36a_demo_c关系操作符和逻辑操作符_逻辑运算符_txwtech 36_CppPrimer_关系操作符和逻辑操作符_逻辑运算符 关系操作符 < ,<,>,>,,! 逻辑操作符 && || ! 特别注意&#xff1a; 短路求值 不能串接关系操作符&#xff0c;0《a<100是错误的 相等测试与…

【精选】DO-218AB封装 SM8S36A - 车规级TVS选型要点

一、车规级TVS主要应用领域有哪些&#xff1f; 车规级TVS瞬态抑制二极管应用范围广&#xff0c;包括行车记录仪、车载导航仪、车载电机控制系统、车载娱乐系统、倒车雷达、车载电源、防盗器、车载加热坐垫、车载按摩座椅、车载MP3播放器等等。随着科技和信息技术的大力发展&am…