之前我们已经解密到了
let a = 0x1;
alert(a);
(function (_0xc2361a, _0x49f6b2, _0x4c5d49) {
var _0x4bbdd6 = {
PTyWI: "ert",
CFOau: function _0x2e9886(_0x27d2c4, _0x233ed3) {
return _0x27d2c4 !== _0x233ed3;
},
yGZoO: "undefined",
UQhqT: function _0xe650a3(_0x4590a1, _0x160226) {
return _0x4590a1 === _0x160226;
},
TtTMq: "jsjiami.com.v5",
FQggo: function _0x47c22c(_0x2fe61e, _0x50381a) {
return _0x2fe61e + _0x50381a;
},
FTCAn: "删除版本号,js会定期弹窗",
};
_0x4c5d49 = "al";
try {
_0x4c5d49 += _0x4bbdd6["PTyWI"];
_0x49f6b2 = encode_version;
if (
!(
_0x4bbdd6["CFOau"](typeof _0x49f6b2, _0x4bbdd6["yGZoO"]) &&
_0x4bbdd6["UQhqT"](_0x49f6b2, _0x4bbdd6["TtTMq"])
)
) {
_0xc2361a[_0x4c5d49](
_0x4bbdd6["FQggo"]("删除", "版本号,js会定期弹窗,还请支持我们的工作")
);
}
} catch (_0x2d647c) {
_0xc2361a[_0x4c5d49](_0x4bbdd6["FTCAn"]);
}
})(window);
encode_version = "jsjiami.com.v5";
我们接下来来处理花指令
根据观察可以发现其特征都是访问对象.成员的形式,我们先丢Ast里看一下
丢到Ast explorer看一下
可以发现成员.属性是一个MemberExpression结构
object.name是对象名
property.value是属性名
那我们可以假设一下
我们可以遍历MemberExpression对象
如果找到,就根据对象名找到对应的对象,然后查找属性
判断是不是字符串
如果是字符串则直接替换
如果是函数则判断是否只有一行,并且有两个关键词,且有一个操作符
理论建立完毕,实战开始!
我们先替换字符串
首先判断属性是否是一个string字符串,如果是则判断可能是一个对象.属性的花指令
traverse(ast, {
MemberExpression(path) {
let obj_name = path.node.object.name;
let obj_value =
path.node.property.type === "StringLiteral"
? path.node.property.value
: undefined;
if (obj_name && obj_value) {
console.log("obj_name", obj_name, obj_value);
}
},
});
然后找到对象,我们可以判断obj_name && obj_value是否都符合条件
如果符合则开始找对象
通过path.scope.getBinding找
path表示两个节点的链接,而scope表示该属性所在的函数作用域
找到函数作用域后通过getBinding获取该函数作用域绑定的哪个值
if (obj_name && obj_value) {
let obj_binding = path.scope.getBinding(obj_name);
}
那么这句话的代码就是
找到我们所用的path的函数作用域,并找到对应的绑定(Binding)
也就是说我们从一个节点,跳到了这个函数的范围,再找到该函数内对应的绑定字符串
找到的是一个Bingding对象
Identifier表示声明得时候所用的标识符
path表示该ast的path对象
kind表示var还是let等
referenced表示是否被引用
references表示引用的次数
constant表示是否是常量
constantViolations表示有谁修改了这个变量
referencePaths表示有谁引用了这个变量
通过打印我们确定了找到的binding在这里
所以我们可以继续写
找到binding后,遍历他的init的properties,也就是对象里声明的属性
判断有没有与我们MemberExpression的属性相等
如果相等,且该属性的初始化值为String类型,则直接进行替换
if (obj_binding) {
let prop_list = obj_binding.path.node.init.properties;
for (let index = 0; index < prop_list.length; index++) {
let item_prop = prop_list[index];
let prop_name = item_prop?.key?.name;
if (prop_name === obj_value) {
if (item_prop.value.type === "StringLiteral") {
path.replaceInline(item_prop.value);
return;
}
}
}
}
可以看到已经还原了字符串
完整代码
traverse(ast, {
MemberExpression(path) {
let obj_name = path.node.object.name;
let obj_value =
path.node.property.type === "StringLiteral"
? path.node.property.value
: undefined;
if (obj_name && obj_value) {
let obj_binding = path.scope.getBinding(obj_name);
if (obj_binding) {
let prop_list = obj_binding.path.node.init.properties;
for (let index = 0; index < prop_list.length; index++) {
let item_prop = prop_list[index];
let prop_name = item_prop?.key?.name;
if (prop_name === obj_value) {
if (item_prop.value.type === "StringLiteral") {
path.replaceInline(item_prop.value);
return;
}
}
}
}
}
},
});
那我们就搞定了属性的获取
下节课尝试恢复混淆花指令的函数部分!
结语
撒花~