首页
社区
课程
招聘
[原创]大盗不操戈——新手如何做APK破解
2014-9-30 18:18 87301

[原创]大盗不操戈——新手如何做APK破解

2014-9-30 18:18
87301
传说是阿里的什么竞赛(百度到的地址~http://alictf.com/),因为已经是工作的人了,也就没怎么关注,前一段时间从朋友手中拿到的apk,简单看了一下。

刚刚看到有人发了这个APK的脱壳教程(http://bbs.pediy.com/showthread.php?t=192836),我也简单来说说对于一个新手,这道题目怎么解吧,甚至连ARM汇编都不需要掌握,只要了解一些APK和调试的基础知识就行了。程序下载附在最后

需要的工具呢,android sdk全套是必须的。因为这apk一装进我手机里面就各种崩溃,所以需要一个Android4.0以上的虚拟机,配套的DDMS,Java环境等,就不多说了。然后IDA,需要一些Android调试的知识,知道ARM中函数调用的概念和形式,OK,可以开工了。

1.        拿到APK的第一件事,习惯性地解压缩,看看里面的文件:

注意到classes.dex文件大小只有1KB,就应该猜到关键点不是Java代码了,那就肯定是在lib里面实现了动态加载。

2.        动态跑一下程序,发现界面很普通,就是输入一个密码,然后点登陆。打开monitor(sdk/tools/monitor<.bat>)会发现有很多debug信息(放水?)

发现整个流程已经写得非常明白了。抓住其中的一些重点例如:


3.        现在,打开IDA,设置Android调试环境,Attach到com.ali.encryption进程上面去,在libmobisec.so加载时断下来(如果不会的话,请参照http://bbs.pediy.com/showthread.php?t=178659),然后在Hex View里面按g,输入前面看到的0xaa3c9008,敲回车,看到了什么?

dex.035,标准的dex文件头有木有,这时候相信很多人都会选择把dex dump出来吧。文件起始位置找到了,大小在文件头里面有

长度是0x19cf4。接下来按shift+F2,写一段dump脚本

点击Run,dump.dex到手。

4.        当然,如果这个这么简单也就没有写这些的必要了。用baksmali反编译,会出现一堆错误信息

到此就卡住了。让我们回过头来仔细看看上面这些应该如何分析的。

5.        回到最初的logcat信息,我们仔细来分(xia)析(cai)一下解密流程:

第一步是这些。根据log可以看出,关键函数式parse_dex,第一次dex magic是乱码,之后有一些解密和解压信息,第二次的dex magic就是正常的dex035了。由此可以确定,如果在magic正常之后,进行内存dump,就能获得一个dex文件。过程就不多说了,会点调试的人,配合IDA神奇的F5功能,查找字符串,然后查找引用,或者直接从导出表里面找到parse_dex函数,进行分析。应该就能dump出dex文件来,但是该dump文件反编译之后,发现没有任何有用的代码,所有代码都是RuntimeException的形式。

声明:本图盗自万抽抽的<ALICTF2014 evilAPK400完整脱壳分析>译文,链接:http://bbs.pediy.com/showthread.php?t=192836,个人懒得再做一遍了,如果侵权,请作者联系我删除。:)

6.        然后继续看logcat的输出

这里看到一个dex_juicer_patch的函数,pacth啊,一看到这个单词,就知道,肯定是关键了。然后动态调试dex_juicer_patch函数,发现0xAA3C9008是parse_dex里面存放解密后dex的内存首地址,dex_juicer_patch的内容就是对dex内存空间做了系(x)列(x)操(o)作(o)。过程如果不是对ARM很熟的童鞋,估计看到就头大。在这里就不细说了。

7.        继续看logcat,发现之后的操作,就是一些替换app,加载新dex的操作了,没有什么值得注意的。


8.        到此,应该发现dex_juicer_patch函数是重点中的重点,但是看不懂ARM汇编,该怎么办呢?其实前面说了,dex_juicer_patch是对内存0xAA3C9008的操作,那么等dex_juicer_patch执行完了,0xAA3C9008处的内存是不是就是修复后的dex文件呢?
话不多说,在dex_juicer_patch运行结束,返回前执行之前dump脚本,把内存dump出来。然后用baksmali反编译看看。
然后。。。。。。就回到了第4步的结论,反编译各种错误。不过相比于都是RuntimeException有进步。

9.        大结局
其实做为一个新手,做到这一步就差不多了,后续内容,要么有很强的实力,要么有很强的运气。都没有的话会比较蛋疼,例如me。
过程就不啰嗦了,结论就是,分析dex文件,可以发现里面很多指针指向了文件末尾以外。那么就可以猜测出来,dex文件头的文件长度并不是patch之后真正的文件长度,那么只要扩大这个值,把完整的dex文件dump出来就行了。
个人的方法呢,就是从0xAA3C9008 + 0x19CF4处开始往下找,找到下一段全是0的内存区,然后从0xAA3C9008到全是0的内存区dump出来。因为全0一般表示分割,可以用来大概区分数据段,如果一次不行的话,就继续往后找下一段。
最后贡献一下dump代码:

反编译的结果:


最后的dex破解,就不关我的事了,有兴趣的童鞋可以自己尝试一下,如果还有难点,欢迎联系我。

10.        总结
总之一句话:大盗不操戈。很多看似很困难的事情,只是因为我们没有想到更优雅的解决办法。

crackme.zip

[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (50)
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
QEver 5 2014-9-30 18:33
2
0

例如内存动态加载,走的是Dalvik_dalvik_system_DexFile_openDexFile_bytearray,里面要调用addToDexFileTable在哪里下断点都能截到dex文件,只要能解size大小问题。
只要不自己运行时解析指令的话,这里应该都能拦到,或者盯着gDvm.userDexFiles,但gDvm.userDexFiles不是一直都有效的。
总之还是要动态解析指令啊,但是动态解析的方法不能做产品,稳定性太差了。


本来是希望能有人一起讨论一下,不过看来只能自言自语了。简单补充一下吧。由于本人刚刚转行做Android研究,如果说的哪里不对,欢迎指正

1. 有人说,你这种方法完全是侥幸,dex文件缺少的部分,刚好map到了dex原始内容的后面,使得多dump一段内存之后,就能获取完整的dex文件。
其实呢,要知道,在dex文件结构中,表示偏移的量都是unsigned的,也就是说只要定位到了dex文件头,那么剩余的数据,都是在文件头之后。同时呢,对于现在的Android系统而言,都是32位的,内存的寻址空间是4GB,去掉内核空间,忽略dex文件头之前的空间,假设dex文件头之后有2GB的内存可用(实际上远远小于这个值),那么我们完全可以从dex文件头开始,将之后的2GB空间完全dump出来,然后baksmali一下,再重新打包,新的完整dex文件就出来了。简单粗暴。

2. 根据上面这条方法,结论就是只要在内存中有完整的dex文件存在,那么就有很大可能被dump出来。那么对于这种情况怎么办呢?一种简单有效的办法就是在dex文件加载过程中(之后),将部分dex文件信息抹去,至于什么能抹,什么时候抹掉,这些就不能说了,有兴趣的可以自己尝试一下。

3. 另外一种方法,就是动态解密了。但是由于Android的碎片化严重,造成了方法的兼容性很差。动态解密的话,目前的想法是hook dalvik执行的handler,定位方法暴搜,不过兼容性~唉~~~

4. 大盗不操戈~那么操戈又该如何做呢? 简单地说,就是在gDvm里面有一个loadedClasses项,里面是一个HashTable,用来记录每一个已经加载的class,可以通过注入,把特定class的字节码dump出来,并进行解析。当然,这个工作很麻烦,但却是一种王道的方法,可以应对大部分情况。目前在研究,通过dump的方式,能否从gDvm里面自己拼出一个dex文件来。理论上应该是可以的,但代码尚未完成。
雪    币: 4181
活跃值: (2497)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lylxd 2014-9-30 20:03
3
0
谢谢 mk~
雪    币: 131
活跃值: (98)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
gamehacker 1 2014-9-30 20:31
4
0
不错不错。很有意思啊
雪    币: 2321
活跃值: (4028)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
熊猫正正 9 2014-9-30 22:41
5
0
谢谢分享
雪    币: 370
活跃值: (1181)
能力值: ( LV9,RANK:310 )
在线值:
发帖
回帖
粉丝
ThomasKing 6 2014-9-30 22:48
6
0
感谢分享!
雪    币: 1413
活跃值: (401)
能力值: (RANK:270 )
在线值:
发帖
回帖
粉丝
Claud 6 2014-10-1 14:36
7
0
纯动态的方法,漂亮!尤其喜欢标题。节后记得更新~
雪    币: 507
活跃值: (120)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
鬼谷子c 1 2014-10-2 00:39
8
0
楼主的方法给力,支持一下。
选过几个位置,刚加载,过程中,以及所有so加载完毕,到加载系统字体的位置,找出来的dex都不太完整。最后dump了1g+的数据,里面寻找完整dex无果,因为陷入思维定势,总是将0x20位置大小计算然后dump,没试过额外dump再baksmali,待回头测试下。
雪    币: 32
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
KFCMAC 2014-10-2 14:25
9
0
mark 学习中
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
怕风 2014-10-4 07:18
10
0
感谢分享,学习
雪    币: 2175
活跃值: (966)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Crakme 2014-10-5 11:10
11
0
dump无果后再往下找都是0的地方再dump,我怎么木有想过
雪    币: 11
活跃值: (80)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
华仔在吗 2014-10-6 10:27
12
0
mark....
雪    币: 7
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yahwei 2014-10-7 09:50
13
0
正在学这个,太有用了…………
雪    币: 9857
活跃值: (2979)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
暖洋洋 2014-10-7 16:05
14
0
不懂额,感谢分享了
雪    币: 188
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Romangol 2014-10-12 23:42
15
0
来发一个动态分析的~视频见

http://pan.baidu.com/share/link?shareid=4134563823&uk=4010119447

具体的原理在今年的互联网安全大会ISC 2014上讲过
雪    币: 130
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yuletianxi 2014-10-13 13:58
16
0
mark,多谢楼主分享!
雪    币: 39
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
huihuitest 2014-10-13 14:15
17
0
mark,thanks.
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
IBMLover 2014-10-14 10:39
18
0
楼主写的深入浅出,受教
雪    币: 75
活跃值: (53)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiaogangha 2014-11-15 15:06
19
0
在第3步attach com.ali.encryption后IDA处于 "Searching for crypto constants..."的状态,点取消后停在 libc.so下图位置


然后“jdb -connect ....”
F9后发现libmobisec.so开始加载,但是IDA并没有停下来…,下图


Debug options中按以前 http://bbs.pediy.com/showthread.php?t=178659 这个帖子中的设置


请问有人遇到这样的问题了吗?

补充:IDA-pro-plus-6.5
上传的附件:
雪    币: 2015
活跃值: (902)
能力值: ( LV12,RANK:1000 )
在线值:
发帖
回帖
粉丝
天易love 18 2014-12-31 09:43
20
0
这IDC脚本怎么执行没反应
雪    币: 188
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JackJoker 2014-12-31 09:47
21
0
标记,多谢分享。
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
QEver 5 2014-12-31 10:10
22
0
应该是IDA版本的问题。可以尝试在libdvm.so的dvmLoadNativeCode函数下断点,对照源码,在调用dlopen之后,在so里面下断点
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
QEver 5 2014-12-31 10:11
23
0
在IDA的output window里面会有提示信息,看那个就行了。
雪    币: 30
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cnywco 2014-12-31 10:13
24
0
非常的棒,,,,顶上,。。。
雪    币: 2015
活跃值: (902)
能力值: ( LV12,RANK:1000 )
在线值:
发帖
回帖
粉丝
天易love 18 2015-1-3 10:10
25
0
楼主能否告知一下,你的AVD的配置,例如Target Name/Platform/API Level/CPU/ABI
我试了很多种,程序启动时解密都是失败,直接奔溃退出,就看到了个标题栏。还有那个IDC脚本,应该是要动态调试解密成功后运行才有效。现在不懂安卓就等于不懂逆向,所以学习一下还是必须的。
上传的附件:
游客
登录 | 注册 方可回帖
返回