android apk 防止反编译技术第二篇-运行时修改Dalvik指令
来源:互联网 发布:海外代购近年数据 编辑:程序博客网 时间:2024/06/06 02:50
上一篇我们讲了apk防止反编译技术中的加壳技术,如果有不明白的可以查看我的上一篇博客http://my.oschina.net/u/2323218/blog/393372。接下来我们将介绍另一种防止apk反编译的技术-运行时修改字节码。这种方法是在工作中在实现app wrapping时,看到国外的一篇关于android 安全的介绍实现的并且独创。下面我们来介绍一下这种方法。
我们知道apk生成后所有的java生成的class文件都被dx命令整合成了一个classes.dex文件,当apk运行时dalvik虚拟机加载classes.dex文件并且用dexopt命令进行进一步的优化成odex文件。我们的方法就是在这个过程中修改dalvik指令来达到我们的目的。
一、dex文件格式
dex的文件格式通常有7个主要部分和数据區组成,格式如下:
header部分记录了主要的信息其他的部分只是索引,索引的内容存在data区域。
Header部分结构如下:
字段名称
偏移值
长度
描述
magic
0x0
8
'Magic'值,即魔数字段,格式如”dex/n035/0”,其中的035表示结构的版本。
checksum
0x8
4
校验码。
signature
0xC
20
SHA-1签名。
file_size
0x20
4
Dex文件的总长度。
header_size
0x24
4
文件头长度,009版本=0x5C,035版本=0x70。
endian_tag
0x28
4
标识字节顺序的常量,根据这个常量可以判断文件是否交换了字节顺序,缺省情况下=0x78563412。
link_size
0x2C
4
连接段的大小,如果为0就表示是静态连接。
link_off
0x30
4
连接段的开始位置,从本文件头开始算起。如果连接段的大小为0,这里也是0。
map_off
0x34
4
map数据基地址。
string_ids_size
0x38
4
字符串列表的字符串个数。
string_ids_off
0x3C
4
字符串列表表基地址。
type_ids_size
0x40
4
类型列表里类型个数。
type_ids_off
0x44
4
类型列表基地址。
proto_ids_size
0x48
4
原型列表里原型个数。
proto_ids_off
0x4C
4
原型列表基地址。
field_ids_size
0x50
4
字段列表里字段个数。
field_ids_off
0x54
4
字段列表基地址。
method_ids_size
0x58
4
方法列表里方法个数。
method_ids_off
0x5C
4
方法列表基地址。
class_defs_size
0x60
4
类定义类表中类的个数。
class_defs_off
0x64
4
类定义列表基地址。
data_size
0x68
4
数据段的大小,必须以4字节对齐。
data_off
0x6C
4
数据段基地址
dex与class文件相比的一个优势,就是将所有的常量字符串集统一管理起来了,这样就可以减少冗余,最终的dex文件size也能变小一些。详细的dex文件介绍就不说了,有兴趣的可以查看android 源码dalvik/docs目录下的dex-format.html文件有详细介绍。不过我记得在android4.0版本后就没有了这个文件。
根据上面的dex文件的格式结构,dalvik虚拟机运行dex文件执行的字节码就存在method_ids区域里面。我们查看dalvik虚拟机源码会有一个
struct DexCode {
u2 registersSize;
u2 insSize;
u2 outsSize;
u2 triesSize;
u4 debugInfoOff; /* file offset to debug info stream */
u4 insnsSize; /* size of the insns array, in u2 units */
u2 insns[1];
/* followed by optional u2 padding */
/* followed by try_item[triesSize] */
/* followed by uleb128 handlersSize */
/* followed by catch_handler_item[handlersSize] */
};
这样一个结构,这里的insns数组存放的就是dalvik的字节码。我们只要定位到相关类方法的DexCode数据段,即可通过修改insns数组,从而实现我们的目的。
二、odex文件格式
apk安装或启动时,会通过dexopt来将dex生成优化的odex文件。过程是将apk中的classes.dex解压后,用dexopt处理并保存为/data/dalvik-cache/data@app@<package-name>-X.apk@classes.dex文件。
odex文件结构如下:
从上图中我们发现dex文件作为优化后的odex的一部分,我们只需要从odex中找出dex的部分即可以了。
三、方法实现
要实现修改字节码,就需要先定位到想要修改得代码的位置,这就需要先解析dex文件。dex文件的解析在dalvik源码的dexDump.cpp给出了我们具体的实现,根据它的实现我们可以查找我们需要的类及方法。具体实现步骤如下:
(1) 找到我们apk生成的odex文件,获得odex文件在内存中的映射地址和大小。实现代码如下:
void
*base = NULL;
int
module_size = 0;
char
filename[512];
// simple test code here!
for
(
int
i=0; i<2; i++){
sprintf
(filename,
"/data/dalvik-cache/data@app@%s-%d.apk@classes.dex"
,
"com.android.dex"
, i+1);
base = get_module_base(-1, filename);
//获得odex文件在内存中的映射地址
if
(base != NULL){
break
;
}
}
module_size = get_module_size(-1, filename);
//获得odex文件大小
(2) 知道dex文件在odex中的偏移,以便解析dex文件。代码如下:
// search dex from odex
void
*dexBase = searchDexStart(base);
if
(checkDexMagic(dexBase) ==
false
){
ALOGE(
"Error! invalid dex format at: %p"
, dexBase);
return
;
}
(3) 找到dex偏移以后就可以解析dex文件,从而查找我们要进行替换的方法所在的类,然后在该类中找到该方法并返回该方法对应的DexCode结构体。函数实现如下:
static
const
DexCode *dexFindClassMethod(DexFile *dexFile,
const
char
*clazz,
const
char
*method)
{
DexClassData* classData = dexFindClassData(dexFile, clazz);
if
(classData == NULL)
return
NULL;
const
DexCode* code = dexFindMethodInsns(dexFile, classData, method);
if
(code != NULL) {
dumpDexCode(code);
}
return
code;
}
(4) 找到DexCode后就可以进行指令替换了。实现如下:
const
DexCode *code =
dexFindClassMethod(&gDexFile,
"Lcom/android/dex/myclass;"
,
"setflagHidden"
);
const
DexCode*code2 =
dexFindClassMethod(&gDexFile,
"Lcom/android/dex/myclass;"
,
"setflag"
);
// remap!!!!
if
(mprotect(base, module_size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0){
DexCode *pCode = (DexCode *)code2;
// Modify!
pCode->registersSize = code->registersSize;
for
(u4 k=0; k<code->insnsSize; k++){
pCode->insns[k] = code->insns[k];
}
mprotect(base, module_size, PROT_READ | PROT_EXEC);
}
注意:由于是在运行时修改的dalvik指令,这是进程的内存映射为只读的,所以需要调用mprote
- android apk 防止反编译技术第二篇-运行时修改Dalvik指令
- android apk 防止反编译技术第二篇-运行时修改Dalvik指令
- android apk 防止反编译技术第二篇-运行时修改Dalvik指令
- android apk 防止反编译技术第二篇-运行时修改Dalvik指令
- android apk 防止反编译技术第二篇-运行时修改Dalvik指令
- android apk 防止反编译技术第二篇-运行时修改Dalvik指令
- android apk 防止反编译技术第二篇-运行时修改字节码
- android apk 防止反编译技术第二篇-运行时修改字节码
- android apk 防止反编译技术第三篇-加密apk
- android apk 防止反编译技术第三篇-加密apk
- android apk 防止反编译技术第三篇-加密
- android apk 防止反编译技术第四篇-对抗JD-GUI
- android apk 防止反编译技术第四篇-对抗JD-GUI
- android apk 防止反编译技术第四篇-对抗JD-GUI
- android apk 防止反编译技术第四篇-对抗JD-GUI
- android apk 防止反编译技术第四篇-对抗JD-GUI
- android apk 防止反编译技术第五篇-完整性校验
- android apk 防止反编译技术第三篇-加密
- HTML5(二) canvas基础
- WordCount的MapReduce的实现
- 无名线段树2
- java泛型
- HDU 2076 夹角有多大(题目已修改,注意读题)
- android apk 防止反编译技术第二篇-运行时修改Dalvik指令
- 最近5年133个Java面试问题列表
- node与ES6系列3——generator对象
- android混淆去掉日志
- 从编译到制作固件
- Codeforces 616E Sum Of Reminders
- iOS应用生命周期相关内容
- node与ES6系列4——class
- jdk配置正确但是tomcat服务器启动时一闪而过