当前位置: 首页 > news >正文

三层switch转一层switch的处理方法

阿里三层switch转一层switch的处理方法

如下所示的混淆代码,在淘系140、227等滑块的代码经过一些转化后得到。

这些转化包括:

//去自执行避免变量污染
traverse(ast, { UnaryExpression: renameScopIdn })
//去自执行
traverse(ast, { UnaryExpression: movezishixing })
//三目运算转if-else
traverse(ast, { ConditionalExpression: condition2ifelse })//例如a&&console.log(b)  转if-no-else
traverse(ast, { LogicalExpression: Logic2if })//将9==Ai,转成Ai==9,放在左边
traverse(ast, { BinaryExpression: putIdenLeft })// Ai > 9  Ai < 10 转 Ai == x
traverse(ast, { BinaryExpression: ifLeGe2Eq })//从switchCase入口是很有用的
//if嵌套转switch
//if嵌套能转switch的究极原因在于,它是通过一些混淆逻辑得到的代码,肉眼分析就会发现,每个代码块总是对应了条件变量等于某个值时,才会进入
traverse(ast, { SwitchCase: if2switch })

通过上面的转化得到了三层嵌套的switch,这篇我们重点看看这个转化:

 try {for (var li = 16996; void 0 !== li;) {var Ci = 31 & li,fi = li >> 5,mi = 31 & fi,bi = fi >> 5,Ai = 31 & bi;switch (Ci) {case 0:switch (mi) {case 0:switch (Ai) {case 12:N = Se[vo], Q = N[Z](), li = Q ? 11460 : 1475;break;case 5:li = 8804;break;case 2:W = $ % 128, ie = [], M = W + 128, _ = $ - W, W = _ / 128, _ = 127 & W, ie.push(M, _), se = ie, li = 16390;break;case 0:Dn.push(0), li = 11522;break;case 1:L = mo, li = 24641;break;case 3:Oe = K, li = 20257;break;case 4:_ = 0 !== se.length, I = je, li = _ ? 22694 : 16963;break;……………………

通过上面可以看出,在满足

var Ci = 31 & li, fi = li >> 5, mi = 31 & fi, bi = fi >> 5, Ai = 31 & bi

并且 Ci===0 && mi ===0 && Ai ===0

的情况下进入第一个代码块,眼看好像很多变量,实际上都是由li运算得来,因此就是求满足这些约束的条件下的li的值。

然后最终转化为:

switch(li){case x:……………………
}

那么怎么求解嘞?

嘿嘿,下面提供两种思路:

1.穷举

通过for循环,穷举0到999999(一个较大的数)的范围内,看看是否有满足上面条件的li的值

代码示例:

function iter() {here: for (let li = 0; li < 999999; li++) {var Ci = 31 & li,fi = li >> 5,mi = 31 & fi,bi = fi >> 5,Ai = 31 & bi;for (let con1 = 0; con1 < 26; con1++) {for (let con2 = 0; con2 < 26; con2++) {for (let con3 = 0; con3 < 26; con3++) {if (Ci === con1 && mi === con2 && Ai === con3) {//记录下来li和对应代码块的映射关系,后续重建switch即可console.log(con1, con2, con3, "<==>", li)// if (li === 16996) break here}}}}}
}
iter()

输出:

……
21 18 16 <==> 16981
22 18 16 <==> 16982
23 18 16 <==> 16983
24 18 16 <==> 16984
25 18 16 <==> 16985
0 19 16 <==> 16992
1 19 16 <==> 16993
2 19 16 <==> 16994
3 19 16 <==> 16995
4 19 16 <==> 16996
……

可以看到,还是挺快的就得出结果了。

值得注意的是,你会发现为什么我只遍历0到26的范围,这个的话取决于程序三层switch的case的范围有多大,当然你也可以写ast程序去搜集这三个的变化范围


2.约束求解

作者推荐使用这种方式,想到这个是因为作者的毕业设计使用的就是这个技术,如今没想到在js逆向上还能排上用场

我们直接使用z3-solver进行约束求解得到一个满足条件的解即可,穷举些许显得low

如下我们直接使用Z3对收集到的情况进行求解:

import json
from z3 import *
import sysli = BitVec('li', 16)
s = Solver()  # 创建约束求解器
Ci = li & 31
fi = li >> 5
mi = 31 & fi
bi = fi >> 5
Ai = 31 & bidef get_ans(n1, n2, n3):s.add(Ci == n1)  # 添加约束条件s.add(mi == n2)  # 添加约束条件s.add(Ai == n3)  # 添加约束条件if s.check() == sat:  # 检测是否有解# result = s.model()resst = s.model().eval(li).as_string()  # 若有解则得出解,注意这里的解是等式s.reset()return resstelse:print('no result')  # 无解
for n1 in range(26):for n2 in range(26):for n3 in range(26):ans = get_ans(n1, n2, n3)print(n1,n2,n3,"<==>",ans)

总结

两种方式的话,速度我没有进行比较,甚至目前cpu情况下,穷举更快一些,为什么提出第二个方法呢?

实际上我在设想,我们没必要写前面所说那些复杂的ast还原插件,写了费劲巴拉调试了很久,才得到,三层switch嵌套,最后来转一层,如果我们能通过程序分析的策略往深度分支进行探索,一路上不断收集约束集合,直到最深的代码块(没有子分支),此时将收集到的约束进行求解,即可一步到位直接得到li和最终执行代码块的关系,直接就从混淆的代码得到了一层switch

上述方法的难点在于约束收集,纵观基于js写的符号执行引擎,ExpoSE算一个,但是文档稀少,安装编译都成问题,其次这些符号执行引擎都是动态符号执行,需要程序能够运行的情况下设计实现的,但是我们的被混淆的js代码一般都是不能直接运行的,虽然我们可以通过一些操作,比如将最主要的需要还原的代码抠出来,然后将不能执行的代码块暂时替换成能够运行的代码,但是映射关系需要留存好,后续还原用。但是这些为了能够使用动态符号执行思路的前期操作,比起直接写ast插件的方式,工作量也不一定小,所以解混淆嘛!本着简单直接的方式,所以还是目前建议使用ast插件的方式,进行,因为动态符号执行还涉及到代码插装等,写论文的水平了,已经是……

记得加入我们的学习群,更多知识尽在我的知识星球:

我的星球https://t.zsxq.com/125umU2l8

qq群 961566389获取更多资讯

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 大数据基础
  • C++第八章:多态性
  • 完美解决html2canvas + jsPDF导出pdf分页内容截断问题
  • 【产品经理】定价策略
  • DotPlot 的宽高自动设置 | 线性拟合
  • 英语写作中“传统的”traditional conventional 的用法
  • 游戏引擎phaser.js3的使用之玩家和静态物理组碰撞
  • AT_zone2021_d 宇宙人からのメッセージ 题解
  • C语言——构造(结构体)
  • JavaScript 基础(四)
  • CentOS 7 上配置 NFS
  • 安卓应用开发学习:手机摇一摇功能应用尝试--摇骰子和摇红包
  • Qt解析XML
  • 力扣面试经典算法150题:删除有序数组中的重复项 II
  • Java - IDEA开发
  • emacs初体验
  • express + mock 让前后台并行开发
  • golang中接口赋值与方法集
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • JavaScript的使用你知道几种?(上)
  • JavaScript新鲜事·第5期
  • Meteor的表单提交:Form
  • PHP变量
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • SpriteKit 技巧之添加背景图片
  • vue-loader 源码解析系列之 selector
  • 产品三维模型在线预览
  • 电商搜索引擎的架构设计和性能优化
  • 巧用 TypeScript (一)
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • #Linux(make工具和makefile文件以及makefile语法)
  • (2.2w字)前端单元测试之Jest详解篇
  • (动态规划)5. 最长回文子串 java解决
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (四)图像的%2线性拉伸
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转)h264中avc和flv数据的解析
  • (转)使用VMware vSphere标准交换机设置网络连接
  • *算法训练(leetcode)第三十九天 | 115. 不同的子序列、583. 两个字符串的删除操作、72. 编辑距离
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .NET gRPC 和RESTful简单对比
  • .Net OpenCVSharp生成灰度图和二值图
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .NET 材料检测系统崩溃分析
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET/C#⾯试题汇总系列:⾯向对象
  • /etc/fstab和/etc/mtab的区别
  • @EnableAsync和@Async开始异步任务支持
  • [ 2222 ]http://e.eqxiu.com/s/wJMf15Ku
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell
  • [20170705]diff比较执行结果的内容.txt