第二篇
 
第四段 去混淆(解密后的代碼,又一段新的歷程)
 
 接下來的代碼行數以解密后的?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 語法樹,破解這玩意真的賊容易。
 
特別是替換對象屬性的那段,很適合,有時間學習下。
                            總結
                            
                                以上是生活随笔為你收集整理的JS 不可逆加密后半部分,去混淆还原代码。的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。