前天打了个 安卓逆向 + JavaScript 逆向组合课 的广告,今天写在原创的东西,以飨读者。
更新了
obfuscator 混淆工具更新了,地址
https://obfuscator.io/
之前的解混淆脚本都失效了,因为解密的字符串函数反复的赋值给其他的变量,所以遍历 CallExpression 表达式时,判断条件就失效了。举个简单的例子,打开 上面的网站,如下配置:
按下上面的 Reset options 按钮后,再勾选 Disable Console Output复选框,再点击 Obfuscator 按钮,它就自动将示例代码进行了混淆,当前我的混淆代码如下:
-
var _0x9892 = ['trace', 'toString', 'Hello\x20World!', 'return\x20(function()\x20', 'log', '__proto__', 'table', 'console', '{}.constructor(\x22return\x20this\x22)(\x20)', 'length', 'apply', 'exception', 'bind', 'error', 'constructor'];
-
(function(_0x4b56d1, _0x4564e9) {
-
var _0x9892e2 = function(_0x17c1cb) {
-
while (--_0x17c1cb) {
-
_0x4b56d1['push'](_0x4b56d1['shift']());
-
}
-
};
-
_0x9892e2(++_0x4564e9);
-
}(_0x9892, 0x1dc));
-
var _0x17c1 = function(_0x4b56d1, _0x4564e9) {
-
_0x4b56d1 = _0x4b56d1 - 0xbf;
-
var _0x9892e2 = _0x9892[_0x4b56d1];
-
return _0x9892e2;
-
};
-
function hi() {
-
var _0x2e11d2 = _0x17c1
-
, _0x1b400d = function() {
-
var _0x56b97f = !![];
-
return function(_0x2f02e6, _0x3da0d9) {
-
var _0x5610cd = _0x56b97f ? function() {
-
var _0x18fd4c = _0x17c1;
-
if (_0x3da0d9) {
-
var _0x154edd = _0x3da0d9[_0x18fd4c(0xcd)](_0x2f02e6, arguments);
-
return _0x3da0d9 = null,
-
_0x154edd;
-
}
-
}
-
: function() {}
-
;
-
return _0x56b97f = ![],
-
_0x5610cd;
-
}
-
;
-
}()
-
, _0x3bc942 = _0x1b400d(this, function() {
-
var _0x1eb17c = _0x17c1, _0x118c6f;
-
try {
-
var _0x2521bf = Function(_0x1eb17c(0xc6) + _0x1eb17c(0xcb) + ');');
-
_0x118c6f = _0x2521bf();
-
} catch (_0x2241e2) {
-
_0x118c6f = window;
-
}
-
var _0x59b918 = _0x118c6f[_0x1eb17c(0xca)] = _0x118c6f[_0x1eb17c(0xca)] || {}
-
, _0x3a8d6f = [_0x1eb17c(0xc7), 'warn', 'info', _0x1eb17c(0xc1), _0x1eb17c(0xbf), _0x1eb17c(0xc9), _0x1eb17c(0xc3)];
-
for (var _0x42b442 = 0x0; _0x42b442 < _0x3a8d6f[_0x1eb17c(0xcc)]; _0x42b442++) {
-
var _0x1b8b7a = _0x1b400d[_0x1eb17c(0xc2)]['prototype'][_0x1eb17c(0xc0)](_0x1b400d)
-
, _0x1d1203 = _0x3a8d6f[_0x42b442]
-
, _0x5a65c9 = _0x59b918[_0x1d1203] || _0x1b8b7a;
-
_0x1b8b7a[_0x1eb17c(0xc8)] = _0x1b400d['bind'](_0x1b400d),
-
_0x1b8b7a[_0x1eb17c(0xc4)] = _0x5a65c9['toString']['bind'](_0x5a65c9),
-
_0x59b918[_0x1d1203] = _0x1b8b7a;
-
}
-
});
-
_0x3bc942(),
-
console[_0x2e11d2(0xc7)](_0x2e11d2(0xc5));
-
}
-
hi();
可以看到,解密字符串的函数是 _0x17c1,之前的版本,这个函数是直接调用的,现在变了,不直接调用了,而是赋值给其他的变量,如图:
如果按照之前的解混淆代码:
-
scope.traverse(scope.block,{
-
"CallExpression"(_path)
-
{
-
if (_path.node.start < end) return;
-
let {callee,arguments} = _path.node;
-
if (!types.isIdentifier(callee,{name:func_name})) return;
-
if (!isElementsLiteral(_path))
-
{
-
can_removed = false;
-
return;
-
}
-
let value = eval(_path.toString());
-
console.log(_path.toString(),"-->",value);
-
_path.replaceWith(types.valueToNode(value));
-
},
-
});
在
if (!types.isIdentifier(callee,{name:func_name})) return;
这行代码,判断就会失效,因为函数名称已经变了。那如何让它不失效呢?
分析
遇事不慌,我们先来分析。可以看到,它每次赋值的语句都是 VariableDeclarator 这种类型的表达式:
-
var _0x2e11d2 = _0x17c1,
-
var _0x18fd4c = _0x17c1;
-
var _0x1eb17c = _0x17c1;
-
........
那是不是可以在 解密函数的作用域(scope)内遍历 VariableDeclarator表达式呢,找到这些语句呢:
-
scope.traverse(scope.block,{
-
VariableDeclarator(_path)
-
{
-
let {id,init} = _path.node;
-
},
-
})
注意,它们还有个共同的特定,就是其 init 节点都是 Identifier类型的节点,而且其name子节点就是 解密函数名,因此可以写出判断:
-
scope.traverse(scope.block,{
-
VariableDeclarator(_path)
-
{
-
let {id,init} = _path.node;
-
if (!types.isIdentifier(init,{name:func_name})) return;
-
},
-
})
那符合条件的节点又该如何处理?当然是调用强大的 rename 函数了。
举个简单的列子,
var _0x2e11d2 = _0x17c1,
将作用域内的所有 _0x2e11d2 变量名,全部重命名为 _0x17c1,那上面那个判断失效的语句不就不会失效了?
代码如下:
-
scope.traverse(scope.block,{
-
VariableDeclarator(_path)
-
{
-
let {id,init} = _path.node;
-
if (!types.isIdentifier(init,{name:func_name})) return;
-
_path.scope.rename(id.name,func_name);
-
},
-
})
替换完成后,会变成:
var _0x17c1= _0x17c1,
这是一个DeadCode,直接删除就好了。
因此完整的代码就是:
-
scope.traverse(scope.block,{
-
VariableDeclarator(_path)
-
{
-
let {id,init} = _path.node;
-
if (!types.isIdentifier(init,{name:func_name})) return;
-
_path.scope.rename(id.name,func_name);
-
_path.remove();
-
},
-
})
其真正核心的代码就一行:
_path.scope.rename(id.name,func_name);
怎么样,是不是超级简单, 几乎没有任何难度,就轻松秒掉了新版ob混淆解密字符串函数重复赋值的问题。
留个疑问,如果赋值的变量又重新赋值了呢,例如:
-
var _0x2e11d2 = _0x17c1;
-
var _0x2e11d3 = _0x2e11d2;
-
var _0x2e11d4 = _0x2e11d3;
-
var _0x2e11d5 = _0x2e11d4;
-
........
多达十多次的反复赋值,上面的脚本会失效吗?为什么?
文章来源: blog.csdn.net,作者:悦来客栈的老板,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq523176585/article/details/110944650