http://blog.itpub.net/31562043/viewspace-2284074/
https://blog.csdn.net/tabactivity/article/details/50435140

https://blog.csdn.net/chenya866/article/details/79355156 (分析了各大加密产品的共性)

https://blog.csdn.net/androidsecurity/article/details/8678399
https://blog.csdn.net/zzx410527/article/details/51673908 (不落地式加载dex)

最新各大apk加固特征库
https://blog.csdn.net/g5703129/article/details/85054405

通过给ClassLoader加日志分析APK加固原理

1.给各个ClassLoader加上日志

在android4.4源码里我在DexClassLoader、BaseDexClassLoader、ClassLoader均加了日志,所有的地方都要将dexPath判断一下再输出日志,否则系统无法正常启动。
加日志的目的:如果360使用了自定义的ClassLoader,就能知道。
- ClassLoader
源码目录1:libcore/libdvm/src/main/java/java/lang
源码目录2:libcore/libart/src/main/java/java/lang
编译目录:libcore

重载了一个dexPath的构造方法,给BaseDexClassLoader调用,两个目录的ClassLoader都要修改。

    /**
     * CZ define
     * @param parentLoader
     * @param dexPath
     */
    protected ClassLoader(ClassLoader parentLoader,String dexPath) {
        this(parentLoader, false);
        if(dexPath.startsWith("/data/app/")){
            Logger logger = Logger.getLogger("CZLogQiHu4444444");
            logger.warning("ClassLoader: " + ",dexPath = " + dexPath + ",name = " + getClass().getName());
        }
    }
  • BaseDexClassLoader
    源码目录:libcore/dalvik/src/main/java/dalvik/system
    编译目录:libcore
  public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(parent,dexPath);
        //super(parent);
        this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);

        if(dexPath.startsWith("/data/app/")){
            Logger logger = Logger.getLogger("CZLogQiHu111");
            logger.warning("BaseDexClassLoader: " + ",dexPath = " + dexPath  + "\npathList = " + pathList + ",name = " + getClass().getName());
        }

    }
  • DexClassLoader
    源码目录:libcore/dalvik/src/main/java/dalvik/system
    编译目录:libcore
  public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
     if(dexPath.startsWith("/data/app/")){
            Logger logger = Logger.getLogger("CZLogQiHu2222");
            logger.warning("DexClassLoader: " + ",dexPath = " + dexPath + ",optimizedDirectory = " + optimizedDirectory +
        ",libraryPath = " + libraryPath + ",name = " + getClass().getName()
        );
        }
    }

2.给DexFile相关类加上日志

  • DexFile.java
    源码目录:libcore/dalvik/src/main/java/dalvik/system
    编译目录:libcore
    static public DexFile loadDex(String sourcePathName, String outputPathName,
        int flags) throws IOException {

        /*
         * TODO: we may want to cache previously-opened DexFile objects.
         * The cache would be synchronized with close().  This would help
         * us avoid mapping the same DEX more than once when an app
         * decided to open it multiple times.  In practice this may not
         * be a real issue.
         */
        log("DexFile loadDex:sourcePathName = " + sourcePathName + ",outputPathName = " + outputPathName);
        return new DexFile(sourcePathName, outputPathName, flags);
    }
  private DexFile(String sourceName, String outputName, int flags) throws IOException {
        if (outputName != null) {
            try {
                String parent = new File(outputName).getParent();
                if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
                    throw new IllegalArgumentException("Optimized data directory " + parent
                            + " is not owned by the current user. Shared storage cannot protect"
                            + " your application from code injection attacks.");
                }
            } catch (ErrnoException ignored) {
                // assume we'll fail with a more contextual error later
            }
        }
    if(outputName == null ){
      log("DexFile created here");
    }

        mCookie = openDexFile(sourceName, outputName, flags);
        mFileName = sourceName;
        guard.open("close");
        //System.out.println("DEX FILE cookie is " + mCookie);
    }
    private static int openDexFile(String sourceName, String outputName,
        int flags) throws IOException {

    log("DexFile openDexFile,sourceName = " + sourceName + ",outputName = " + outputName);
        return openDexFileNative(new File(sourceName).getCanonicalPath(),
                                 (outputName == null) ? null : new File(outputName).getCanonicalPath(),
                                 flags);
    }
  • dalvik_system_DexFile.cpp
    源码目录:dalvik/vm/native
    编译目录:dalvik/vm
static void Dalvik_dalvik_system_DexFile_openDexFileNative(const u4* args,
    JValue* pResult)
{
    ALOGE("CZLog Dalvik_dalvik_system_DexFile_openDexFileNative");
    StringObject* sourceNameObj = (StringObject*) args[0];
    StringObject* outputNameObj = (StringObject*) args[1];
    DexOrJar* pDexOrJar = NULL;
    JarFile* pJarFile;
    RawDexFile* pRawDexFile;
    char* sourceName;
    char* outputName;

    if (sourceNameObj == NULL) {
        dvmThrowNullPointerException("sourceName == null");
        RETURN_VOID();
    }

    sourceName = dvmCreateCstrFromString(sourceNameObj);
    ALOGE("CZLog from dvmCreateCstrFromString sourceName%s",sourceName);
    if (outputNameObj != NULL)
        outputName = dvmCreateCstrFromString(outputNameObj);
    else
        outputName = NULL;
static void addToDexFileTable(DexOrJar* pDexOrJar) {
    ALOGE("CZLog addToDexFileTable");

3.安装一个普通的没有加固的app(直接从as上run)

开机首次安装应用,会先启动系统的两个系统应用pm和am(as上run才有这个日志)。
pm

E/dalvikvm( 2201): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative

E/dalvikvm( 2201): CZLog from dvmCreateCstrFromString sourceName/system/framework/pm.jar

E/dalvikvm( 2201): Couldn't open /system/framework/pm.odex: No such file or directory

E/dalvikvm( 2201): dvmJarFileOpen: Checking cache for /system/framework/pm.jar (/data/dalvik-cache/system@framework@pm.jar@classes.dex)

E/dalvikvm( 2201): Successfully opened 'classes.dex' in '/system/framework/pm.jar'

E/dalvikvm( 2201): Opening DEX file '/system/framework/pm.jar' (Jar)

E/dalvikvm( 2201): CZLog addToDexFileTable

am

E/dalvikvm( 2259): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative

E/dalvikvm( 2259): CZLog from dvmCreateCstrFromString sourceName/system/framework/am.jar

E/dalvikvm( 2259): Couldn't open /system/framework/am.odex: No such file or directory

E/dalvikvm( 2259): dvmJarFileOpen: Checking cache for /system/framework/am.jar (/data/dalvik-cache/system@framework@am.jar@classes.dex)

E/dalvikvm( 2259): Successfully opened 'classes.dex' in '/system/framework/am.jar'

E/dalvikvm( 2259): Opening DEX file '/system/framework/am.jar' (Jar)

E/dalvikvm( 2259): CZLog addToDexFileTable

然后就是我安装的应用的日志:

W/CZLogQiHu4444444( 2275): ClassLoader: ,dexPath = /data/app/com.example.jni02-1.apk,name = dalvik.system.PathClassLoader

W/CZLogXXX( 2275): DexFile openDexFile,sourceName = /data/app/com.example.jni02-1.apk,outputName = null

E/dalvikvm( 2275): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative

E/dalvikvm( 2275): CZLog from dvmCreateCstrFromString sourceName/data/app/com.example.jni02-1.apk

E/dalvikvm( 2275): Couldn't open /data/app/com.example.jni02-1.odex: No such file or directory

E/dalvikvm( 2275): dvmJarFileOpen: Checking cache for /data/app/com.example.jni02-1.apk (/data/dalvik-cache/data@app@com.example.jni02-1.apk@classes.dex)

E/dalvikvm( 2275): Successfully opened 'classes.dex' in '/data/app/com.example.jni02-1.apk'

E/dalvikvm( 2275): Opening DEX file '/data/app/com.example.jni02-1.apk' (Jar)

E/dalvikvm( 2275): CZLog addToDexFileTable

W/CZLogQiHu111( 2275): BaseDexClassLoader: ,dexPath = /data/app/com.example.jni02-1.apk

W/CZLogQiHu111( 2275): pathList = DexPathList[[zip file "/data/app/com.example.jni02-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.jni02-1, /vendor/lib, /system/lib]],name = dalvik.system.PathClassLoader

https://blog.csdn.net/black_dreamer/article/details/81665728
所以,apk 安装时,系统会使用 PathClassLoader 来加载apk文件中的dex

4.安装加固的app

第一部分:加载壳dex
壳apk执行普通apk的加载流程

I/ActivityManager(  753): Start proc com.chinalwb.are.demo for activity com.chinalwb.are.demo/.IndexActivity: pid=2485 uid=10073 gids={50073, 1028, 1015, 3003}

W/CZLogQiHu4444444( 2485): ClassLoader: ,dexPath = /data/app/com.chinalwb.are.demo-1.apk,name = dalvik.system.PathClassLoader

W/CZLogXXX( 2485): DexFile openDexFile,sourceName = /data/app/com.chinalwb.are.demo-1.apk,outputName = null

E/dalvikvm( 2485): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative

E/dalvikvm( 2485): CZLog from dvmCreateCstrFromString sourceName/data/app/com.chinalwb.are.demo-1.apk

E/dalvikvm( 2485): Couldn't open /data/app/com.chinalwb.are.demo-1.odex: No such file or directory

E/dalvikvm( 2485): dvmJarFileOpen: Checking cache for /data/app/com.chinalwb.are.demo-1.apk (/data/dalvik-cache/data@app@com.chinalwb.are.demo-1.apk@classes.dex)

E/dalvikvm( 2485): Successfully opened 'classes.dex' in '/data/app/com.chinalwb.are.demo-1.apk'

E/dalvikvm( 2485): Opening DEX file '/data/app/com.chinalwb.are.demo-1.apk' (Jar)

E/dalvikvm( 2485): CZLog addToDexFileTable

W/CZLogQiHu111( 2485): BaseDexClassLoader: ,dexPath = /data/app/com.chinalwb.are.demo-1.apk

W/CZLogQiHu111( 2485): pathList = DexPathList[[zip file "/data/app/com.chinalwb.are.demo-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.chinalwb.are.demo-1, /vendor/lib, /system/lib]],name = dalvik.system.PathClassLoader

D/dalvikvm( 2485): DexOpt: couldn't find static field Landroid/os/Build;.SUPPORTED_32_BIT_ABIS

W/dalvikvm( 2485): VFY: unable to resolve static field 4 (SUPPORTED_32_BIT_ABIS) in Landroid/os/Build;

D/dalvikvm( 2485): VFY: replacing opcode 0x62 at 0x0004

D/dalvikvm( 2485): Trying to load lib /data/data/com.chinalwb.are.demo/.jiagu/libjiagu837801602.so 0x42628f50

D/dalvikvm( 2485): Added shared lib /data/data/com.chinalwb.are.demo/.jiagu/libjiagu837801602.so 0x42628f50

E/dalvikvm( 2485): ERROR: couldn't find native method

E/dalvikvm( 2485): Requested: Lcom/stub/StubApp;.interface7:(Landroid/app/Application;Landroid/content/Context;)Z

第二部分:再次加载了一次dex
上面的日志里最后一行
```Requested: Lcom/stub/StubApp;.interface7:(Landroid/app/Application;Landroid/content/Context;)Z```应该就是360解密壳内部真正的地方
然后它没有自定义任何的ClassLoader,而是直接使用DexFile.java的loadDex方法加载dex。

W/CZLogXXX( 2485): DexFile loadDex:sourcePathName = /data/app/com.chinalwb.are.demo-1.apk,outputPathName = null

W/CZLogXXX( 2485): DexFile created here

W/CZLogXXX( 2485): DexFile openDexFile,sourceName = /data/app/com.chinalwb.are.demo-1.apk,outputName = null

E/dalvikvm( 2485): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative

E/dalvikvm( 2485): CZLog from dvmCreateCstrFromString sourceName/data/app/com.chinalwb.are.demo-1.apk

E/dalvikvm( 2485): Couldn't open /data/app/com.chinalwb.are.demo-1.odex: No such file or directory

E/dalvikvm( 2485): dvmJarFileOpen: Checking cache for /data/app/com.chinalwb.are.demo-1.apk (/data/dalvik-cache/data@app@com.chinalwb.are.demo-1.apk@classes.dex)

E/dalvikvm( 2485): Successfully opened 'classes.dex' in '/data/app/com.chinalwb.are.demo-1.apk'

E/dalvikvm( 2485): Opening DEX file '/data/app/com.chinalwb.are.demo-1.apk' (Jar)

E/dalvikvm( 2485): CZLog addToDexFileTable

注意
```E/dalvikvm( 2094): Opening DEX file '/data/app/com.chinalwb.are.demo-1.apk' (Jar)```这行日志,这是系统自己打的日志。
![image.png](https://upload-images.jianshu.io/upload_images/18328858-1f6c36427f019279.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
调用了```dvmJarFileOpen```方法来打开dex
这个方法的实现不在dalvik_system_DexFile.cpp文件,通过```grep 'dvmJarFileOpen' -Inrw --include=*.cpp```找到方法的实现位置

  • JarFile.cpp
    源码目录:dalvik/vm
    编译目录:dalvik/vm
    关于dvmJarFileOpen这个方法的资料:
    这个方法真的十分重要!!!!!!
    https://bbs.pediy.com/thread-209631.htm
    https://blog.csdn.net/mengkevin/article/details/74177927
    JarFile.cpp的日志都是用ALOGV来打印的,logcat捕捉不到,改用ALOGE。

  • /data/dalvik-cache目录下的dex

    ```dvmJarFileOpen: Checking cache for /data/app/com.chinalwb.are.demo-1.apk (/data/dalvik-cache/data@app@com.chinalwb.are.demo-1.apk@classes.dex)```这行日志,这里的```/data/dalvik-cache/data@app@com.chinalwb.are.demo-1.apk@classes.dex```dex是不是呢?
    pull出来,无法反编译出smali,下面博客说明了这个dex不是源程序的dex。
    [https://blog.csdn.net/u010144805/article/details/78894321](https://blog.csdn.net/u010144805/article/details/78894321)
    ##5.360解密后的dex
    通过上面详细的日志分析可知,360加固后的app进行了2次dex加载,那么真正的源程序的dex是否能拿到呢?

看JarFile.cpp的dvmDexFileOpenFromFd这个方法

    /*
     * Map the cached version.  This immediately rewinds the fd, so it
     * doesn't have to be seeked anywhere in particular.
     */
    if (dvmDexFileOpenFromFd(fd, &pDvmDex) != 0) {
        ALOGI("Unable to map %s in %s", kDexInJarName, fileName);
        goto bail;
    }

通过
```grep 'dvmDexFileOpenFromFd' -Inrw --include=*.cpp```搜索这个方法的实际定义位置,发现位于DvmDex.cpp。
- DvmDex.cpp
源码目录:dalvik/vm
编译目录:dalvik/vm
![dvmdex.jpg](https://upload-images.jianshu.io/upload_images/18328858-10650323742ef5a0.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

通过
```grep 'dexFileParse' -Inrw --include=*.cpp```搜索出dexFileParse所在的文件位置,为DexFile.cpp。
- DexFile.cpp。
源码目录:dalvik/libdex
编译目录:dalvik/libdex
关于dexFileParse方法我就不再细讲了,因为有了pDexFile就能搞到dex。

用pDexFile将dex搞出来看看

参考https://bbs.pediy.com/thread-218891.htm这位大佬。


0 条评论

发表回复

您的电子邮箱地址不会被公开。