文档章节

android apk 防止反编译技术第二篇-运行时修改Dalvik指令

lonely1986
 lonely1986
发布于 2015/04/05 09:20
字数 1624
阅读 1.8W
收藏 37

上一篇我们讲了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

数据段基地址

 

dexclass文件相比的一个优势,就是将所有的常量字符串集统一管理起来了,这样就可以减少冗余,最终的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指令,这是进程的内存映射为只读的,所以需要调用mprotect函数将只读改为读写才能进行指令的修改。

 

         根据上面的讲述相信大家对运行时修改字节码的技术有了一定的了解,下一篇我们将讲解另一种android apk防止反编译技术,期待大家的捧场。如果对这篇讲的技术有任何疑问及想要获得这篇文章讲的技术的工程源码

    欢迎关注个人微信公众平台:程序员互动联盟(coder_online),扫一扫下方二维码或搜索微信号coder_online即可关注,我们可以在线交流。

© 著作权归作者所有

lonely1986
粉丝 110
博文 34
码字总数 8686
作品 0
海淀
私信 提问
加载中

评论(5)

麦向巅峰
但是odex仅存在于4.4以前,ART模式下dex被优化成oat文件就不适用了。
goolong
goolong
还是用C写的,
goolong
goolong
都涉及到了Android底层开发了 不是很懂
通付盾
通付盾
可转载到自己博客么
mgic
mgic
有点高深,收藏起来慢慢看。
如何防止Android应用代码被窃

上一篇我们讲了apk防止反编译技术中的加壳技术,如果有不明白的可以查看我的上一篇博客http://my.oschina.net/u/2323218/blog/393372。接下来我们将介绍另一种防止apk反编译的技术-运行时修改...

东辉在线
2015/04/05
516
0
android apk 自我保护技术-修改Dalvik指令

上一篇我们讲了apk防止反编译技术中的加壳技术,如果有不明白的可以查看我的上一篇博客http://my.oschina.net/u/2323218/blog/393372。接下来我们将介绍另一种防止apk反编译的技术-运行时修改...

lonely_online
2015/04/08
959
7
android apk 防止反编译技术第一篇-加壳技术

做android framework方面的工作将近三年的时间了,现在公司让做一下android apk安全方面的研究,于是最近就在网上找大量的资料来学习。现在将最近学习成果做一下整理总结。学习的这些成果我会...

lonely1986
2015/03/29
4.2W
40
浅谈Android应用保护(一):Android应用逆向的基本方法

对于未进行保护的Android应用,有很多方法和思路对其进行逆向分析和攻击。使用一些基本的方法,就可以打破对应用安全非常重要的机密性和完整性,实现获取其内部代码、数据,修改其代码逻辑和...

阿里聚安全
2016/04/15
356
1
android apk 防止反编译技术第二篇-运行时修改Dalvik指令(转)

接下来我们将介绍另一种防止apk反编译的技术-运行时修改字节码。这种方法是在工作中在实现app wrapping时,看到国外的一篇关于android 安全的介绍实现的并且独创。下面我们来介绍一下这种方法...

我是IT码农
2015/05/25
107
0

没有更多内容

加载失败,请刷新页面

加载更多

微信-公众号自定义微信菜单二次开发

1.开发 <基本配置< 服务器配置 服务器地址(URL) :接收回调事件本系统接口(微信业务回调入口(用户关注,取消关注、发消息等) 令牌(Token) :wx.callback.token,本系统定义的,开发时会用到...

Shingfi
5分钟前
22
0
「网易官方」极客战记(codecombat)攻略-地牢-严酷考验 B

简介: 这一关在while-true循环内只需要4条命令。 默认代码 # 使用你刚学到的技能击败那些食人魔。 # 记住:打败食人魔矮人需要两次攻击。 概览 有了循环和变量这些利器,解决所有这些食人魔...

极客战记
5分钟前
45
0
本地DOCKER删除镜像时报错解决办法

1.报错: C:\Users\hongcq>docker rmi 6bef6f0a19bcError response from daemon: conflict: unable to delete 6bef6f0a19bc (must be forced) - image is being used by stopped container......

楚番
18分钟前
23
0
分享Linux系统快速入门法

相信看到这篇文章的你一定是想要学习Linux,或者已经在学习Linux的人了,那我们就可以一起探讨一下,学习Linux如何快速入门呢? 首先,希望大家弄清楚自己为什么要学习Linux,有的人是因为兴...

linuxprobe2020
23分钟前
35
0
压测中测量异步写入接口的延迟

在服务端性能优化的时候,有一种方案叫 “异步写入”。就是把本来要写入数据库的功能放到异步来做,跟异步查询转同步的区别在于,异步查询是要等结果的,而异步写入则可以不等返回结果,甚至...

八音弦
28分钟前
54
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部