本期目标网站为:
aHR0cHMlM0EvL2R1bi4xNjMuY29tL3RyaWFsL2ppZ3Nhdw==
市面上有许多好用的解混淆的工具,如v神的插件、蔡老板的一键还原等,效果都非常不错。
本文是对易盾加密代码的简单解混淆,主要是对 AST 进行一个初步的学习与了解。
AST 解混淆需要使用到 babel 库,关于babel库的使用可以看官方文档。这里不介绍库的用法,只对解混淆思路做一个简单分析。本案例代码在最下方。
对于易盾这类混淆来说,基本特征都是一样的。在开头或某个地方定义一个大数组,用于存储变量的值,然后定义一个方法,根据传入的参数来从大数组中取值。稍微复杂一点就如易盾一样,还会通过一个自执行函数来对数组进行偏移。所以如果我们需要将大数组进行还原,需要先要对大数组进行偏移,然后通过eval将所有引用了大数组的地方的值计算出来。
本案例中:
大数组变量名为:_0x5ea4
取值方法名为:_0x4139
//大数组取值方法名
const largeArray = ast1.program.body[0].declarations[0].id.name
// _0x4139
得到大数组变量名后再取大数组与偏移代码,观察代码结构,可以发现我们需要的为 body 下的 VariableDeclaration、FunctionDeclaration 与 ExpressionStatement下的第一个 CallExpression。
VariableDeclaration :大数组
FunctionDeclaration :大数组取值方法
CallExpression:大数组偏移代码
拿到这三个结构后我们就可以执行了,这里我们可以直接删除掉 AssignmentExpression 结构,剩余的就是我们要执行的结构。
traverse(ast, {enter(path) {if (pe === 'AssignmentExpression' && pe === 'MemberExpression') {ve()}}
})offsetCode = generator(ast, {compact: true}).code
eval(offsetCode)
console.log(_0x4139(0xb34))
// toString
为了防止误删其他代码,这里多做了一层判断。为了验证代码是否正确执行,可以调用一下大数组取值方法,看看是否能够正确输出结果。(_0x4139 是本案例代码中大数组取值的方法名)
能够正确执行偏移代码后,就可以将所有引用大数组的代码替换成真实的值了。如
var _0x530fea = _0x4139, _0x1bbc44 = {}[_0x530fea(0xb34)]
我们可以直接将它替换为
_0x1bbc44 = {}["toString"]
想要实现这一步,我们首先需要找到哪些地方通过 _0x4139 引用了大数组。并且,有些代码是嵌套调用的,如:
var _0x530fea = _0x4139
var _0xba4eba = _0x530fea
_0xba4eba(0x9d2)
因此,需要找到这条引用链上的所有变量名。
我们通过第一步中取到的大数组取值方法名来进行遍历。
let quoteArray = new Set([largeArray]);
let current = [largeArray];
while (true) {let floor = [];current.forEach(function (valName) {traverse(ast1, {VariableDeclarator(path) {if (de.init != null && pe === "Identifier" && de.init.name === valName) {floor.de.id.ve()}}});})if (floor.length === 0) {break} else {quoteArray = new Set([...quoteArray].concat(floor));current = floor;}
}console.log(quoteArray)
console.log(quoteArray.size)
鉴于博主 JS 方面不是很在行,所以这里逻辑有点混乱,运行速度稍微较慢,因为需要大量的循环与判断。
拿到所有变量名后就可以进行替换了。
traverse(ast1, {CallExpression(path) {if (de.arguments.length === 1 && quoteArray.de.callee.name)) {de.callee.name = placeInline(types.stringLiteral(String())))}}
});
这时候我们可以将处理后的代码保存观察一下,是否符合我们的预期。
const gcode = generator(ast1.program.body[2].pressions[1])fs.writeFileSync("code1.js", de)
除了大数组,我们还会看到一些大对象,这些对象里面声明了许多方法,这些也是可以直接还原的。
原理与大数组一样。
这里只做简单示例,想要完整的还原也需要分析对象的引用关系,添加 try catch 是因为判断条件不够,可以根据代码结构添加一些判断:
let largeObjects = [];
traverse(ast1, {VariableDeclarator(path) {if (de.init != null && pe === "ObjectExpression" && de.init.properties.length >= 1) {try {largeObjects.de.id.name)String())} catch (e) {}}}
})
traverse(ast1, {MemberExpression(path) {if (pe === 'Identifier' && largeObjects.de.object.name) > -1) {try {var path_value = String());placeInline(types.stringLiteral(path_value));} catch (e) {}}}
})
traverse(ast1, {"StringLiteral|NumericLiteral"(path) {de.extra;}
})
traverse(ast1, {IfStatement(path) {if (st.type === "BooleanLiteral") {if (st.value) {de.consequent.body)} else {de.alternate.body)}}}
})
traverse(ast1, {BinaryExpression(path) {let {confident, value} = path.evaluate()if (value !== undefined) {placeInline(types.valueToNode(value))}}
})
易盾的混淆中并未涉及到平坦流,想要了解的可以看看k哥的文章。
AST 能做的还有许多,这里只列举以上的基本操作。
案例代码
本文发布于:2024-01-28 08:22:27,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064013536081.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |