业务逻辑非常依赖前端的安全产品,比如极验[1]、顶象-无感验证[2]、瑞数 等都会对前端代码做混淆。其中有一种强度较高的混淆方式,叫"控制流平坦化"。
"控制流平坦化"是将一些顺序执行的代码,变化成阅读难度更大的
while-switch-case
或者for-switch-case
代码。可以见ControlFlow[3]这个项目的例子。
如果能够"反混淆"这种"控制流平坦化"混淆后的代码,就能让代码变得更容易阅读一些。
本文介绍"反控制流平坦化"的思路和实践过程,最终可以反混淆ControlFlow
和https://obfuscator.io/
两个工具的"控制流平坦化"。
反混淆思路:
怎么实现?
分为两步:
* 第一步获取case块的执行顺序
* 第二步根据case块的执行顺序,拼接case块
怎么获取"case块的执行顺序"?
思路是在每个case块中"注入代码",然后在浏览器中执行js代码,执行过程"注入代码"就可以记录执行顺序。我理解这个类似"软件测试"中计算"代码覆盖率"时用到的插桩。
原始代码如下:
while (!![]){
switch (...){
case "0":
...
case "1":
...
}
}
插桩后,代码如下
// 利用"插桩"记录while-switch-case执行顺序
// 集合 = {while id: [case1节点, case2节点,case3节点,case2节点]}
let while_id_stack = [] // 栈
let collection = {}
while (!![]){
while_statement_id = 111
while_id_stack.push(while_statement_id)
collection[while_statement_id] = []
switch (...){
case "0":
case_statement_id = 222
while_id_on_stack_op = while_id_stack[while_id_stack.length-1]
collection[while_id_on_stack_op].push(case_statement_id)
...
case "1":
...
}
while_id_stack.pop()
}
record(collection)
浏览器运行后,集合中就存放有case节点的执行顺序。
上面都是伪代码,具体实现见 hook.js
怎么拼接case块?
伪代码如下:
集合 = {while id: [case1节点, case2节点,case3节点,case2节点]}
函数1:
遍历ast,如果遇到while语句 {
得到当前while id
if while id in 集合:
顺序拼接各个case块内容
用"拼接后的顺序语句"替换"while语句"
从集合中删除 while id记录
}
while 集合中还有元素:
调用 函数1
具体实现见 simple_decode.js
可以将"while-switch-case代码块"变成"顺序执行的代码块"。
比如 PlayWithObfuscator/tests/encoded_js/simple.js 中的混淆后的代码
while (!![]) {
switch (_0xcgcd3c[_0x3922ce++]) {
case "0":
if (_0x33g15b = _0x5153cd.charCodeAt(_0xeea791 += .75), _0x33g15b > 255) throw new t("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
continue;
case "1":
_0xed1fcd = _0xed1fcd << 8 | _0x33g15b;
continue;
}
break;
}
转换成 阅读性更好一些的代码
if (_0x33g15b = _0x5153cd.charCodeAt(_0xeea791 += .75), _0x33g15b > 255) throw new t("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
_0xed1fcd = _0xed1fcd << 8 | _0x33g15b;
目前属于demo阶段,可以对以下工具的"控制流平坦化"做反混淆:
测试结果在 tests目录[4] 看到
JS反混淆-控制流平展(一)[5]
极验: https://www.geetest.com/
[2]顶象-无感验证: https://www.dingxiang-inc.com/docs/detail/captcha
[3]ControlFlow: https://github.com/Tsaiboss/ControlFlow
[4]tests目录: https://github.com/leveryd/PlayWithObfuscator/tree/main/tests
[5]JS反混淆-控制流平展(一): https://blog.csdn.net/a314131070/article/details/106567825?spm=1001.2014.3001.5501