一、背景
hanbingle在看雪论坛上分享了[原创]FART:ART环境下基于主动调用的自动化脱壳方案,思路非常棒;可惜并没有公开修改android源码部分,这让深入理解脱壳方案或者定制化自己的脱壳方案存在困难,本文通过逆向FART所提供的system.img镜像得到思路,同时修改源码适配android-9.0.0_r36,并公开脱壳源码。
二、如何逆向system.img呢?
1、simg2img system.img system.img.ext4
2、sudo mkdir sysmain
3、sudo mount -t ext4 -o loop system.img.ext4 sysmain
进入到sysmain中,找到framework.jar、core-libart.jar、libart.so,主要涉及修改的是
framework.jar中的ActivityThread.java、core-libart.jar中的DexFile.java、libart.so中的libdexfile/dex/standard_dex_file.h、runtime/art_method-inl.h、runtime/art_method.h、runtime/native/dalvik_system_DexFile.cc。
将framework.jar改为
framework.zip解压后得到classes.dex,使用dex2jar,jd-gui转换为java代码查看,但jd-guid无法将核心的smali代码转为java代码。
所以只能通过阅读smali来了解脱壳思路,使用dex2smali将dex转换为smali,我们主要看ActivityThread.smali;
同理core-libart.jar也是同样的思路,最终我们得到DexFile.java,在这里只是加了一个函数,这个函数时个native方法,我们会在libart.so里面实现,在
ActivityThread.smali 里面调用,如何调用呢,我们看接下来的分析。
public classs DexFile {
+private static native void dumpMethodCode(Object methodid);
}
三、分析Java层脱壳代码
我们先看
ActivityThread.smali里面核心的脱壳代码:
.method public static fart()V
.catch Ljava/lang/Exception; { :L0 .. :L1 } :L11
.catch Ljava/lang/Exception; { :L3 .. :L4 } :L12
.catch Ljava/lang/IllegalAccessException; { :L15 .. :L16 } :L19
.catch Ljava/lang/IllegalAccessException; { :L21 .. :L22 } :L25
.catch Ljava/lang/reflect/InvocationTargetException; { :L21 .. :L22 } :L24
.registers 30
.prologue
.line 701
invoke-static { }, Landroid/app/ActivityThread;->getClassloader()Ljava/lang/ClassLoader;
move-result-object v5
.line 702
.local v5, appClassloader:Ljava/lang/ClassLoader;
new-instance v9, Ljava/util/ArrayList;
invoke-direct { v9 }, Ljava/util/ArrayList;->()V
.line 703
.local v9, dexFilesArray:Ljava/util/List;, "Ljava/util/List;"
const-string/jumbo v25, "dalvik.system.BaseDexClassLoader"
const-string/jumbo v26, "pathList"
move-object/from16 v0, v25
move-object/from16 v1, v26
invoke-static { v5, v0, v1 }, Landroid/app/ActivityThread;->getClassField(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Field;
move-result-object v23
.line 705
.local v23, pathList_Field:Ljava/lang/reflect/Field;
const-string/jumbo v25, "dalvik.system.BaseDexClassLoader"
const-string/jumbo v26, "pathList"
move-object/from16 v0, v25
move-object/from16 v1, v26
invoke-static { v0, v5, v1 }, Landroid/app/ActivityThread;->getFieldOjbect(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
move-result-object v24
.line 706
.local v24, pathList_object:Ljava/lang/Object;
const-string/jumbo v25, "dalvik.system.DexPathList"
const-string/jumbo v26, "dexElements"
move-object/from16 v0, v25
move-object/from16 v1, v24
move-object/from16 v2, v26
invoke-static { v0, v1, v2 }, Landroid/app/ActivityThread;->getFieldOjbect(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
move-result-object v4
check-cast v4, [Ljava/lang/Object;
.line 707
.local v4, ElementsArray:[Ljava/lang/Object;
const/4 v8, 0
:L0
.line 709
.local v8, dexFile_fileField:Ljava/lang/reflect/Field;
const-string/jumbo v25, "dalvik.system.DexPathList$Element"
const-string/jumbo v26, "dexFile"
move-object/from16 v0, v25
move-object/from16 v1, v26
invoke-static { v5, v0, v1 }, Landroid/app/ActivityThread;->getClassField(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Field;
:L1
move-result-object v8
:L2
.line 713
.end local v8
const/4 v3, 0
:L3
.line 715
.local v3, DexFileClazz:Ljava/lang/Class;
const-string/jumbo v25, "dalvik.system.DexFile"
move-object/from16 v0, v25
invoke-virtual { v5, v0 }, Ljava/lang/ClassLoader;->loadClass(Ljava/lang/String;)Ljava/lang/Class;
:L4
move-result-object v3
:L5
.line 719
.end local v3
const/16 v19, 0
.line 720
.local v19, getClassNameList_method:Ljava/lang/reflect/Method;
const/4 v7, 0
.line 721
.local v7, defineClass_method:Ljava/lang/reflect/Method;
const/4 v11, 0
.line 722
.local v11, dumpDexFile_method:Ljava/lang/reflect/Method;
const/4 v12, 0
.line 724
.local v12, dumpMethodCode_method:Ljava/lang/reflect/Method;
invoke-virtual { v3 }, Ljava/lang/Class;->getDeclaredMethods()[Ljava/lang/reflect/Method;
move-result-object v26
const/16 v25, 0
move-object/from16 v0, v26
array-length v0, v0
move/from16 v27, v0
:L6
.end local v7
.end local v11
.end local v12
.end local v19
move/from16 v0, v25
move/from16 v1, v27
if-ge v0, v1, :L13
aget-object v18, v26, v25
.line 725
.local v18, field:Ljava/lang/reflect/Method;
invoke-virtual/range { v18 .. v18 }, Ljava/lang/reflect/Method;->getName()Ljava/lang/String;
move-result-object v28
const-string/jumbo v29, "getClassNameList"
invoke-virtual/range { v28 .. v29 }, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v28
if-eqz v28, :L7
.line 726
move-object/from16 v19, v18
.line 727
.local v19, getClassNameList_method:Ljava/lang/reflect/Method;
const/16 v28, 1
move-object/from16 v0, v19
move/from16 v1, v28
invoke-virtual { v0, v1 }, Ljava/lang/reflect/Method;->setAccessible(Z)V
:L7
.line 729
.end local v19
invoke-virtual/range { v18 .. v18 }, Ljava/lang/reflect/Method;->getName()Ljava/lang/String;
move-result-object v28
const-string/jumbo v29, "defineClassNative"
invoke-virtual/range { v28 .. v29 }, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v28
if-eqz v28, :L8
.line 730
move-object/from16 v7, v18
.line 731
.local v7, defineClass_method:Ljava/lang/reflect/Method;
const/16 v28, 1
move/from16 v0, v28
invoke-virtual { v7, v0 }, Ljava/lang/reflect/Method;->setAccessible(Z)V
:L8
.line 733
.end local v7
invoke-virtual/range { v18 .. v18 }, Ljava/lang/reflect/Method;->getName()Ljava/lang/String;
move-result-object v28
const-string/jumbo v29, "dumpDexFile"
invoke-virtual/range { v28 .. v29 }, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v28
if-eqz v28, :L9
.line 734
move-object/from16 v11, v18
.line 735
.local v11, dumpDexFile_method:Ljava/lang/reflect/Method;
const/16 v28, 1
move/from16 v0, v28
invoke-virtual { v11, v0 }, Ljava/lang/reflect/Method;->setAccessible(Z)V
:L9
.line 737
.end local v11
invoke-virtual/range { v18 .. v18 }, Ljava/lang/reflect/Method;->getName()Ljava/lang/String;
move-result-object v28
const-string/jumbo v29, "dumpMethodCode"
invoke-virtual/range { v28 .. v29 }, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v28
if-eqz v28, :L10
.line 738
move-object/from16 v12, v18
.line 739
.local v12, dumpMethodCode_method:Ljava/lang/reflect/Method;
const/16 v28, 1
move/from16 v0, v28
invoke-virtual { v12, v0 }, Ljava/lang/reflect/Method;->setAccessible(Z)V
:L10
.line 724
.end local v12
add-int/lit8 v25, v25, 1
goto :L6
:L11
.line 710
.end local v18
.restart local v8
move-exception v13
.line 711
.local v13, e:Ljava/lang/Exception;
const-string/jumbo v25, "ActivityThread->err"
invoke-static { v1