Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函数读取 DEX 文件 )(代

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函数读取 DEX 文件 )(代相关的知识,希望对你有一定的参考价值。

前言


上一篇博客 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | 查找 DexFile 对应的C代码 | dalvik_system_DexFile.cpp 分析 ) 中 , dalvik_system_DexFile.cppDalvik_dalvik_system_DexFile_openDexFileNative() 方法中 , 调用了 RawDexFile.cpp 中的 dvmRawDexFileOpen() 方法 ;





一、RawDexFile.cpp 中 dvmRawDexFileOpen() 方法分析



调用 open 函数 以只读形式 , 打开了 DEX 文件 ;

    dexFd = open(fileName, O_RDONLY);

校验 DEX 文件 ;

verifyMagicAndGetAdler32(dexFd, &adler32) < 0

调用 DexPrepare.cpp 中的 dvmOptimizeDexFile() 函数 , 优化 DEX 文件 ;

            result = dvmOptimizeDexFile(optFd, dexOffset, fileSize,
                fileName, modTime, adler32, isBootstrap);

源码示例 :

/*
 * 打开一个未优化的 DEX 文件.
 */

/* 请参阅页眉中的文档注释. */
int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
    RawDexFile** ppRawDexFile, bool isBootstrap)

    /*
     * TODO: 这复制了JarFile.c 中 dvmJarFileOpen() 的大量代码。这应该被重构。
     */

    DvmDex* pDvmDex = NULL;
    char* cachedName = NULL;
    int result = -1;
    int dexFd = -1;
    int optFd = -1;
    u4 modTime = 0;
    u4 adler32 = 0;
    size_t fileSize = 0;
    bool newFile = false;
    bool locked = false;

	// 调用 open 函数 以只读形式 , 打开了 DEX 文件
    dexFd = open(fileName, O_RDONLY);
    if (dexFd < 0) goto bail;

    /* If we fork/exec into dexopt, don't let it inherit the open fd. */
    dvmSetCloseOnExec(dexFd);

	// 校验 DEX 文件 
    if (verifyMagicAndGetAdler32(dexFd, &adler32) < 0) 
        ALOGE("Error with header for %s", fileName);
        goto bail;
    

    if (getModTimeAndSize(dexFd, &modTime, &fileSize) < 0) 
        ALOGE("Error with stat for %s", fileName);
        goto bail;
    

	/*
	 * 查看缓存的文件是否匹配。如果是这样,optFd将成为一个参考
	 * 到缓存文件,并将被查找到刚刚超过“opt”
	 * 标题。
	 */

    if (odexOutputName == NULL) 
    	// 优化的过程 
        cachedName = dexOptGenerateCacheFileName(fileName, NULL);
        if (cachedName == NULL)
            goto bail;
     else 
        cachedName = strdup(odexOutputName);
    

    ALOGV("dvmRawDexFileOpen: Checking cache for %s (%s)",
            fileName, cachedName);

    optFd = dvmOpenCachedDexFile(fileName, cachedName, modTime,
        adler32, isBootstrap, &newFile, /*createIfMissing=*/true);

    if (optFd < 0) 
        ALOGI("Unable to open or create cache for %s (%s)",
                fileName, cachedName);
        goto bail;
    
    locked = true;

    /*
     * 如果optFd指向一个新文件(因为没有缓存
     * 版本,或缓存的版本已过时),生成
     * 优化的DEX。返回的文件描述符仍处于锁定状态,
     * 并定位在刚好超过优化标题的位置。
     */
    if (newFile) 
        u8 startWhen, copyWhen, endWhen;
        bool result;
        off_t dexOffset;

        dexOffset = lseek(optFd, 0, SEEK_CUR);
        result = (dexOffset > 0);

        if (result) 
            startWhen = dvmGetRelativeTimeUsec();
            result = copyFileToFile(optFd, dexFd, fileSize) == 0;
            copyWhen = dvmGetRelativeTimeUsec();
        

        if (result) 
            result = dvmOptimizeDexFile(optFd, dexOffset, fileSize,
                fileName, modTime, adler32, isBootstrap);
        

        if (!result) 
            ALOGE("Unable to extract+optimize DEX from '%s'", fileName);
            goto bail;
        

        endWhen = dvmGetRelativeTimeUsec();
        ALOGD("DEX prep '%s': copy in %dms, rewrite %dms",
            fileName,
            (int) (copyWhen - startWhen) / 1000,
            (int) (endWhen - copyWhen) / 1000);
    

	/*
	 * 映射缓存的版本。这会立即倒带fd,因此
	 * 不需要在任何地方寻找。
	 */
    if (dvmDexFileOpenFromFd(optFd, &pDvmDex) != 0) 
        ALOGI("Unable to map cached %s", fileName);
        goto bail;
    

    if (locked) 
        /* unlock the fd */
        if (!dvmUnlockCachedDexFile(optFd)) 
            /* uh oh -- this process needs to exit or we'll wedge the system */
            ALOGE("Unable to unlock DEX file");
            goto bail;
        
        locked = false;
    

    ALOGV("Successfully opened '%s'", fileName);

    *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
    (*ppRawDexFile)->cacheFileName = cachedName;
    (*ppRawDexFile)->pDvmDex = pDvmDex;
    cachedName = NULL;      // don't free it below
    result = 0;

bail:
    free(cachedName);
    if (dexFd >= 0) 
        close(dexFd);
    
    if (optFd >= 0) 
        if (locked)
            (void) dvmUnlockCachedDexFile(optFd);
        close(optFd);
    
    return result;

以上是关于Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函数读取 DEX 文件 )(代的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmContinueOptimizati() 函数分析 )

Android 逆向整体加固脱壳 ( DEX 优化流程分析 | dvmDexFileOpenPartial | dexFileParse | 脱壳点 | 获取 dex 文件在内存中的首地址 )(代码片

Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 构造函数分析 | makeDexElements 函数分析 )

Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexFile loadDexFile 函数 | 构造函数 | openDexFile 函数 )(代码片

Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 中根据 File 加载 DexFile | loadDexFile 分析 )(代

Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函数读取 DEX 文件 )(代