【Android SDK程序逆向分析与破解系列】之四:Android可执行程序ODEX分析

作者:郭嘉
邮箱:[email protected]
博客:http://blog.csdn.net/allenwells
github:https://github.com/AllenWells

【Android SDK程序逆向分析与破解系列】章节索引

【Android SDK程序逆向分析与破解系列】之一:Android安装程序APK分析
【Android SDK程序逆向分析与破解系列】之二:Android可执行程序DEX分析(一)
【Android SDK程序逆向分析与破解系列】之三:Android可执行程序DEX分析(二)
【Android SDK程序逆向分析与破解系列】之四:Android可执行程序ODEX分析
【Android SDK程序逆向分析与破解系列】之五:Android APK的静态分析

ODEX(OptimizedDEX)表示经过优化的DEX文件

一 生成ODEX文件

ODEX文件有两种存在方式

  • 从APK程序中提取出来,与APK文件放在用一个目录中,文件后缀名为”.odex”的文件。这类ODEX文件多为Android ROM的系统程序。

  • dalvik-cache缓存文件,文件后缀为“.dex”,保存在cache/dalvik-cache目录下,保存形式为“apk路径@apk名@classes.dex”,比如“system@[email protected]@classes.dex”表示安装在system/app目录下的Calculator.apk程序的ODEX文件。

二 ODEX文件结构

ODEX文件可以理解为DEX文件的一个超集,具体的结构如下所示:

这里写图片描述

三 ODEX结构体

3.1 DexOptHeader结构体

DexOptHeader是ODEX文件的文件头

/*
 * Header added by DEX optimization pass.  Values are always written in
 * local byte and structure padding.  The first field (magic + version)
 * is guaranteed to be present and directly readable for all expected
 * compiler configurations; the rest is version-dependent.
 *
 * Try to keep this simple and fixed-size.
 */
struct DexOptHeader {
    u1  magic[8];           /* ODEX版本标识 */
    u4  dexOffset;          /* DEX文件头偏移 */
    u4  dexLength;          /* DEX文件总长度 */
    u4  depsOffset;         /* ODEX依赖库列表偏移 */
    u4  depsLength;         /* ODEX依赖库列表总长度 */
    u4  optOffset;          /* 辅助数据偏移 */
    u4  optLength;          /* 辅助数据总长度 */
    u4  flags;              /* 标志 */
    u4  checksum;           /* 依赖库与辅助数据的检验和 */

    /* pad for 64-bit alignment if necessary */
};

3.2 Dependences结构体

Dependences结构体并不会被加载进内存,它的结构如下所示:

struct Dependences{
    u4 modWhen;             /* 时间戳 */
    u4 crc;                 /* 检验 */
    u4 DALVIK_VM_BUILD;     /* Dalvik虚拟机版本号 */
    u4 numDeps;             /* 依赖库个数 */
    struct{
    u4 len;                 /* name字符串长度 */
    u1 name[len];           /* 依赖库名称 */
    kSHA1DigestLen signature;/* SHA-1哈希值 */
}table[numDeps];
};
  • modWhen:用来记录优化前classes.dex的时间戳。
  • crc:优化前classes.dex的crc校验值。
  • DALVIK_VM_BUILD:Dalvik虚拟机版本号,不同版本的系统定义不同,Android2.2.3:19,Android2.3.3-2.3.7:23,Android4.0-4.1:27。
  • numDeps:依赖库的个数。
  • table:table结构的连续个数是由numDeps字段决定的,每个table结构由3个字段组成,用来描述一个依赖库的文件信息。

Dependences结构体结构体的操作函数为DexPrepare.cpp的writeDependencies()函数,代码片段如下所示:

源码下载


/*
 * Write the dependency info to "fd" at the current file position.
 */
static int writeDependencies(int fd, u4 modWhen, u4 crc)
{
    u1* buf = NULL;
    int result = -1;
    ssize_t bufLen;
    ClassPathEntry* cpe;
    int numDeps;

    /*
     * Count up the number of completed entries in the bootclasspath.
     */
    numDeps = 0;
    bufLen = 0;
    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
        const char* cacheFileName =
            dvmPathToAbsolutePortion(getCacheFileName(cpe));
        assert(cacheFileName != NULL); /* guaranteed by Class.c */

        ALOGV("+++ DexOpt: found dep '%s'", cacheFileName);

        numDeps++;
        bufLen += strlen(cacheFileName) +1;
    }

    bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);

    buf = (u1*)malloc(bufLen);

    set4LE(buf+0, modWhen);
    set4LE(buf+4, crc);
    set4LE(buf+8, DALVIK_VM_BUILD);
    set4LE(buf+12, numDeps);

    // TODO: do we want to add dvmGetInlineOpsTableLength() here?  Won't
    // help us if somebody replaces an existing entry, but it'd catch
    // additions/removals.

    u1* ptr = buf + 4*4;
    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
        const char* cacheFileName =
            dvmPathToAbsolutePortion(getCacheFileName(cpe));
        assert(cacheFileName != NULL); /* guaranteed by Class.c */

        const u1* signature = getSignature(cpe);
        int len = strlen(cacheFileName) +1;

        if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
            ALOGE("DexOpt: overran buffer");
            dvmAbort();
        }

        set4LE(ptr, len);
        ptr += 4;
        memcpy(ptr, cacheFileName, len);
        ptr += len;
        memcpy(ptr, signature, kSHA1DigestLen);
        ptr += kSHA1DigestLen;
    }

    assert(ptr == buf + bufLen);

    result = sysWriteFully(fd, buf, bufLen, "DexOpt dep info");

    free(buf);
    return result;
}

四 DEX文件的验证和优化工具dexopt的工作过程

Dalvik虚拟机在加载一个DEX文件时,通过指定的验证和优化选项来调用dexopt工具来进行相应的验证和优化。

处理流程如下所示:

  1. classes.dex的处理函数是extractAndProcessZip()extractAndProcessZip()函数会陆续
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值