AST还原技术专题:浅谈去控制流平坦化的思路及方法
【摘要】
一. while-switch结构的控制流
这类平坦化代码很简单,常见于经过obfuscator在线工具混淆后的控制流平坦化。一般代码段不会很长,常见的 switch-case 基本都在10个分支以内,因此是否还原,并不影响阅读。
代码举例:
var _0x42b38e = "5|4|3|1|2|0"["split"]('|'), _0x435210 = 0; ...
一. while-switch结构的控制流
这类平坦化代码很简单,常见于经过obfuscator在线工具混淆后的控制流平坦化。一般代码段不会很长,常见的 switch-case 基本都在10个分支以内,因此是否还原,并不影响阅读。
代码举例:
var _0x42b38e = "5|4|3|1|2|0"["split"]('|'), _0x435210 = 0;
while (true) {
switch (_0x42b38e[_0x435210++]) {
case '0':
_0x352bac[_0x4447b2] = _0x38b230;
continue;
case '1':
_0x38b230["__proto__"] = _0x529196["bind"](_0x529196);
continue;
case '2':
_0x38b230["toString"] = _0x1bd819["toString"]["bind"](_0x1bd819);
continue;
case '3':
var _0x1bd819 = _0x352bac[_0x4447b2] || _0x38b230;
continue;
case '4':
var _0x4447b2 = _0x124cae[_0x31cdb9];
continue;
case '5':
var _0x38b230 = _0x529196["constructor"]['prototype']["bind"](_0x529196);
continue;
}
break;
}
变量_0x42b38e 充当着分发器的角色,_0x435210则是索引,每次索引自增匹配case,从case语句中取相关的代码,直到全部取完。这类代码结构固定,case语句中无更改索引值的代码,因此,取出来的代码顺序是固定的。使用AST编写插件很容易,并能达到一劳永逸的结果。
二. while-if结构的控制流
这种控制流与第一种比较类似,也是在while循环外面直接定义一个分发器(数组元素全部是常量),只不过switch-case语句变成了if-else 结构,还有一点就是索引值(变量_0x435210)可能会在 代码中改变,不再是自增。其实如果仔细观察,这类代码可以直接改写成 switch-case结构。
代码举例:
switch(dispatch++)
{
......
if (dispatch == 5)
{
if (somecode)
{
dispatch += 2;//在这里更改了dispatch的值,干扰了下一条执行的语句,会走向不同的分支
}
......
}
else if (dispatch == 6)
{
......
}
......
}
这类代码其实也很好处理,可以先还原成switch-case结构的代码,再进行处理。
唯一需要注意的是 索引值在代码中可能变化,这时需要考虑代码还原后的样子,可能是 while循环,也可能是 if-else 结构。
三. while-switch-switch...结构的控制流
这类代码其实与上面的代码区别不大,只不过不再有分发器,而是给定 一个初始值,通过这个初始值分别计算出另外多个值来定位 switch-case-switch-case...节点,复杂度增加了。
switch语句嵌套了switch语句,甚至有多重嵌套,看起来确实无从下手。
其实也有技巧,既然代码变复杂了,那就想办法简化它。
对于 while-switch-switch 这种结构,如:
while(dispatch)
{
.....//通过dispath计算出switch中的a和b
switch(a)
{
......
case 11:
switch(b)
{
......
case 11:
{
......
dispatch = 5;
break;
}
......
}
......
}
}
经过分析,所有有用的代码基本都在第二个switch中,当然有些核心代码也可能在第一个switch-case结构中,但是第一个switch大部分都充当了一个继续分发的角色。
如何简化代码,很简单,在此不表。总之,还原前可以做些预处理,不再受垃圾代码的干扰即可。
而对于 while-switch-switch-switch 结构,也可以先简化,再还原,和while-switch-switch 结构没啥区别。
总结:
复杂的代码简单化,也就是我常说的看看能不能转变成熟悉的代码
如何判断什么时候是while循环,什么时候是if-else语句。这个没有什么好的技巧,有时候需要手动还原去找规律找条件。
使用递归语句容易死循环,因此建议使用非递归代码。
备注:所有内容首发于公众号,之后会更新AST反混淆实战、Javascript基础知识、APP逆向、C++、数据结构与算法等等一系列教程,也会更新一些自己的学习心得等,欢迎大家关注。
文章来源: blog.csdn.net,作者:悦来客栈的老板,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq523176585/article/details/115302509
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)