Android安全–从源码看Dex Dump于dvmDexFileOpenPartial原理

很多脱壳教程里面经常看到在dvmDexFileOpenPartial这个函数下断点,但是为什么在这个函数下断点就能把dex dump下来呢,下面从源码来看看dex的优化流程。

源码传送门:http://androidxref.com/4.4_r1/xref/dalvik/dexopt/OptMain.cpp

OptMain中的main函数就是优化dex的原始入口:

int main(int argc, char* const argv[])
{
    set_process_name(“dexopt”);

    setvbuf(stdout, NULL, _IONBF, 0);

    if (argc > 1) {
        if (strcmp(argv[1], “–zip”) == 0)
            return fromZip(argc, argv);
        else if (strcmp(argv[1], “–dex”) == 0)
            return fromDex(argc, argv);
        else if (strcmp(argv[1], “–preopt”) == 0)
            return preopt(argc, argv);
    }

    fprintf(stderr,
        “Usage:\n\n”
        “Short version: Don’t use this.\n\n”
        “Slightly longer version: This system-internal tool is used to\n”
        “produce optimized dex files. See the source code for details.\n”);

    return 1;
}

这里分别对三种不同类型的文件做不同的处理,跟进fromdex函数看看对dex是如何处理的。

static int fromDex(int argc, char* const argv[])
{
…….
if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
        ALOGE(“VM init failed”);
        goto bail;
    }

    vmStarted = true;

    /* do the optimization */
    if (!dvmContinueOptimization(fd, offset, length, debugFileName,
            modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
    {
        ALOGE(“Optimization failed”);
        goto bail;
    }
…….
}

首先初始化虚拟机,然后调用dvmContinueOptimization函数,继续跟进:

bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
{
…….
/*
         * Rewrite the file.  Byte reordering, structure realigning,
         * class verification, and bytecode optimization are all performed
         * here.
         *
         * In theory the file could change size and bits could shift around.
         * In practice this would be annoying to deal with, so the file
         * layout is designed so that it can always be rewritten in place.
         *
         * This creates the class lookup table as part of doing the processing.
         */
        success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
                    doVerify, doOpt, &pClassLookup, NULL);

        if (success) {
            DvmDex* pDvmDex = NULL;
            u1* dexAddr = ((u1*) mapAddr) + dexOffset;

            if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
                ALOGE(“Unable to create DexFile”);
                success = false;
            } else {
                /*
                 * If configured to do so, generate register map output
                 * for all verified classes.  The register maps were
                 * generated during verification, and will now be serialized.
                 */
                if (gDvm.generateRegisterMaps) {
                    pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
                    if (pRegMapBuilder == NULL) {
                        ALOGE(“Failed generating register maps”);
                        success = false;
                    }
                }

                DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
                updateChecksum(dexAddr, dexLength, pHeader);

                dvmDexFileFree(pDvmDex);
            }
        }
…….
}

这个函数对Dex文件做了一些优化(字节重排序,结构对齐,字节优化等),然后重新写入Dex文件,如果优化重写成功就调用dvmDexFileOpenPartial,这个函数的第一个参数就是dex文件的起始地址,第二个参数是dex的长度,继续跟进:

/*
* Create a DexFile structure for a “partial” DEX.  This is one that is in
* the process of being optimized.  The optimization header isn’t finished
* and we won’t have any of the auxillary data tables, so we have to do
* the initialization slightly differently.
*
* Returns nonzero on error.
*/
int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
{
    DvmDex* pDvmDex;
    DexFile* pDexFile;
    int parseFlags = kDexParseDefault;
    int result = -1;

    /* — file is incomplete, new checksum has not yet been calculated
    if (gDvm.verifyDexChecksum)
        parseFlags |= kDexParseVerifyChecksum;
    */

    pDexFile = dexFileParse((u1*)addr, len, parseFlags);
    if (pDexFile == NULL) {
        ALOGE(“DEX parse failed”);
        goto bail;
    }
    pDvmDex = allocateAuxStructures(pDexFile);
    if (pDvmDex == NULL) {
        dexFileFree(pDexFile);
        goto bail;
    }

    pDvmDex->isMappedReadOnly = false;
    *ppDvmDex = pDvmDex;
    result = 0;

bail:
    return result;
}

里面调用了dexFileParse来具体解析Dex文件。

所以断点在这个地方就能获取加载的dex文件。

本文链接:http://www.alonemonkey.com/load-dex-source.html