首页
社区
课程
招聘
[原创] FART:ART环境下基于主动调用的自动化脱壳方案 [android脱壳源码公开,基于android-9.0.0_r36]
发表于: 2020-1-7 18:16 19972

[原创] FART:ART环境下基于主动调用的自动化脱壳方案 [android脱壳源码公开,基于android-9.0.0_r36]

2020-1-7 18:16
19972

runtime/native/dalvik_system_DexFile.cc

在这里实现DexFile类的函数private static native void dumpMethodCode(Object methodid);


一、背景
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);
}

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;-><init>()V
    .line 703
    .local v9, dexFilesArray:Ljava/util/List;, "Ljava/util/List<Ljava/lang/Object;>;"
    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 { v13 }, Landroid/util/Log;->getStackTraceString(Ljava/lang/Throwable;)Ljava/lang/String;
    move-result-object v26
    invoke-static/range { v25 .. v26 }, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    goto/16 :L2
    :L12
    .line 716
    .end local v8
    .end local v13
    .restart local v3
    move-exception v13
    .line 717
    .restart local v13
    const-string/jumbo v25, "ActivityThread->err"
    invoke-static { v13 }, Landroid/util/Log;->getStackTraceString(Ljava/lang/Throwable;)Ljava/lang/String;
    move-result-object v26
    invoke-static/range { v25 .. v26 }, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    goto/16 :L5
    :L13
    .line 742
    .end local v3
    .end local v13
    const-string/jumbo v25, "dalvik.system.DexFile"
    const-string/jumbo v26, "mCookie"
    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 v21
    .line 743
    .local v21, mCookiefield:Ljava/lang/reflect/Field;
    const/16 v20, 0
    :L14
    .local v20, j:I
    array-length v0, v4
    move/from16 v25, v0
    move/from16 v0, v20
    move/from16 v1, v25
    if-ge v0, v1, :L26
    .line 744
    aget-object v17, v4, v20
    .line 745
    .local v17, element:Ljava/lang/Object;
    const/4 v10, 0
    :L15
    .line 747
    .local v10, dexfile:Ljava/lang/Object;
    move-object/from16 v0, v17
    invoke-virtual { v8, v0 }, Ljava/lang/reflect/Field;->get(Ljava/lang/Object;)Ljava/lang/Object;
    :L16
    move-result-object v10
    :L17
    .line 751
    .end local v10
    if-nez v10, :L20
    .line 752
    const-string/jumbo v25, "ActivityThread"
    const-string/jumbo v26, "dexfile is null"
    invoke-static/range { v25 .. v26 }, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    :L18
    .line 743
    add-int/lit8 v20, v20, 1
    goto :L14
    :L19
    .line 748
    .restart local v10
    move-exception v14
    .line 749
    .local v14, e:Ljava/lang/IllegalAccessException;
    invoke-virtual { v14 }, Ljava/lang/IllegalAccessException;->printStackTrace()V
    goto :L17
    :L20
    .line 755
    .end local v10
    .end local v14
    if-eqz v10, :L18
    .line 756
    invoke-interface { v9, v10 }, Ljava/util/List;->add(Ljava/lang/Object;)Z
    .line 757
    const-string/jumbo v25, "dalvik.system.DexFile"
    const-string/jumbo v26, "mCookie"
    move-object/from16 v0, v25
    move-object/from16 v1, v26
    invoke-static { v5, v0, v10, v1 }, Landroid/app/ActivityThread;->getClassFieldObject(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
    move-result-object v22
    .line 758
    .local v22, mcookie:Ljava/lang/Object;
    if-eqz v22, :L18
    .line 761
    const/4 v6, 0
    .line 763
    .local v6, classnames:[Ljava/lang/String;
    const/16 v25, 1
    :L21
    move/from16 v0, v25
    new-array v0, v0, [Ljava/lang/Object;
    move-object/from16 v25, v0
    const/16 v26, 0
    aput-object v22, v25, v26
    move-object/from16 v0, v19
    move-object/from16 v1, v25
    invoke-virtual { v0, v10, v1 }, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
    move-result-object v6
    .end local v6
    check-cast v6, [Ljava/lang/String;
    :L22
    .line 771
    .local v6, classnames:[Ljava/lang/String;
    if-eqz v6, :L18
    .line 772
    const/16 v25, 0
    array-length v0, v6
    move/from16 v26, v0
    :L23
    move/from16 v0, v25
    move/from16 v1, v26
    if-ge v0, v1, :L18
    aget-object v16, v6, v25
    .line 773
    .local v16, eachclassname:Ljava/lang/String;
    move-object/from16 v0, v16
    invoke-static { v5, v0, v12 }, Landroid/app/ActivityThread;->loadClassAndInvoke(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/reflect/Method;)V
    .line 772
    add-int/lit8 v25, v25, 1
    goto :L23
    :L24
    .line 767
    .end local v6
    .end local v16
    move-exception v15
    .line 768
    .local v15, e:Ljava/lang/reflect/InvocationTargetException;
    invoke-virtual { v15 }, Ljava/lang/reflect/InvocationTargetException;->printStackTrace()V
    goto :L18
    :L25
    .line 764
    .end local v15
    move-exception v14
    .line 765
    .restart local v14
    invoke-virtual { v14 }, Ljava/lang/IllegalAccessException;->printStackTrace()V
    goto :L18
    :L26
    .line 779
    .end local v14
    .end local v17
    .end local v22
    return-void
.end method

.method public static fartthread()V
    .registers 2
    .prologue
    .line 783
    new-instance v0, Ljava/lang/Thread;
    new-instance v1, Landroid/app/ActivityThread$1;
    invoke-direct { v1 }, Landroid/app/ActivityThread$1;-><init>()V
    invoke-direct { v0, v1 }, Ljava/lang/Thread;-><init>(Ljava/lang/Runnable;)V
    invoke-virtual { v0 }, Ljava/lang/Thread;->start()V
    .line 782
    return-void
.end method
转换为java代码如下:
    public static void fart() {
        try {
            ClassLoader class_loader = getClassloader();
            Method[] md = class_loader.loadClass("dalvik.system.DexFile").getDeclaredMethods();
            Method getClassNameListMethod = null;
            Method dumpMethodCodeMethod = null;
            int mdCount = md.length;
            for (int i = 0; i < mdCount; i++) {
                if (md[i].getName().equals("getClassNameList")) {
                    getClassNameListMethod = md[i];//获取DexFile类的getClassNameList方法
                    md[i].setAccessible(true);
                } else if (md[i].getName().equals("dumpMethodCode")) {
                    dumpMethodCodeMethod = md[i];//获取DexFile类的dumpMethodCode方法
                    md[i].setAccessible(true);
                }
            }

            Object[] dexElementsObjs = (Object[]) getFieldOjbect("dalvik.system.DexPathList", getFieldOjbect("dalvik.system.BaseDexClassLoader", class_loader, "pathList"), "dexElements");
            Field dexFileField = getClassField(class_loader, "dalvik.system.DexPathList$Element", "dexFile");
            for (int i = 0; i < dexElementsObjs.length; i++) {
                Object dexFileObj = dexFileField.get(dexElementsObjs[i]);
                Object cookObj = getClassFieldObject(class_loader, "dalvik.system.DexFile", dexFileObj, "mCookie");//获取mCookie
                String[] classNames = (String[]) getClassNameListMethod.invoke(dexFileObj, new Object[]{cookObj});//调用DexFile类的getClassNameList获取dex中所有类名
                for (int j = 0; j < classNames.length; j++) {
                    Log.e(TAG, "fart classNames:" + classNames[j]);
                    loadClassAndInvoke(class_loader, classNames[j], dumpMethodCodeMethod);
                }
            }
        } catch (ClassNotFoundException e) {
            Log.e(TAG, "fart ClassNotFoundException" + e.getMessage());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Log.e(TAG, "fart IllegalAccessException" + e.getMessage());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Log.e(TAG, "fart InvocationTargetException" + e.getMessage());
            e.printStackTrace();
        }

    }

    public static void loadClassAndInvoke(ClassLoader class_loader, String className, Method dumpMethodCodeMethod) {
        try {
            Class class1 = class_loader.loadClass(className);//主动加载dex中的所有类,此时Method数据已解密
            Constructor[] constructors = class1.getDeclaredConstructors();
            for (int i = 0; i < constructors.length; i++) {
                dumpMethodCodeMethod.invoke(null, new Object[]{constructors[i]});//调用DexFile中dumpMethodCode方法,参数为Constructor对象
            }

            Method[] methods = class1.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                dumpMethodCodeMethod.invoke(null, new Object[]{methods[i]});//调用DexFile中dumpMethodCode方法,参数为Method对象
            }
            Log.e(TAG, "className:" + className + ",constructors length:" + constructors.length + ",method length:" + methods.length);
        } catch (ClassNotFoundException e) {
            Log.e(TAG, "fart ClassNotFoundException" + e.getMessage());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Log.e(TAG, "fart IllegalAccessException" + e.getMessage());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Log.e(TAG, "fart InvocationTargetException" + e.getMessage());
            e.printStackTrace();
        }
        return;
    }

    public static void fartthread() {
        (new Thread(new Runnable() {
            public void run() {
                try {
                    Log.e("ActivityThread", "start sleep......");
                    Thread.sleep(10000L);//睡眠10s钟
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
                Log.e("ActivityThread", "sleep over and start fart");
                ActivityThread.fart();//调用脱壳程序
                Log.e("ActivityThread", "fart run over");
            }
        })).start();
    }
主要是开启了一个线程,睡眠10s后开始干活,fart方法执行流程如下:
1、通过反射获取了DexFile类的getClassNameList方法和dumpMethodCode方法,dumpMethodCode我们刚刚在DexFile里面填加上的native方法。
2、通过当前进程的classloader,一步一步根据如下类结构pathList->dexElements->dexFile->mCookie进一步获取到当前classloader所加载的dexfile的mCookie,这个 mCookie 是native层所加载dex文件结构的标识。
public class BaseDexClassLoader extends ClassLoader {

   private final DexPathList pathList;
   ......
}

package*/ final class DexPathList {
    private static final String DEX_SUFFIX = ".dex";
    private static final String zipSeparator = "!/";

    private Element[] dexElements;
    ......
}

 /*package*/ static class Element {
    private final DexFile dexFile;
    ......
}

public final class DexFile {

    private Object mCookie;

    private static native void dumpMethodCode(Object methodid);
    private static native String[] getClassNameList(Object cookie);
    ....
}
那么当前进程的classlodaer如何获取的呢?
public static ClassLoader getClassloader() {
       Object currentActivityThread = invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class[]{}, new Object[]{});
       Object mBoundApplication = getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mBoundApplication");
       return ((Application) getFieldOjbect("android.app.LoadedApk", getFieldOjbect("android.app.ActivityThread$AppBindData", mBoundApplication, "info"), "mApplication")).getClassLoader();
}
通过反射调用 ActivityThread 类的静态函数 currentActivityThread 获取当前的 ActivityThread对象,然后获取 ActivityThread对象的mBoundApplication成员变量,t之后获取mBoundApplication对象的info成员变量,他是个LoadedApk类型;最终获取 info对象的mApplication成员变量,他的类型是Application,最后通过调用 Application.getClassLoader得到当前进程的classloader。理解整个流程请参考下面的类关系:
public final class ActivityThread extends ClientTransactionHandler {

	AppBindData mBoundApplication;
	public static ActivityThread currentActivityThread() {
		return sCurrentActivityThread;
	}
	
	static final class AppBindData {
        LoadedApk info;
		......
	}
	......

}


public final class LoadedApk {
	private Application mApplication;
	......
}	
.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;-><init>()V
    .line 703
    .local v9, dexFilesArray:Ljava/util/List;, "Ljava/util/List<Ljava/lang/Object;>;"
    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 { v13 }, Landroid/util/Log;->getStackTraceString(Ljava/lang/Throwable;)Ljava/lang/String;
    move-result-object v26
    invoke-static/range { v25 .. v26 }, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    goto/16 :L2
    :L12
    .line 716
    .end local v8
    .end local v13
    .restart local v3
    move-exception v13
    .line 717
    .restart local v13
    const-string/jumbo v25, "ActivityThread->err"
    invoke-static { v13 }, Landroid/util/Log;->getStackTraceString(Ljava/lang/Throwable;)Ljava/lang/String;
    move-result-object v26
    invoke-static/range { v25 .. v26 }, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    goto/16 :L5
    :L13
    .line 742
    .end local v3
    .end local v13
    const-string/jumbo v25, "dalvik.system.DexFile"
    const-string/jumbo v26, "mCookie"
    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 v21
    .line 743
    .local v21, mCookiefield:Ljava/lang/reflect/Field;
    const/16 v20, 0
    :L14
    .local v20, j:I
    array-length v0, v4
    move/from16 v25, v0
    move/from16 v0, v20
    move/from16 v1, v25
    if-ge v0, v1, :L26
    .line 744
    aget-object v17, v4, v20
    .line 745
    .local v17, element:Ljava/lang/Object;
    const/4 v10, 0
    :L15
    .line 747
    .local v10, dexfile:Ljava/lang/Object;
    move-object/from16 v0, v17
    invoke-virtual { v8, v0 }, Ljava/lang/reflect/Field;->get(Ljava/lang/Object;)Ljava/lang/Object;
    :L16
    move-result-object v10
    :L17
    .line 751
    .end local v10
    if-nez v10, :L20
    .line 752
    const-string/jumbo v25, "ActivityThread"
    const-string/jumbo v26, "dexfile is null"
    invoke-static/range { v25 .. v26 }, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    :L18
    .line 743
    add-int/lit8 v20, v20, 1
    goto :L14
    :L19
    .line 748
    .restart local v10
    move-exception v14
    .line 749
    .local v14, e:Ljava/lang/IllegalAccessException;
    invoke-virtual { v14 }, Ljava/lang/IllegalAccessException;->printStackTrace()V
    goto :L17
    :L20
    .line 755
    .end local v10
    .end local v14
    if-eqz v10, :L18
    .line 756
    invoke-interface { v9, v10 }, Ljava/util/List;->add(Ljava/lang/Object;)Z
    .line 757
    const-string/jumbo v25, "dalvik.system.DexFile"
    const-string/jumbo v26, "mCookie"
    move-object/from16 v0, v25
    move-object/from16 v1, v26
    invoke-static { v5, v0, v10, v1 }, Landroid/app/ActivityThread;->getClassFieldObject(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
    move-result-object v22
    .line 758
    .local v22, mcookie:Ljava/lang/Object;
    if-eqz v22, :L18
    .line 761
    const/4 v6, 0
    .line 763
    .local v6, classnames:[Ljava/lang/String;
    const/16 v25, 1
    :L21
    move/from16 v0, v25
    new-array v0, v0, [Ljava/lang/Object;
    move-object/from16 v25, v0
    const/16 v26, 0
    aput-object v22, v25, v26
    move-object/from16 v0, v19
    move-object/from16 v1, v25
    invoke-virtual { v0, v10, v1 }, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
    move-result-object v6
    .end local v6
    check-cast v6, [Ljava/lang/String;
    :L22
    .line 771
    .local v6, classnames:[Ljava/lang/String;
    if-eqz v6, :L18
    .line 772
    const/16 v25, 0
    array-length v0, v6
    move/from16 v26, v0
    :L23
    move/from16 v0, v25
    move/from16 v1, v26
    if-ge v0, v1, :L18
    aget-object v16, v6, v25
    .line 773
    .local v16, eachclassname:Ljava/lang/String;
    move-object/from16 v0, v16
    invoke-static { v5, v0, v12 }, Landroid/app/ActivityThread;->loadClassAndInvoke(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/reflect/Method;)V
    .line 772
    add-int/lit8 v25, v25, 1
    goto :L23
    :L24
    .line 767
    .end local v6
    .end local v16
    move-exception v15
    .line 768
    .local v15, e:Ljava/lang/reflect/InvocationTargetException;
    invoke-virtual { v15 }, Ljava/lang/reflect/InvocationTargetException;->printStackTrace()V
    goto :L18
    :L25
    .line 764
    .end local v15
    move-exception v14
    .line 765
    .restart local v14
    invoke-virtual { v14 }, Ljava/lang/IllegalAccessException;->printStackTrace()V
    goto :L18
    :L26
    .line 779
    .end local v14
    .end local v17
    .end local v22
    return-void
.end method

.method public static fartthread()V
    .registers 2
    .prologue
    .line 783
    new-instance v0, Ljava/lang/Thread;
    new-instance v1, Landroid/app/ActivityThread$1;
    invoke-direct { v1 }, Landroid/app/ActivityThread$1;-><init>()V
    invoke-direct { v0, v1 }, Ljava/lang/Thread;-><init>(Ljava/lang/Runnable;)V
    invoke-virtual { v0 }, Ljava/lang/Thread;->start()V
    .line 782
    return-void
.end method
转换为java代码如下:
    public static void fart() {
        try {
            ClassLoader class_loader = getClassloader();
            Method[] md = class_loader.loadClass("dalvik.system.DexFile").getDeclaredMethods();
            Method getClassNameListMethod = null;
            Method dumpMethodCodeMethod = null;
            int mdCount = md.length;
            for (int i = 0; i < mdCount; i++) {
                if (md[i].getName().equals("getClassNameList")) {
                    getClassNameListMethod = md[i];//获取DexFile类的getClassNameList方法
                    md[i].setAccessible(true);
                } else if (md[i].getName().equals("dumpMethodCode")) {
                    dumpMethodCodeMethod = md[i];//获取DexFile类的dumpMethodCode方法
                    md[i].setAccessible(true);
                }
            }

            Object[] dexElementsObjs = (Object[]) getFieldOjbect("dalvik.system.DexPathList", getFieldOjbect("dalvik.system.BaseDexClassLoader", class_loader, "pathList"), "dexElements");
            Field dexFileField = getClassField(class_loader, "dalvik.system.DexPathList$Element", "dexFile");
            for (int i = 0; i < dexElementsObjs.length; i++) {
                Object dexFileObj = dexFileField.get(dexElementsObjs[i]);
                Object cookObj = getClassFieldObject(class_loader, "dalvik.system.DexFile", dexFileObj, "mCookie");//获取mCookie
                String[] classNames = (String[]) getClassNameListMethod.invoke(dexFileObj, new Object[]{cookObj});//调用DexFile类的getClassNameList获取dex中所有类名
                for (int j = 0; j < classNames.length; j++) {
                    Log.e(TAG, "fart classNames:" + classNames[j]);
                    loadClassAndInvoke(class_loader, classNames[j], dumpMethodCodeMethod);
                }
            }
        } catch (ClassNotFoundException e) {
            Log.e(TAG, "fart ClassNotFoundException" + e.getMessage());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Log.e(TAG, "fart IllegalAccessException" + e.getMessage());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Log.e(TAG, "fart InvocationTargetException" + e.getMessage());
            e.printStackTrace();
        }

    }

    public static void loadClassAndInvoke(ClassLoader class_loader, String className, Method dumpMethodCodeMethod) {
        try {
            Class class1 = class_loader.loadClass(className);//主动加载dex中的所有类,此时Method数据已解密
            Constructor[] constructors = class1.getDeclaredConstructors();
            for (int i = 0; i < constructors.length; i++) {
                dumpMethodCodeMethod.invoke(null, new Object[]{constructors[i]});//调用DexFile中dumpMethodCode方法,参数为Constructor对象
            }

            Method[] methods = class1.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                dumpMethodCodeMethod.invoke(null, new Object[]{methods[i]});//调用DexFile中dumpMethodCode方法,参数为Method对象
            }
            Log.e(TAG, "className:" + className + ",constructors length:" + constructors.length + ",method length:" + methods.length);
        } catch (ClassNotFoundException e) {
            Log.e(TAG, "fart ClassNotFoundException" + e.getMessage());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Log.e(TAG, "fart IllegalAccessException" + e.getMessage());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Log.e(TAG, "fart InvocationTargetException" + e.getMessage());
            e.printStackTrace();
        }
        return;
    }

    public static void fartthread() {
        (new Thread(new Runnable() {
            public void run() {
                try {
                    Log.e("ActivityThread", "start sleep......");
                    Thread.sleep(10000L);//睡眠10s钟
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
                Log.e("ActivityThread", "sleep over and start fart");
                ActivityThread.fart();//调用脱壳程序
                Log.e("ActivityThread", "fart run over");
            }
        })).start();
    }
主要是开启了一个线程,睡眠10s后开始干活,fart方法执行流程如下:
1、通过反射获取了DexFile类的getClassNameList方法和dumpMethodCode方法,dumpMethodCode我们刚刚在DexFile里面填加上的native方法。
    public static void fart() {
        try {
            ClassLoader class_loader = getClassloader();
            Method[] md = class_loader.loadClass("dalvik.system.DexFile").getDeclaredMethods();
            Method getClassNameListMethod = null;
            Method dumpMethodCodeMethod = null;
            int mdCount = md.length;
            for (int i = 0; i < mdCount; i++) {
                if (md[i].getName().equals("getClassNameList")) {
                    getClassNameListMethod = md[i];//获取DexFile类的getClassNameList方法
                    md[i].setAccessible(true);
                } else if (md[i].getName().equals("dumpMethodCode")) {
                    dumpMethodCodeMethod = md[i];//获取DexFile类的dumpMethodCode方法
                    md[i].setAccessible(true);
                }
            }

            Object[] dexElementsObjs = (Object[]) getFieldOjbect("dalvik.system.DexPathList", getFieldOjbect("dalvik.system.BaseDexClassLoader", class_loader, "pathList"), "dexElements");
            Field dexFileField = getClassField(class_loader, "dalvik.system.DexPathList$Element", "dexFile");
            for (int i = 0; i < dexElementsObjs.length; i++) {
                Object dexFileObj = dexFileField.get(dexElementsObjs[i]);
                Object cookObj = getClassFieldObject(class_loader, "dalvik.system.DexFile", dexFileObj, "mCookie");//获取mCookie
                String[] classNames = (String[]) getClassNameListMethod.invoke(dexFileObj, new Object[]{cookObj});//调用DexFile类的getClassNameList获取dex中所有类名
                for (int j = 0; j < classNames.length; j++) {
                    Log.e(TAG, "fart classNames:" + classNames[j]);
                    loadClassAndInvoke(class_loader, classNames[j], dumpMethodCodeMethod);
                }
            }
        } catch (ClassNotFoundException e) {
            Log.e(TAG, "fart ClassNotFoundException" + e.getMessage());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Log.e(TAG, "fart IllegalAccessException" + e.getMessage());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Log.e(TAG, "fart InvocationTargetException" + e.getMessage());
            e.printStackTrace();
        }

    }

    public static void loadClassAndInvoke(ClassLoader class_loader, String className, Method dumpMethodCodeMethod) {
        try {
            Class class1 = class_loader.loadClass(className);//主动加载dex中的所有类,此时Method数据已解密
            Constructor[] constructors = class1.getDeclaredConstructors();
            for (int i = 0; i < constructors.length; i++) {
                dumpMethodCodeMethod.invoke(null, new Object[]{constructors[i]});//调用DexFile中dumpMethodCode方法,参数为Constructor对象
            }

            Method[] methods = class1.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                dumpMethodCodeMethod.invoke(null, new Object[]{methods[i]});//调用DexFile中dumpMethodCode方法,参数为Method对象
            }
            Log.e(TAG, "className:" + className + ",constructors length:" + constructors.length + ",method length:" + methods.length);
        } catch (ClassNotFoundException e) {
            Log.e(TAG, "fart ClassNotFoundException" + e.getMessage());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Log.e(TAG, "fart IllegalAccessException" + e.getMessage());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Log.e(TAG, "fart InvocationTargetException" + e.getMessage());
            e.printStackTrace();
        }
        return;
    }

    public static void fartthread() {
        (new Thread(new Runnable() {
            public void run() {
                try {
                    Log.e("ActivityThread", "start sleep......");
                    Thread.sleep(10000L);//睡眠10s钟
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
                Log.e("ActivityThread", "sleep over and start fart");
                ActivityThread.fart();//调用脱壳程序
                Log.e("ActivityThread", "fart run over");
            }
        })).start();
    }
主要是开启了一个线程,睡眠10s后开始干活,fart方法执行流程如下:
1、通过反射获取了DexFile类的getClassNameList方法和dumpMethodCode方法,dumpMethodCode我们刚刚在DexFile里面填加上的native方法。
2、通过当前进程的classloader,一步一步根据如下类结构pathList->dexElements->dexFile->mCookie进一步获取到当前classloader所加载的dexfile的mCookie,这个 mCookie 是native层所加载dex文件结构的标识。
public class BaseDexClassLoader extends ClassLoader {

   private final DexPathList pathList;
   ......
}

package*/ final class DexPathList {
    private static final String DEX_SUFFIX = ".dex";
    private static final String zipSeparator = "!/";

    private Element[] dexElements;
    ......
}

 /*package*/ static class Element {
    private final DexFile dexFile;
    ......
}

public final class DexFile {

    private Object mCookie;

    private static native void dumpMethodCode(Object methodid);
    private static native String[] getClassNameList(Object cookie);
    ....
}
那么当前进程的classlodaer如何获取的呢?
public class BaseDexClassLoader extends ClassLoader {

   private final DexPathList pathList;
   ......
}

package*/ final class DexPathList {
    private static final String DEX_SUFFIX = ".dex";
    private static final String zipSeparator = "!/";

    private Element[] dexElements;
    ......
}

 /*package*/ static class Element {
    private final DexFile dexFile;
    ......
}

public final class DexFile {

    private Object mCookie;

    private static native void dumpMethodCode(Object methodid);
    private static native String[] getClassNameList(Object cookie);
    ....
}
那么当前进程的classlodaer如何获取的呢?
public static ClassLoader getClassloader() {
       Object currentActivityThread = invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class[]{}, new Object[]{});
       Object mBoundApplication = getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mBoundApplication");
       return ((Application) getFieldOjbect("android.app.LoadedApk", getFieldOjbect("android.app.ActivityThread$AppBindData", mBoundApplication, "info"), "mApplication")).getClassLoader();
}
通过反射调用 ActivityThread 类的静态函数 currentActivityThread 获取当前的 ActivityThread对象,然后获取 ActivityThread对象的mBoundApplication成员变量,t之后获取mBoundApplication对象的info成员变量,他是个LoadedApk类型;最终获取 info对象的mApplication成员变量,他的类型是Application,最后通过调用 Application.getClassLoader得到当前进程的classloader。理解整个流程请参考下面的类关系:
public static ClassLoader getClassloader() {
       Object currentActivityThread = invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class[]{}, new Object[]{});
       Object mBoundApplication = getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mBoundApplication");
       return ((Application) getFieldOjbect("android.app.LoadedApk", getFieldOjbect("android.app.ActivityThread$AppBindData", mBoundApplication, "info"), "mApplication")).getClassLoader();
}
通过反射调用 ActivityThread 类的静态函数 currentActivityThread 获取当前的 ActivityThread对象,然后获取 ActivityThread对象的mBoundApplication成员变量,t之后获取mBoundApplication对象的info成员变量,他是个LoadedApk类型;最终获取 info对象的mApplication成员变量,他的类型是Application,最后通过调用 Application.getClassLoader得到当前进程的classloader。理解整个流程请参考下面的类关系:
public final class ActivityThread extends ClientTransactionHandler {

	AppBindData mBoundApplication;
	public static ActivityThread currentActivityThread() {
		return sCurrentActivityThread;
	}
	
	static final class AppBindData {
        LoadedApk info;
		......
	}
	......

}


public final class LoadedApk {
	private Application mApplication;
	......
}	
public final class ActivityThread extends ClientTransactionHandler {

	AppBindData mBoundApplication;
	public static ActivityThread currentActivityThread() {
		return sCurrentActivityThread;
	}
	
	static final class AppBindData {
        LoadedApk info;
		......
	}
	......

}


public final class LoadedApk {
	private Application mApplication;
	......
}	
3、我们已经获取了DexFile类的 getClassNameList方法和dumpMethodCode方法,和 getClassNameList所需要的cookie参数如下:
public final class DexFile {

    private Object mCookie;

    private static native void dumpMethodCode(Object methodid);
    private static native String[] getClassNameList(Object cookie);
    ....
}
调用getClassNameList(mCookie)来获取当前dex中的所有类名。
4、loadClassAndInvoke,首先通过loadClass来主动加载所有类,然后调用dumpMethodCode来进行脱壳,参数为Method或者Constructor对象。
这个有个重点我们的标题是《ART环境下基于主动调用的自动化脱壳方案》,这里主动调用就体现到这里了,loadClass。加壳程序hook了加载类的方法,当真正执行时加载类的时候会进行还原,这个加载类相当于隐式加载。我们这里loadClass是显示加载所有的类,这时候类的方法已经被还原。
其他关于反射所使用的方法,请参考文末github。

那么什么时候调用fartthread呢?
public final class ActivityThread extends ClientTransactionHandler {
 
     /**  Core implementation of activity launch. */
     private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
+        Log.e(TAG, "go into performLaunchActivity");
         ActivityInfo aInfo = r.activityInfo;
         if (r.packageInfo == null) {
             r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
@@ -2951,10 +2956,161 @@ public final class ActivityThread extends ClientTransactionHandler {
                     + ": " + e.toString(), e);
             }
         }
-
+        Log.e(TAG, "app name:" + r.packageInfo.getPackageName());
+        if (r.packageInfo.getPackageName().equals("com.example.jltxgcy.arttest")) { //在这里判断进程
+            ActivityThread.fartthread();
+        }
         return activity;
     }
}
原作者是在native层判断的进程,这里采用在ActivityThread的performLaunchActivity判断。
public final class DexFile {

    private Object mCookie;

    private static native void dumpMethodCode(Object methodid);
    private static native String[] getClassNameList(Object cookie);
    ....
}
调用getClassNameList(mCookie)来获取当前dex中的所有类名。
4、loadClassAndInvoke,首先通过loadClass来主动加载所有类,然后调用dumpMethodCode来进行脱壳,参数为Method或者Constructor对象。
这个有个重点我们的标题是《ART环境下基于主动调用的自动化脱壳方案》,这里主动调用就体现到这里了,loadClass。加壳程序hook了加载类的方法,当真正执行时加载类的时候会进行还原,这个加载类相当于隐式加载。我们这里loadClass是显示加载所有的类,这时候类的方法已经被还原。
其他关于反射所使用的方法,请参考文末github。

那么什么时候调用fartthread呢?
public final class ActivityThread extends ClientTransactionHandler {
 
     /**  Core implementation of activity launch. */
     private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
+        Log.e(TAG, "go into performLaunchActivity");
         ActivityInfo aInfo = r.activityInfo;
         if (r.packageInfo == null) {
             r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
@@ -2951,10 +2956,161 @@ public final class ActivityThread extends ClientTransactionHandler {
                     + ": " + e.toString(), e);
             }
         }
-
+        Log.e(TAG, "app name:" + r.packageInfo.getPackageName());
+        if (r.packageInfo.getPackageName().equals("com.example.jltxgcy.arttest")) { //在这里判断进程
+            ActivityThread.fartthread();
+        }
         return activity;
     }
}
原作者是在native层判断的进程,这里采用在ActivityThread的performLaunchActivity判断。
public final class ActivityThread extends ClientTransactionHandler {
 
     /**  Core implementation of activity launch. */
     private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
+        Log.e(TAG, "go into performLaunchActivity");
         ActivityInfo aInfo = r.activityInfo;
         if (r.packageInfo == null) {
             r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
@@ -2951,10 +2956,161 @@ public final class ActivityThread extends ClientTransactionHandler {
                     + ": " + e.toString(), e);
             }
         }
-
+        Log.e(TAG, "app name:" + r.packageInfo.getPackageName());
+        if (r.packageInfo.getPackageName().equals("com.example.jltxgcy.arttest")) { //在这里判断进程
+            ActivityThread.fartthread();
+        }
         return activity;
     }
}
原作者是在native层判断的进程,这里采用在ActivityThread的performLaunchActivity判断。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-1-7 18:28 被jltxgcy编辑 ,原因:
收藏
免费 10
支持
分享
最新回复 (32)
雪    币: 13096
活跃值: (4171)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
前排支持 地址没了?....
2020-1-7 18:23
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
3
xJJuno 前排支持 地址没了?....
正在上传。
2020-1-7 18:26
0
雪    币: 997
活跃值: (420)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
4
前排
2020-1-7 18:30
0
雪    币: 8266
活跃值: (4650)
能力值: ( LV8,RANK:134 )
在线值:
发帖
回帖
粉丝
5
看来你等不及了,本来打算新年大年30就会全部上传到github的,给大家作为新年礼物的。还有文中有部分讲的还不够细致,先是用loadclass加载类,虽然一部分的函数抽取的壳的实现在类加载后就已经恢复,但是事实上还有一些壳是在函数调用前甚至是在函数本身执行后才恢复,这里是主动调用的关键所在
2020-1-7 18:45
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
hanbingle 看来你等不及了[em_13],本来打算新年大年30就会全部上传到github的,给大家作为新年礼物的。还有文中有部分讲的还不够细致,先是用loadclass加载类,虽然一部分的函数抽取的壳的实现在类加 ...
期待大佬的权威源码。
2020-1-7 19:08
0
雪    币: 163
活跃值: (3072)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
jltxgcy 期待大佬的权威源码。[em_13]
等你的权威源码了
2020-1-7 19:40
0
雪    币: 657
活跃值: (68)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
8
谢谢大佬分享
2020-1-7 21:54
0
雪    币: 4468
活跃值: (1864)
能力值: ( LV12,RANK:209 )
在线值:
发帖
回帖
粉丝
9
hanbingle 看来你等不及了[em_13],本来打算新年大年30就会全部上传到github的,给大家作为新年礼物的。还有文中有部分讲的还不够细致,先是用loadclass加载类,虽然一部分的函数抽取的壳的实现在类加 ...
前排观望
2020-1-8 09:33
0
雪    币: 14642
活跃值: (5903)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
建议同时提供这三个文件下载:framework.jar、core-libart.jar、libart.so
免得每个人都去编译一下
最后于 2020-1-8 09:50 被tDasm编辑 ,原因:
2020-1-8 09:49
0
雪    币: 3429
活跃值: (1566)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
大佬牛逼
2020-1-8 10:05
0
雪    币: 28
活跃值: (489)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
谢谢大佬分享
2020-1-8 10:06
0
雪    币: 31
活跃值: (211)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
大佬牛逼,正好最近也在看这方便的东西,学习了
2020-1-8 10:31
0
雪    币: 2224
活跃值: (1063)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
大佬也是66666
2020-1-8 10:41
0
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
灬哈密瓜 大佬也是66666
66666666666
2020-1-8 10:46
0
雪    币: 208
活跃值: (258)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
支持分享
2020-1-8 11:14
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
感谢分享
2020-1-8 14:51
0
雪    币: 88
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
日常膜拜
2020-1-8 21:30
0
雪    币: 1759
活跃值: (2334)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
19
这个CodeItem()改为public,会不会让人可以据此检测到正在运行在脱壳系统中?
2020-1-9 09:53
0
雪    币: 1759
活跃值: (2334)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
20
只能移植到art下?dvm不能实现吗?
2020-1-9 09:54
0
雪    币: 8266
活跃值: (4650)
能力值: ( LV8,RANK:134 )
在线值:
发帖
回帖
粉丝
21
又见飞刀z 只能移植到art下?dvm不能实现吗?
FART是一个框架,虽然也支持dalvik,但是已经没有意义了
2020-1-9 12:49
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
hanbingle FART是一个框架,虽然也支持dalvik,但是已经没有意义了
呀呀呀,原作大佬来了
2020-1-9 14:53
0
雪    币: 4116
活跃值: (1034)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
23
膜拜大佬
2020-1-9 17:19
0
雪    币: 24478
活跃值: (62834)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
24
大佬!感谢分享!
2020-1-10 10:05
0
雪    币: 3
活跃值: (618)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
还是老哥的执行力高,之前我也想着这么搞,结果现在就开了个头,膜拜老哥
2020-1-10 15:03
0
游客
登录 | 注册 方可回帖
返回
//