一:首先dump出核心函数的so
参考:https://bbs.pediy.com/thread-221270.htm
可以从上面看到的是内存地址是不连续的,并且走到.init_array处以后就会消失code区域。可能是中间存在一些解壳的数据或者是IDA没有读出来。先不管这些,往应用级函数走。
在应用级函数oncreate处按照在.init处的libx3g.so在内存中的地址进行dump。在010中按照
进行修复,然后用IDA打开,可以清晰的看到oncreate和test方法。
二、接一下一步步的分析并尝试着手动进行还原。
1.函数NewLocalRef有时被用来确保一个工具函数返回一个局部引用,先这么理解,先往下看。
Sub_206C函数是一个JNI抛出异常的解决办法,如下图所示为函数体:
接着往下看sub_2170函数:
可以看到通过Findclass获取类的对象,然后通过GetMethodID来获取oncreate方法的属性。接下来通过sub_13C8函数调用callNonvirtualVoidMethod对刚才获取的方法属性进行调用。
这就是一个JNI反射调用的过程,所对应的Smali代码如下:
最后通过sub_1980本地方法执行完毕后进行释放。
可以发现顶象在对于oncreate函数这块的安排上主要是采用对于Android SDK中JNI反射调用的原理。
通过上面的分析可以推测出对应的smali的调用过程为:
Invoke-super{ 参数怎么确定}Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
2.接着往下分析,可以发现setContentView跟上面那个oncreate的调用是一样,但是对于这个参数是怎么确定的,在静态分析的时候是不清楚的。
需要动态调试进行分析一下。
可以确定的是这块所执行的smali代码为:
const v2, 0x7f040019
invoke-virtual {p0, v2},Lcom/example/zbb/dingxiangdemo01/MainActivity;->setContentView(I)V
3.接着往下看
可以发现跟上边是一样的原理,只不过在这里可以看到的是得到的值给了V6,因此肯定有一个调用函数返回给某个寄存器的过程。动态调试看一下运行的过程为:
因此可以得到大概的对应的smali的代码为:
const vX, 0x7f0c0051
invoke-virtual {p0, vX},Lcom/example/zbb/dingxiangdemo01/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object vX
4.接着往下分析看到的是
这两个函数的作用就是,在上面一步可以得到的是通过findviewbyid得到的,自然要把对象引用转换为ID类型的实例。因此这可以得到对应的smali为:
check-cast v1, Landroid/widget/EditText;
5.接着往下看,下面这个跟上面是相似的就不描述了。
可以大致推断出来smali的代码为:
const v2, 0x7f0c0052
invoke-virtual {p0, v2},Lcom/example/zbb/dingxiangdemo01/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
6.在这里可以看到一个新的类的出现
new-instance v2,Lcom/example/zbb/dingxiangdemo01/MainActivity$1;
invoke-direct {v2, p0, v1},Lcom/example/zbb/dingxiangdemo01/MainActivity$1;-><init>(Lcom/example/zbb/dingxiangdemo01/MainActivity;Landroid/widget/EditText;)V
invoke-virtual {v0, v2},Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
三、对于单纯的java2C
我在测试的过程中专门写了一个纯的java方法,可以看到的是顶象变成了一个C方法,如下图所示:以此为原java、汇编、伪C
对于以上这种的还原目前还没有想到好的办法,只能是理解汇编、理解伪C,写出对应的java,我觉得这种想法实现起来会比较困难。
四、手动还原or自动还原
上面的一个分析是手动进行大致还原的一个过程,真的是异常的麻烦,还是一个事倍功半的效果,包括对于MainActivity$1都还没有进行还原分析,这还是一个简单的demo,如果一个成熟APK这么还原肯定是行不通的,如果把so进行混淆,直接就增加了工作量。对于在自动还原这一块,也还没有想到好的自定处理脚本应该来怎么写。
五、总结
顶象这种保护目前来说我认为是比较理想的并且达到的效果应该是在之前以360为代表的dex虚拟机之上的,首先把所有的smali理解变为C,并且进行编译,在这种情况下的很多语义完全的失真,对于攻击者来说要想还原只能是理解ARM的基础上转成smali。对于ARM汇编的理解还是难度比较大。所以这个保护策略的价值比较大。
对于保护者来说,有了进一步的smali转为C,我们可以在编译或者在编译之前对dex都做一些混淆,或者说对保护完的so做加壳加密等保护措施,以及对C做一些白箱转换的保护我觉得最后的效果是惊人的。还有现在最为流行的对so做VMP保护。因此可做的事情会很多很多。
六、YY一下
思考一下如果作为一个加固者,对于一个待保护的APK是怎么进行保护的?
首先反编译得到对应的Smali代码,然后如果从单纯的Smali转为C,应该是不是很现实的。
这里的重点是理解Dalvik虚拟机或者ART虚拟机是怎么执行这些汇编的,用C语言是怎么模拟执行Smali的。有待于进一步的考虑和分析。
今天的文章 顶象加固分析和一点还原分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/83437.html