调试手机是Android 6.0的32位的手机。样本是自己写的一个demo小程序。加固时间为今年的12月中旬左右。
壳的入口是 MyWrapperProxyApplication,继承了父类 WrapperProxyApplication,并且实现了父类中的方法 initProxyApplication。
我们找到父类WrapperProxyApplication,首先找到最先执行的 attachBaseContext 方法。
可以看到首先获得了 basContext,这个 baseContext 变量会在后面 so 层中获取,进行 attach 新的 DelegateApplication。然后是给 shellApp 赋值,在调用 initProxyApplication,就是上面图中 MyWrapperProxyApplication 中实现的 initProxyApplication,可以看到
是为了获取 libshell-super.2019 的 so 文件路径进行 System.load 加载。到这里,我们Java层的分析就差不多了,下面进入SO层分析。
一般的话是先分析.init_array节区,再分析JNI_OnLoad。在这里我们先分析.init_array节区里的函数,如图所示:
从中我们可以看到有很多函数,那么我们就要考虑这些函数都做了什么事了。
同时我们可以看一下字符串有没有被处理,如果被处理的话,那么此部分极可能是做一些初始化工作和解密一些东西。
字符串窗口如图所示:
可以看出有一部分字符串是解密状态的,在这里我们可以用一下 elf-dump-fix 工具来dump出字符串被解密的so,然后分析。
此工具来自
接下来我们开始分析JNI_OnLoad,按F5查看函数的伪代码,把函数参数改为JavaVM *,在这里我们可以看一下它的Graph窗口,如下图:
从中可以看出,函数被混淆的比较厉害。分支较多,在这里因为混淆难度不是很高,即混淆是比较死的,不是很灵活,那么是什么意思呢,
它的路径只有一条,所以直接IDA动态调试就可以的,咱们这里就不展开讲如何处理混淆了。直接开始重点函数分析。
首先是 sub_1CA8C 函数,在这个函数里面对壳运行环境数据的初始化和获取,以及最重要的是找到被抽取的 Dex 文件压缩后的数据,
并释放到内存中。
还有一个是sub_CC9C 函数,它做了很多事情,完成了对系统函数的 hook,如mmap、fopen等,加载了Dex文件,并进行了对 ProxyApplication
到 DelegateApplication 的替换。
下面开始说sub_1CA8C函数,
那么如何定位到sub_1CA8C函数呢,我这里说一下。
咱们在这里定位v44变量,即JavaVM *,如图:
在这里可以看到,sub_1CA8C函数传进去了JavaVM *,那么此函数就需要分析一下了。
我们点进去之后可以看到此函数做了很多事,如下图:
在这里,初始化了一些环境信息,比如系统SDK版本、虚拟机类型、壳的一些信息等等,并且把他们都存放到此函数的第三个函数里,
那么它的类型应该是一个结构体。当然它的类型可以在IDA中不做修改。
可以对比一下它的原so,即字符串未解密时,如图:
可以看到,字符串都是被加密了,信息获取不到。那么我们从内存中把so给dump下来,对我们的静态分析提供了很大的帮助。
当然,也仅仅是静态分析,动态调试时,这些字符串都解密了。
接下里,我们接着看这个函数,
随后,打开了o0oooOO0ooOo.dat文件,
需要一提的是*(v5 + 151)存的是虚拟机的类型,即 1==dalvik 2==art。
后面就会根据这个走对应的分支,如下图:
此图为dalivik分支
此为art分支
在sub_1BF80中就会找到被抽取加密的dex文件,并对它进行解密,即下面这个文件,
在此函数中有一下三个关键点,如图:
打开文件,然后映射,sub_1BF20函数解密。
IDA动态调试视角如下:
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-12-23 17:20
被[軍]编辑
,原因: