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返回的插件列表不一样