android反编译脱壳,Android脱壳圣战之---如何脱掉"爱加密"家的保护壳

上面就简单分析了爱加密的原理和流程,但是我们没有继续往下面分析了,因为这个不是我们今天讲解的重点,我们今天的重点是如何脱掉爱加密的壳,那么还是开始说到的,脱壳的核心就一个:给dvmDexFileOpenPartial函数下断点,dump出内存的dex文件即可,那么下面我们就是用IDA开始脱壳操作了:

第一步:启动设备中的android_server,然后进行端口转发

adb forward tcp:23946 tcp:23946

55fd2b2273b5a8b4531f72773c469d6e.gif

15.png (7.03 KB, 下载次数: 10)

2016-6-12 09:03 上传

第二步:用debug模式启动程序

adb shell am start -D -n com.droider.crackme0201/.MainActivity

这里的包名和入口Activity都可以在上面反编译之后的AndroidManifest.xml中找到

55fd2b2273b5a8b4531f72773c469d6e.gif

16.png (10.03 KB, 下载次数: 9)

2016-6-12 09:03 上传

第三步:双开IDA,一个用于静态分析libdvm.so,一个用于动态调试

55fd2b2273b5a8b4531f72773c469d6e.gif

17.png (116.22 KB, 下载次数: 12)

2016-6-12 09:03 上传

记录dvmDexFileOpenPartial函数的相对地址:4777C

再次打开一个IDA,进行attach调试进程

55fd2b2273b5a8b4531f72773c469d6e.gif

18.png (33.9 KB, 下载次数: 13)

2016-6-12 09:03 上传

第四步:使用jdb命令attach上调试器

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

55fd2b2273b5a8b4531f72773c469d6e.gif

19.png (10.44 KB, 下载次数: 11)

2016-6-12 09:03 上传

第五步:对dvmDexFileOpenPartial函数下断点

进入调试页面之后,Ctrl+S查找libdvm.so的内存基地址:415BB000

55fd2b2273b5a8b4531f72773c469d6e.gif

20.png (41.73 KB, 下载次数: 11)

2016-6-12 09:03 上传

在第三步得到相对地址:4777C+415BB000=4160277C 得到了dvmDexFileOpenPartial在内存中的绝对地址

注意:

当然这里还有一个更方便的办法:

就是直接打开Modules View:

55fd2b2273b5a8b4531f72773c469d6e.gif

21.png (34.14 KB, 下载次数: 10)

2016-6-12 09:03 上传

在这里查找libdvm.so文件:

55fd2b2273b5a8b4531f72773c469d6e.gif

22.png (17.1 KB, 下载次数: 10)

2016-6-12 09:03 上传

然后双击libdvm.so文件:

查找需要下断点的函数名称,看到这里的绝地地址也是:4160277C

这里有两种方式可以得到一个函数在内存中的绝对地址。

然后我们使用G键,直接跳转到函数处,下断点:

55fd2b2273b5a8b4531f72773c469d6e.gif

23.png (17.71 KB, 下载次数: 11)

2016-6-12 09:03 上传

第六步:设置Debugger Options选项

能够让程序断在dvmDexFileOpenPartial函数处

55fd2b2273b5a8b4531f72773c469d6e.gif

24.png (18.03 KB, 下载次数: 11)

2016-6-12 09:03 上传

注意:

上面的第四步,第五步,第六步,没有顺序的,只要在运行之前设置到就可以了。

第七步:运行程序

出现这个对话框,不要在意,一路点击Cancel即可

55fd2b2273b5a8b4531f72773c469d6e.gif

25.png (37.98 KB, 下载次数: 14)

2016-6-12 09:03 上传

jdb也attach上了调试程序:

55fd2b2273b5a8b4531f72773c469d6e.gif

26.png (30.73 KB, 下载次数: 8)

2016-6-12 09:03 上传

我们一路点击运行按钮,知道运行到dvmDexFileOpenPartial处的断点,但是可惜的是,这里我们遇到了错误:

55fd2b2273b5a8b4531f72773c469d6e.gif

27.png (16.86 KB, 下载次数: 11)

2016-6-12 09:03 上传

我们点击OK之后,出现了下面对话框:

55fd2b2273b5a8b4531f72773c469d6e.gif

28.png (30.06 KB, 下载次数: 8)

2016-6-12 09:03 上传

再次点击任何一个按钮,都会退出了调试页面:

55fd2b2273b5a8b4531f72773c469d6e.gif

29.png (27.64 KB, 下载次数: 9)

2016-6-12 09:03 上传

我们在重新尝试一次上面的流程,开始调试,但是错误是一样的,好了,到这里我们就立马想到了,之前说的IDA调试so的那篇文章遇到的那个问题:反调试检测

当时我们也是遇到这个情况,在没有运行到我们下的断点处,就退出了调试页面,其实这个是现在加固平台必要选择的一种方式,其实反调试原理很简单,就是在程序运行最早的时机比如so加载的时候即:JNI_OnLoad方法中,读取本进程的status文件,查看TracerPid字段是否为0,如果不为0,那么就表示自己的进程被别人跟踪了,也就是attach了,那么这时候立马退出程序,下面我们使用IDA在attach进程成功之后,查看本进程的status信息:

55fd2b2273b5a8b4531f72773c469d6e.gif

30.png (19.94 KB, 下载次数: 10)

2016-6-12 09:03 上传

看到这里的TracerPid为11340,不为0,表示被11340进程attach了,那么我们可以查看一下这个进程是谁:

55fd2b2273b5a8b4531f72773c469d6e.gif

31.png (20.16 KB, 下载次数: 11)

2016-6-12 09:03 上传

其实这个进程就是我们在设备中安插的android_server,它用于和IDA进行通信。

好了到这里,我们可以看到爱加密做了反调试检测,但是按照之前的那篇文章中,我们可以给JNI_OnLoad函数下断点,然后找到检测代码,把对应的arm指令改成空指令,检测失效了,但是这里我们知道爱加密的两个so文件被处理了,IDA没法分析了,那么这里我们该怎么办呢?如何应对反调试呢?其实我们可以借助IDA可以修改寄存器和内存数据的特性来做到?

首先我们上面分析了反调试的原理,一般在native代码去做检测的话,都是用fopen系统函数打开status文件,然后用fgets函数读取一行的内容,这个是国际惯例的,操作文件都是用的fopen函数的

好了,那么这里思路就有了:既然反调试肯定用到了fopen和fgets这两个函数,那么我们直接像给dvmDexFileOpenPartial下断点的方式一样,给这两个函数下断点,然后运行到fgets断点处的时候,发现如果是读取TracerPid这行内容的时候,就开始修改内存内容,把TracerPid字段的值改成0,或者修改R0寄存器的内容,跳过反调试检测

这两个函数是在libc.so文件中的,我们可以把设备的/system/lib/libc.so使用adb pull到本地即可,然后用IDA得到他的相对地址,在调试页面得到基地址,然后相加得到绝对地址,跳转即可,但是这里不用这种复杂的方式,有两种方式可以进行跳转:

第一种方式:在Modules界面,找到libc.so,然后在找到这两个函数,就可以得到他们的绝对地址了

55fd2b2273b5a8b4531f72773c469d6e.gif

32.png (9.74 KB, 下载次数: 12)

2016-6-12 09:03 上传

然后使用G键,跳转下断点即可:

55fd2b2273b5a8b4531f72773c469d6e.gif

33.png (16.88 KB, 下载次数: 9)

2016-6-12 09:03 上传

第二种方式:也是最简单的方式,就是G键,本身就有可以直接输入函数名进行跳转的功能

55fd2b2273b5a8b4531f72773c469d6e.gif

34.png (20.47 KB, 下载次数: 9)

2016-6-12 09:03 上传

下断点:

55fd2b2273b5a8b4531f72773c469d6e.gif

35.png (22.61 KB, 下载次数: 10)

2016-6-12 09:03 上传

看到了吧,这种方式是不是非常简单高效

好了到这里就给这两个函数下好了断点,当然这里还需要给dvmDexFileOpenPartial函数下断点,一切弄好了之后,这时候我们再次运行:

55fd2b2273b5a8b4531f72773c469d6e.gif

36.png (19.08 KB, 下载次数: 9)

2016-6-12 09:03 上传

停在了fopen断点处,我们使用F8单步调试,看到R7寄存器中的内容是/proc/...,我们直接点击R7查看全部内容:

55fd2b2273b5a8b4531f72773c469d6e.gif

37.png (27.29 KB, 下载次数: 11)

2016-6-12 09:03 上传

内容有点长,大致的内容是:/proc/self/cmdline.debug.atrace.app_cmdlines,这个是干什么的?

我们看看这个目录内容:

55fd2b2273b5a8b4531f72773c469d6e.gif

38.png (24.06 KB, 下载次数: 11)

2016-6-12 09:03 上传

发现没有这个文件内容,只有cmdline文件,但是这里先不管他了,我们知道这个肯定不是读取status文件的,那我们直接略过这个断点,点击F9运行到下一个断点,中间过程先忽略,一路F9,直到运行到了fopen这个断点:

55fd2b2273b5a8b4531f72773c469d6e.gif

39.png (14.73 KB, 下载次数: 11)

2016-6-12 09:03 上传

果然,这里使用了fopen来读取status文件了,点击R7寄存器查看全部内容:

55fd2b2273b5a8b4531f72773c469d6e.gif

40.png (25.29 KB, 下载次数: 10)

2016-6-12 09:03 上传

这个16396就是我们本进程的id:

55fd2b2273b5a8b4531f72773c469d6e.gif

41.png (18.39 KB, 下载次数: 11)

2016-6-12 09:03 上传

到这里,我们知道下一个断点肯定是fgets,所以点击F9进入到fgets断点处:

55fd2b2273b5a8b4531f72773c469d6e.gif

42.png (11.08 KB, 下载次数: 9)

2016-6-12 09:03 上传

这里还看不到什么信息,我们继续点击F8单步调试:

55fd2b2273b5a8b4531f72773c469d6e.gif

44.png (22.2 KB, 下载次数: 10)

2016-6-12 09:03 上传

途中,会看到有memchr和memcpy这两个重要函数,这个也是操作字符串的核心点,继续往下走:

55fd2b2273b5a8b4531f72773c469d6e.gif

45.png (22.83 KB, 下载次数: 10)

2016-6-12 09:03 上传

到了fgets函数结束的地方,我们看到了R0寄存器的内容是Name...点击R0查看全部内容:

55fd2b2273b5a8b4531f72773c469d6e.gif

46.png (20.74 KB, 下载次数: 11)

2016-6-12 09:03 上传

全部内容是:Name:   der.crackme0201;这个就是status文件的第一行内容:

55fd2b2273b5a8b4531f72773c469d6e.gif

47.png (13.37 KB, 下载次数: 9)

2016-6-12 09:03 上传

到这里,我们知道了,开始读取status文件的每行内容了,但是到TracerPid那行还要继续执行5次fgets函数,所以还会进入5次断点,为了节省时间,这里点击5次F9,直接运行到读取TracerPid那行的内容的fgets断点处:

55fd2b2273b5a8b4531f72773c469d6e.gif

48.png (22.17 KB, 下载次数: 9)

2016-6-12 09:03 上传

看到了关键的内容了TracerPid字段了,这时候,我们打开Hex View 查看16进制的内存数据:

55fd2b2273b5a8b4531f72773c469d6e.gif

49.png (17.92 KB, 下载次数: 10)

2016-6-12 09:03 上传

但是我们看到,这个并没有和调试页面View位置相对应,我们可以这么操作:

在寄存器窗口查看到R0寄存器的内容:

你可能感兴趣的:(android反编译脱壳)