1. 前言 学习安卓逆向差不多也有一段时间了,之前的重心都是打ctf的,大概是疫情开始后差不多重心就转移到了安卓逆向上,因为我发现学弟们打比赛都要比我厉害了,已经不用我操心了。
今天对自己四个多月左右时间的安卓逆向学习进行了一些总结、自我审视以及规划,然后总结完后,想了下不如发个帖子,分享给像我一样的入门者,希望看完后也能学习到很多,就像我一直在论坛中泡着每天都能学到很多一样。
总结的话差不多是想到什么就写上了,没想到的或者不熟悉就等自己先沉淀,以后再总结写一写。
2. 总结 2.1 学习过程 像我的学习过程的话,从大一下学习逆向开始,到大三上学期结束,都是以打 ctf 为主的,我是一起参与小组团队逆向方向的解题,逆向的题型的话像 Windows、Linux、android 都会有涉及到,还是比较杂的,然后我就是在打 ctf 的过程中开始接触 android 逆向的,从大一下到大三上也都是零零碎碎的学习,就是能够在 ctf 中做出了题目就好了,没有太过多深入的探究。
然后是从上学期结束,也就是大三上结束后,今年刚开始的时候,我开始把学习重心从 ctf 上脱离出来,转移到安卓逆向上面了。然后到现在真正专注安卓逆向的时间差不多四个多月的样子。
学习的方法就是首先看书,非虫前辈的那本《Android 软件安全权威指南》给过一遍,把所有的名词都给了解下,盲点都扫一下,然后就是开始大量的看文章,看帖子,复现,然后差不多了就开始自己去实战了,找 app 去分析和逆向。
然后其实收获最大的还是搞实战的时候,因为实战的时候经常会碰到各种问题,尤其是可能会碰到一些莫名其妙的问题,这个时候去解决问题就是比较有意思的一个过程,虽然也很头大。
然后分析过的 app,有的是比较简单,给完整地成功分析了一遍,分析过程中很多时候也不是太顺利,是会被卡到的,然后过了一段时间有了新思路又重新搞成功的。
还有些app就是比较确实比较难,比如企业版的加固,目前的水平分析不了,就先放着了。
像还有些就是有一定难度,但不至于难到没法分析,就会再学到新的知识或者工具后重新回过头来再分析下。
整个过程还是学到了非常多的东西,经验也积累了很多。然后完整分析出来的感觉很有意义的都会发帖子分享出来。
2.2 常用分析工具 在逆向分析的过程中,IDA、JEB、frida、jadx 、Charles还有 MT 管理器几个工具是比较常用的。
Java 层的分析是 JEB、jadx 还有 frida 相互配合着进行静态分析和动态调试以及 hook。
so 层的就是 ida 来分析,静态分析比较困难的就动态调试,大部分时候都会先用 frida hook libart 跑一下,打印一下 RegisterNatives 函数的参数,获得下注册函数的名称还有地址。
还有就是动态调试过程中有时候需要 dump 下来 dex 文件和 so 文件,会使用 idapython 脚本和 idc 脚本。
2.3 frida hook 和脱壳 frida 是我很喜欢的一个工具,大部分时候我不会先选择进行动态调试,而是使用 frida 进行 hook,我使用 frida 在 Java 层的操作比熟练些,在 so 层的操作还没怎么自己尝试过。
frida 在 so 层的操作我主要就是用别人的项目了,比如在 so 文件之前,先使用 frida hook libart 工具来一把梭,可以打印出 so 的名字和函数的偏移地址。
再比如脱壳时候的 dex 整体 dump 操作,我会尝试用 frida-unpack 或者 frida-dexdump 来进行操作。
前者是通过 hook 住 libart.so 库的一些函数来进行对 dex 文件的整体 dump,也就是最常见的脱壳点 openCommon 或者 openMemroy。后者就是通过内存搜索 dump 对 dex 文件进行整体 dump。
在不考虑整体指令抽取的情况,这两个工具是很典型的 dex 文件整体 dump 思路。
然后关于脱壳了解到的还有就是像 Fdex2 采用的思路是对类 java.lang.ClassLoader 的 loadClass 函数进行 hook 获得返回的 Class 对象 cls,再通过 java.lang.Class 类的 getDex 方法和 com.android.dex.Dex 类中的 getBytes 函数完成对内存中的 dex 进行 dump。像这个思路也是能够 frida 很简单的代码能够实现的。
然后就是针对指令抽取壳,指令抽取壳我也是只停留在学习了解的理论知识上,我还没有真正的实战处理过,不过我下面学习的一个计划和重点就是学习对抗指令抽取壳了。
然后这里说下我说下我还不熟悉的东西,也是我下面一段时间重点学习和强化的内容,大的方向就是和安卓系统和它的源码相关的东西,我打算从加固加壳原理的实现,和脱壳机的实现,以及 frdia 对原生层的 hook 作为三个点出发去学习。
然后就是指令抽取壳,art 下的指令抽取壳现在对抗的公开的脱壳机就是 fart 脱壳机,我是在看雪论坛看寒冰大佬的帖子了解的,然后我对它的理解就是通过主动调用来完成抽取的指令的还原修复,就是怎么抽取最后还是要走系统函数流程加载方法然后运行。
前几天看雪一个帖子里面就是没有使用 fart 脱壳机,直接使用 frida 对 libart.so 库中的 LoadMethod()函数进行 hook,然后选择这里作为脱壳点 dump 下来 dex 文件,这时候 dump 下来的 dex 文件中原来的 Java 层中被抽取的方法就是恢复了的,不过恢复的是 app 运行调用的函数,然后我对 fart 脱壳机的理解就是对所有的方法进行主动调用,实现抽取指令的获取然后再修复,看寒冰大佬的帖子知道是 ArmMethod 类中进行了操作。
然后关于 frida 和脱壳机,最让我期待的就是上周在 r0ysue 巨佬大佬的知识星球里面提到的寒冰大佬的新作 frida-fart,就是 frida 实现的 fart 脱壳机,应该不久后就会公开,这样就不用刷机了。刷机我还没有试过,下面对安卓系统和源码的学习计划中,我也会学习下自己修改源码编译然后刷机。
2.4 ELF 文件和 DEX 文件 我对 ELF 文件的学习,首先是对它的结构的了解,ELF 头部——ELF Header、程序头部表——Program Heaer Table,还有节区头部表——Section Header Table,然后就是节区——Section,和段——Segment,用 010Editor 的 elf 模板来学习的话就是十分清晰的,代表哪些信息和相应的地址都是非常清楚的。
然后我觉得对 ELF 的学习最重要的就是理解 Segment 和 Section 是个一体两面的东西,对应着的是两种视图,一个是 Section 的链接视图,另一个就是 Segment 的装载视图。
像 ELF 文件加载到内存中的是按照 Segment 加载的,有着 Load 属性的 Segment 才会被加载内存中,我对这个的深刻认识是在一次分析百度加固过程中需要 dump 解密后的 so 文件并且修复后产生的。
dump 下来内存中的 so 文件拖进 IDA 里面是分析不了的,这个时候就想着去修复它,然后加深了对 ELF 文件的理解。问题出现在内存中 dump 下来的 so 文件只是完整 so 文件中有着 LOAD 属性的 Segment,其他部分是没有的,然后这个修复它的办法就是把原来 so 文件中除了 LOAD 属性 Segment 的部分都添加到 dump 下来的 so 文件中,然后这个时候再用 IDA 分析就是可以的了。
然后关于 ELF 文件还需要理解的就是 .init 了,分析 so 文件首先是看 .init 里面有没有函数首先执行,很多时候这里会进行解密和其他的一些操作,分析完 .init 后就是找 JNI_Onload 函数了。
然后关于 so 文件还有就是混淆的处理,ollvm,花指令,表跳转,反调试,这方面我分析的不是很多,经验也比较少,以后会找些样本进行练习来强化学习。
然后就是对 ELF 文件的逆向中深刻感受到了 C 语言的重要性,同时有时候在查看安卓源码过程中感觉到阅读吃力,也决心要加强对 C 语言的编程能力。
然后是 DEX 文件,我只是开始理论学习时候简单地使用 010Editor 学习了下它的结构,后面再学习就是是接触到指令抽取壳这个东西了,关注的就是 encode_method 这个结构体,里面的 code_item 中有着方法的代码信息,指令抽取就是把这里给抽取了,这样对 dex 文件的整体 dump 就没有作用了。
2.5 Dalvik 虚拟机和 ART 虚拟机的区别 Dalvik 和 ART 虚拟机我了解的其实不是很多,因为我目前阅读源码还是比较吃力的,以及我之前是在计划通过修改源码刷机,在这个过程中来学习 Dalvik 和 art 虚拟机。
目前我了解到的就是,像 Dalvik 虚拟机中,有一道环节是 dexopt,dexopt在 dalvik 虚拟机上的目标是将 dex 文件优化成 odex 文件,可以让虚拟机更加优化的执行。
然后在 ART 虚拟机中,dexopt 将 dex 文件优化成二进制格式的文件,从可以让 ART 虚拟机执行。dexopt 会调用 dex2oat 进行。而 dex2oat 的任务是将原来的dex文件做预先的翻译,从而可以加快APP运行的时间。
然后像有的脱壳思路就是在 dex2oat 寻找脱壳点。
2.6 抓包 抓包我最熟练的是用 Charles 抓包,有时候会配合 Drony 一起抓包,抓 https 和 http 是十分方便的。
app在应用层抓 http 和 https 和代码定位的技巧我比较熟悉些,但是传输层抓 socket 的 tcp/udp 及代码定位就很不熟悉了,后面更是看到 @r0ysue 巨佬分享说到了抓包的最高境界——路由器抓包。
巨佬有篇介绍抓包的文章——实用FRIDA进阶:内存漫游、hook anywhere、抓包,今天才看到,实属罪过,准备仔细钻研吃透。
3. 自我审视 在今天晚上进行了一场对我来说极其有意义的交流,完了后我仔细回想交流中的对话,然后进行了深刻的自我审视,希望能从中不断挖掘出来有益的东西来帮助自己持续前行。
3.1 分类归纳能力 可能我会很多种工具的使用和很多种分析姿势,但是我并没有对这些技术进行本质上的分类归纳和总结。
大道至简,很多复杂不相连的事物背后可能会是一个逻辑。
3.2 深入分析和学习的能力 缺乏此种能力,对我来说可以举个很简单的例子来证明,我这么喜欢用 frida,我有仔细分析背后的原理吗?没有。我有仔细把 @r0ysue 巨佬关于 frida 各种使用的方法和姿势自己实践一遍并且吃透吗?没有。我甚至都没把 @r0ysue 巨佬的所有文章仔仔细细的看一遍。
一个技术点是这样,类推到其他的技术点也会都是差不多的,一言以蔽之,缺乏深入分析和学习的能力。
这并不是好事情,因为某种意义上,这是缺乏好奇心和勇气的体现。
3.3 编程能力 这一点是真实硬伤...
打 ctf 比赛都是一天两天,然后 python 最省事,用的也是最多,但是用的多也仅仅是针对 ctf 的,像 python 开发的很多技术和知识点我都一无所知,其实这个也是第二点种说的缺乏深入学习和分析能力的体现。
然后看过些 Android 开发,Java 编程也学了点皮毛。
C/C++ 就更不用说了...
3.4 表达能力和英语水平 表达能力这个也不多说了,众所周知,能够用简练的语言表达自己的想法和观点是十分难得的长处。
然后英语水平这点可以看今天论坛发的一个帖子——二进制安全之路分享,里面说到了“英语决定了你的上限”,十分值得思考。
4. 规划 写到这里突然发现规划其实无形中都在自我审视里面表达出来了,除了那些如果还有的话就是,希望自己能够时常保持好奇心和勇气去发现更多有趣的事物,然后如果能分享给别人就更好了。
最后放一句前几天在论坛最新回复版块看到的 @r0ysue 巨佬以前的一篇文章《似水流年》中学到的一句话,“男儿欲遂平生志,五经勤向窗前读。”
5. 一些学习资料 文中提到的一些技术点可以在下面文章中找到学习,在这里感谢每一位大佬的无私分享精神!
frida-unpack(https://github.com/dstmath/frida-unpack )
FRIDA-DEXDump(https://github.com/hluwa/FRIDA-DEXDump )
frida_hook_libart(https://github.com/lasting-yang/frida_hook_libart )
内存中dump出解密后的so文件--简单修复--使得ida可以静态分析(https://bbs.pediy.com/thread-259058.htm )
FART:ART环境下基于主动调用的自动化脱壳方案(https://bbs.pediy.com/thread-252630.htm )
FART正餐前甜点:ART下几个通用简单高效的dump内存中dex方法(https://bbs.pediy.com/thread-254028.htm )
安卓APP脱壳的本质以及如何快速发现ART下的脱壳点(https://bbs.pediy.com/thread-254555.htm )
某抽取壳的原理简析(https://bbs.pediy.com/thread-259449.htm )
实用FRIDA进阶:内存漫游、hook anywhere、抓包(https://www.anquanke.com/post/id/197657 )
二进制安全之路分享(https://bbs.pediy.com/thread-259492.htm )
似水流年(https://bbs.pediy.com/thread-247957.htm )