對某網站加密混淆後的javascript代碼也算分析了一段時間了,雖然還沒搞出來,但多少有些心得,這裏記錄一下。javascript
在Chrome控制檯裏試了一下,發現全局變量和函數都保存在window中了php
_$xx.call
的,看了一下,其實就是系統方法,好比String.fromCharCode,Array.prototype.slice等所以能夠編寫一段控制檯腳本,遍歷window對象中全部形似_$xx的成員,判斷其類型和函數執行結果。這樣便可將常量字符串映射、系統方法映射等搞出來。在控制檯執行下面這段代碼就能夠把字符串映射表弄到。html
(function () { for (var p in window) { if (p.substr(0, 2) !== "_$") continue; if (typeof window[p] !== "function" || window[p].name !== "") continue; try { var s = window[p](); console.log(p + "=" + s) } catch (e) {} } })()
簡單描述一下AST變換算法。用acorn.parse()
搞到AST以後,遞歸掃描每一個節點:前端
_$xx()
變換爲"xxx"
,則涉及到結構變換,要把CallExpression節點修改成Literal節點並添加value屬性astring.generate()
產生還原後的代碼了上面步驟完成後,這代碼至少勉強能看了,別放鬆,後面還有無數的坑……
還原前的代碼只能是讓人一臉懵逼,還原後的代碼則足以讓人咬牙切齒啊,多大仇啊,滿滿登登5000行全是正面硬懟的……
這裏記錄一部分已經發現的反破解手法吧。java
var eI_v1 = window["eval"]("(function() {var a = new Date(); debugger; return new Date() - a > 100;}())"); _$n1 = _$n1 || eI_v1; //這個在上篇文章分析了,在這找到調用來源了。注意,在可讀性還原以前這貨長這樣: var _$pW = _$u9[_$mz()](_$oi()); _$n1 = _$n1 || _$pW;
function __RW_checkNative(rh_p0, rh_p1) { // 函數名我手動改的 try { var rh_v2 = Function["prototype"]["toString"]["apply"](rh_p0); var rh_v3 = new RegExp("{\\s*\\[native code\\]\\s*}"); if (typeof rh_p0 !== "function" || !rh_v3["test"](rh_v2) || rh_p1 != undefined && rh_p0 !== rh_p1) __GL_undefined_$sy = true; } catch (_$r0) {} }
document["addEventListener"]("visibilitychange", _$r0);
var rm_v5 = "_Selenium_IDE_Recorder,_selenium,callSelenium" , rm_v6 = "__driver_evaluate,__webdriver_evaluate,__selenium_evaluate,__fxdriver_evaluate,__driver_unwrapped,__webdriver_unwrapped,__selenium_unwrapped,__fxdriver_unwrapped,__webdriver_script_func,__webdriver_script_fn" , rm_v7 = ["selenium", "webdriver", "driver"]; if (_$un(window, "callPhantom,_phantom")) { ... }
var ec_v4 = window["XMLHttpRequest"]; if (ec_v4) { var ec_v5 = ec_v4["prototype"]; if (ec_v5) { __GL_f_open = ec_v5["open"]; __GL_f_send = ec_v5["send"]; ec_v5["open"] = function () { _$t5(); arguments[1] = _$pK(arguments[1]); return __GL_f_open["apply"](this, arguments); }; } else { ... } }
var hi_v14 = window["navigator"]; for (hi_v11 in hi_v14) { try { hi_v13 = hi_v14["hasOwnProperty"](hi_v11); } catch (_$r0) { hi_v13 = false; } }
{...}
建立的水貨版本,那就露餡了……navigator.languages
- 在headless chrome中是沒有這個字段的navigator.plugins
- 無頭和有頭的chrome返回的插件列表不同