bsdiff
包含两个程序:bsdiff (比较两个文件的二进制数据,生成差分包)与bspatch (合并旧的文件 与差分包,生成新的文件)。
bsdiff oldfile newfile patchfile
bspatch oldfile newfile patchfile
在Android中使用只需要使用bspatch就可以,就是调用main方法,我们可以将main方法改一个名字,然后调用就可以了传入
#include <jni.h>
#include <android/log.h>
extern "C" {
extern int executePatch(int argc, char *argv[]);
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_enjoy_dexdiff_BsPatchUtils_patch(JNIEnv *env, jclass clazz, jstring old_apk,
jstring new_apk, jstring patch_file) {
int args = 4;
char *argv[args];
argv[0] = "bspatch";
argv[1] = (char *) (env->GetStringUTFChars(old_apk, 0));
argv[2] = (char *) (env->GetStringUTFChars(new_apk, 0));
argv[3] = (char *) (env->GetStringUTFChars(patch_file, 0));
//此处executePathch()就是上面我们修改出的
int result = executePatch(args, argv);
env->ReleaseStringUTFChars(old_apk, argv[1]);
env->ReleaseStringUTFChars(new_apk, argv[2]);
env->ReleaseStringUTFChars(patch_file, argv[3]);
return result;
}
dex文件格式
dex文件是Android系统的可执行文件,包含应用程序的全部操du作指令以及运行时数据。 当java程序编译成class后,还需要使用dx工具将所有的class文件整合到一个dex文件,目的是其中各个类能够共享 数据,在一定程度上降低了冗余,同时也是文件结构更加经凑,实验表明,dex文件是传统jar文件大小的50%左右。
dex 文件可以分为3个模块,头文件、索引区、数据区。头文件概况的描述了整个 dex 文件的分布,包括每一个索 引区的大小跟偏移。索引区表示每个数据的标识,索引区主要是指向数据区的偏移。 1 我们可以使用16进制查看工具打开一个dex来同步分析。(建议使用010Editor)
大小端
文件一般使用小端字节序存储(Dex文件也不例外),网络传输一般使用大端字节序。
大端模式(Big-endian),是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址 中 。
小端模式(Little-endian),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址 中 。
假如有一个4字节的数据为 0x12 34 56 78 (十进制: 305419896 , 0x12 为高字节, 0x78 为低字节),若将其 存放于地址 0x1000 中:
内存地址 | 0x1000(低地址) | 0x1001 | 0x1002 | 0x1003(高地址) |
---|---|---|---|---|
大端模式 | 0x12(高字节) | 0x34 | 0x56 | 0x78(低字节) |
小端模式 | 0x78(低字节) | 0x56 | 0x34 | 0x12(高字节) |
头文件
整个dex文件以16进制打开,前112个字节为头文件数据。Header描述了 dex 文件信息,和其他各个区的索引。 此处数据,最开始为 dex_magic 魔数,数据为:
字段 | 字节数 | 说明 |
---|---|---|
dex | 3 | 文件格式:dex |
newLine | 1 | 换行:"\n" |
ver | 3 | 版本:035 |
zero | 1 | 无意义,00 |
uint为4字节数据
checksum: 文件校验码,使用 alder32 算法校验文件除去 maigc、checksum 外余下的所有文件区域,用于 检 查文件错误。
signature: 使用 SHA-1 算法 hash 除去 magic、checksum 和 signature 外余下的所有文件区域, 用于唯一 识别本文件 。
file_size: dex 文件大小
header_size: header 区域的大小,固定为 0x70
endian_tag: 大小端标签,dex 文件格式为小端,固定值为 0x12345678
map_off: map_item 的偏移地址,该 item 属于 data 区里的内容,值要大于等于 data_off 的大小,处于 dex 文件的末端。
dexdiff
dexDiff是微信结合Dex文件格式设计的一个专门针对Dex的差分算法。根据Dex的文件格式,对两个Dex中每一项 数据进行差分记录。整个实现过程其实很繁琐,我们以字符串StringIds区域的差分举例
优点:产生的差分包小!