一个函数抽取类壳的脱壳过程
AndroidKiller查看此apk发现入口Activity找不到,说明此apk被加壳了。
接着查看apk反编译后的代码,发现使用的XX的乐固。
首先尝试在DEX文件加载过程中进行hook,例如hook DexFileLoader::OpenCommon。然后dump下来的dex进行分析发现所有的方法都被抽空了,原因是因为我们在dex文件加载流程中dump dex时,dex中的方法还未被恢复所以无法得到完整的dex文件。
然后尝试在类加载过程中进行hook,这里直接使用frida_dump脚本,此脚本会hook ClassLinker::DefineClass函数。分析dump下来的dex文件发现被抽空的函数都已经回填了,所以此壳一定是在ClassLinker::DefineClass函数调用之前对类中的方法进行了恢复回填。当然这种是被动调用脱壳,脱壳的前提是此类在运行过程被加载,如果有的类在当前运行过程还未加载那就需要结合主动调用加载所有的类进行dump。
如果抽取壳是在ClassLinker::DefineClass函数调用之后进行回填呢?利用我自己实现的一个简易版抽取壳,并对一个测试函数的方法Tes1.Proc1进行抽空,此抽取壳是在ClassLinker::LoadMethod函数调用时对抽取的函数进行回填。
LoadMethod函数是在ClassLinker::DefineClass函数调用后调用的,因此通过hook ClassLinker::DefineClass函数dump dex文件的时候我们抽取的函数还没有进行回填,最终dump下来的dex文件此函数还是被抽空的。
可以通过在LoadMethod函数调用后进行hook并dump dex文件,可以使用frida脚本或者修改系统源码。这里采用修改系统源码,在LoadMethod函数调用处的后面进行dump dex即可(注意有两处LoadMethod调用,分别是加载直接方法和虚方法,两处都进行dump)。
dump后再次查看dex文件发现被抽取的函数已经回填。
总结:由上述脱壳过程可以看出不同的加壳方法其对应的脱壳方法也会有细微差别,关键在于hook点的选择。而且上面的脱壳方法只是单纯基于apk的被动调用,如果一些类还未加载那么其就需要结合主动调用来进行脱壳。