xxjoy 2019-06-30
对某网站加密混淆后的javascript代码也算分析了一段时间了,虽然还没搞出来,但多少有些心得,这里记录一下。
在Chrome控制台里试了一下,发现全局变量和函数都保存在window中了
_$xx.call
的,看了一下,其实就是系统方法,比如String.fromCharCode,Array.prototype.slice等因此可以编写一段控制台脚本,遍历window对象中所有形似_$xx的成员,判断其类型和函数执行结果。这样即可将常量字符串映射、系统方法映射等搞出来。在控制台执行下面这段代码就可以把字符串映射表弄到。
(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行全是正面硬怼的……
这里记录一部分已经发现的反破解手法吧。
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返回的插件列表不一样