吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10013|回复: 45
收起左侧

[Android 原创] 利用angr去除混淆的优势,不足与实践

  [复制链接]
Rimao 发表于 2021-7-29 11:11
本帖最后由 Rimao 于 2021-7-29 20:15 编辑

前言

随着技术水平的提升,越来越多的apk中的so文件都用上了ollvm来反逆向分析。
这在我们分析的过程中带来了很大的困扰,然而事物是不断发展的,虚假控制流的变体,虚假控制流变种层出不穷。
混淆的技术不断提升,但是反混淆的技术仍然停滞不前。
所以笔者这里对反混淆技术进行了调研,对最流行的angr去混淆技术进行分析与复现,总结了angr去除混淆的可行性与缺陷。
QQ图片20210728214858.png

反混淆思路

目前主流的反混淆思路似乎有以下三种

  • 采用angr等符号/模拟执行引擎来分析控制流去除混淆
  • 采用静态分析引擎,识别混淆静态特征来去除
  • 采用高级的编译优化技术来对混淆代码进行优化
    所以总体上来看,最便捷使用的似乎就是第一种思路。

    angr去除混淆原理

    其实angr最基本的原理并没有想象中的那么高级(当然angr所用的技术综合起来是非常高深的,涉及了各种论文的实现)。
    相比与普通的模拟执行(unicorn引擎),angr使用的是混合执行技术,合并了静态符号执行,和动态具体执行两种技术。
    42e225e74d8fc7434d9a142109e9fe07.png

对于unicorn来说,给一个地址,那么unicorn引擎就会从这个地址开始执行,碰到一个条件跳转则会根据内存或者寄存器的值进行跳转,这个判断是具体的确定的,因此,unicorn只能走jnz的一个分支。
而angr则是在运行的过程中,从给定的一个state(程序状态,程序的寄存器值,内存的不同都可以作为程序状态的不同)开始执行,每个state维护着一个约束条件的集合(比如i<10,i!=0),这里可以去了解一下z3约束引擎。
在angr中的state里有一个solver对象,其中存在保存的约束。

QQ图片20210728221112.png
那么这些约束条件时如何产生的呢,在每一次发生条件跳转时,都会产生一个约束,那么这个条件成立或者不成立都可以作为一个约束。
不管跳转条件成立或者不成立,该约束都会放入state的约束集合,同时会产生两个子state,分别对应着这个条件成立的程序state,不成立的程序state(因为此时的rip不一样,可以区别为不同的程序状态)。
有点类似linux的fork操作,通过收集约束,进行遍历,最终angr理论上可以遍历到程序的所有可能控制流,换句话说,在已有实际输入得到的路径上,对分支路径条件进行取反,就可以让执行走向另外一条路径。
QQ图片20210728215605.jpg

然后angr可以根据这些state的约束条件是否可以满足来判断该程序状态是否成立,或者是否是无法约束。
总的来说,angr就像是多线程版本的unicorn,同时保存了多个程序状态(state),然后根据约束求解引擎,求出对应的路径的约束。
当然笔者也不是专门研究符号执行的,可能理解有些浅显甚至有误,希望读者可以指出。
那么是怎么通过angr来去除混淆的呢,这里讲一讲最基本的两种混淆,一个是控制流平坦化,另一种是虚假控制。

控制流平坦化

b6d9662e5a216ac6e7a976dd8d814a79.png
对于控制流平坦化来说,可以去了解一下基本的概念,比如主分发快,预分发块,真实块,序言块等概念。
其实这些概念都是从反混淆者的角度出发的概念,这里不做混淆原理的赘述。
想要去除这个混淆,就得弄清楚哪些是真实块以及这些真实块的后继是哪些真实块。
真实块的获取在这个例子中其实非常简单,不难发现所有的真实块都会跳转到预分发块处,而预分发块又跳转到主分发块。
那么只需要得到主分发块,然后通过他的前驱的得到预分发块,即可获取所有真实块了。
获取真实块的函数:

QQ图片20210729094633.png
获取程序结构的代码:

QQ图片20210729094719.png
获取到真实块之后就可以开始使用符号执行来去除混淆了,基本的思路就是,我们在每一个真实块上下断点。
每次从一个真实块出发,看看会在哪个断点下断下(这里其实直接判断active的state中有无该真实块),就可以确定该真实块的后继,从而恢复出控制流。
这里时确定符号执行需要确定的一些信息,比如一个真实块是否只有一个后继,不然需要执行两次符号执行来确定两个后继,以及统计call指令避免进入到call的函数里影响去混淆过程。

QQ图片20210729101139.png
之前提到过,angr符号执行是会边执行边收集约束,然后计算约束的可满足性。
由于当真实块有两个后继时,其必然存在一个条件指令,根据条件来决定控制流,所以我们只需要先设定这个条件成立获得一个后继,然后设置这个条件不成立获得一个后继。
这也就是上图中claripy.BVS(1,1)/claripy.BVS(0,1)的用途,分别对应了条件的成立与不成立,这里就出现了两个路径,能够获得两个后继。
QQ图片20210729102316.png
我们不难发现,在这个去除混淆的过程中,我们到底使用上了angr的符号执行的特性么,事实上是没有的。
因为这里相当于只使用到了模拟执行的技术,虽然angr也可以作为模拟执行的引擎。
唯一与angr有关的可能主要就是ITE(if else then)的条件修饰,来达到获取两个后继的目的。
但是这也可以通过unicorn来hook指令,修改flag寄存器来实现获得两个路径对应的基本块。
所以实际上利用angr去除控制流平坦化是完全可行的,且没有缺陷的,只是在获得程序的真实块上还是需要做出一些改变来适应不同的控制流平坦化。
如果有时间,准备用unicorn写一遍(x

虚假控制流

看起来虚假控制流比控制流平坦化简单得多(?

这里我们自己试着使用angr来去除虚假控制流。
既然用上了angr,那就得用上angr符号执行的特点,我们的思路非常粗暴,直接让angr跑下去,跑完angr没有跑到的state所在的基本块,就是虚假的代码。
所以代码如下
QQ图片20210729104250.png
然后我们弄一个idapython脚本来对基本块染下色,看看效果如何。
QQ图片20210729104405.png
发现效果还是不错的
QQ图片20210729104717.png
似乎我们直接就可以拿来用了,似乎是一个完美的去混淆方案?
我们仔细思考一下,真的是这样么,angr是如何确定哪些是真实的,哪些是虚假的呢?

优点

先考虑一下可行性,angr遇到未约束的条件时,会保存下两个state,这样则可以保留下真实的路径
而遇到不可能成立的路径,加入了无解的约束,angr发现是unsat的,即不可满足的,则可以辨别出是虚假控制流。
实现简单。

缺点
  • 第一点 可能会误识别

事实上angr是基于符号执行来遍历程序的所有路径,它是否能遍历所有路径其实取决于其约束求解引擎是否强大,这里采用的是z3
当它能明确发现这个条件是无法满足的时候就不会走向这个路径,我们可以称之为虚假控制流。
但是如果程序本身的逻辑中存在一个条件是非常难以满足的,或者说超出了约束求解引擎的能力,那么则有可能到达不了这个路径,就会被误标记为虚假的控制流,实际中是很少出现的。

  • 第二点 未约束导致路径爆炸

但是还有一个问题,我们不难发现,我们是直接从函数的开头开始执行的,我们并没有对函数的参数进行约束,而且出现函数调用的时候我们也直接返回了未约束的结果。
那么 当这些未被约束的变量影响了循环的轮数会发生什么情况呢。
是的,由于angr不知道这个循环什么时候应该停止,就会出现一直循环的情况,最后路径爆炸,卡死。
QQ图片20210729110731.png
譬如出现如下代码的时候,angr会直接卡死,此时去除混淆就失败了。
有的人可能会说,我们直接限制循环的轮数不久可以了吗,理论上可行,但是如果循环的轮数也影响了后面的if语句。
那么会导致angr无法遍历所有路径,最后导致路径的缺失,误标记为虚假控制流。

结语

我们不难发现angr其实是一个非常强大的工具,但是似乎仍然具有其局限性,在虚假控制流的去除上过于依赖angr特性,也带来了符号执行自身的缺陷。
所以虚假控制流这种混淆还是考虑静态优化来去除吧,控制流平坦化则只要是模拟执行似乎都能很好的去除。
当然有哪位大师傅有更好的想法,欢迎来交流讨论,另外控制流平坦化脚本这里是对腾讯某大佬的去混淆脚本做出的分析。

免费评分

参与人数 21吾爱币 +15 热心值 +18 收起 理由
超无奥义 + 1 + 1 用心讨论,共获提升!
hy8051hy + 1 谢谢@Thanks!
yu100 + 1 + 1 我很赞同!
404undefined + 1 + 1 我很赞同!
5omggx + 1 + 1 用心讨论,共获提升!
yushan8603 + 1 + 1 谢谢@Thanks!
victos + 1 + 1 谢谢@Thanks!
空人空心空回忆 + 1 我很赞同!
光头鸠摩智 + 1 热心回复!
gaosld + 1 + 1 谢谢@Thanks!
zzzbbbccc + 1 用心讨论,共获提升!
qc123 + 1 我很赞同!
zenlsp + 1 我很赞同!
独行风云 + 1 + 1 用心讨论,共获提升!
芽衣 + 1 用心讨论,共获提升!
zhirong + 1 + 1 谢谢@Thanks!
笙若 + 1 + 1 谢谢@Thanks!
cssos15 + 1 我很赞同!
Stubborn6 + 1 用心讨论,共获提升!
呜呜啊哎 + 1 + 1 谢谢@Thanks!
pelephone + 1 + 1 热心回复!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

debugpro 发表于 2021-7-30 16:55
利用IDA microcode进行反混淆:
https://hex-rays.com/blog/hex-rays-microcode-api-vs-obfuscating-compiler/#appendix

对样本0ac399bc541be9ecc4d294fa3545bbf7fac4b0a2d72bce20648abc7754b3df24反混淆:
https://github.com/RolfRolles/HexRaysDeob

对APT10 ANEL反混淆:
https://www.virusbulletin.com/uploads/pdf/conference_slides/2019/VB2019-Haruyama.pdf
https://github.com/carbonblack/HexRaysDeob
Azhan1998 发表于 2021-7-29 11:15
火钳留名,大佬tql,maiyao和无名侠的思路也很强
djxding 发表于 2021-7-29 11:30
来学习一下。

不过,看起来好像很难样。
慢慢琢磨吧。
277782011 发表于 2021-7-29 17:13
纯技术大牛,消化消化
头像被屏蔽
Wits 发表于 2021-7-29 19:27
水平真高,谢谢你的分享
清水常流 发表于 2021-7-29 19:44
这个是什么呀???
bohuixu 发表于 2021-7-29 21:34

来学习一下。看起来不容易的样子。
琢磨下
52guge 发表于 2021-7-29 22:20
有一件反混淆工具吗
头像被屏蔽
Wits 发表于 2021-7-29 23:52
不错  加个鸡腿
Tamluo 发表于 2021-7-30 00:08

楼主很厉害,虽然看不太懂,不过还是支持支持
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-22 12:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表