#### **概述**
我们的APK实际上就是一个ZIP压缩文件,里面包含有一个classes.dex,我们编译后生成的程序代码就全部在那里了,通过apktool等工具可以轻松地将它们反编译成smali代码。有了这些反编译出来的smali代码之后,我们就可以轻松地了解别人的APK使用的一些技术或者直接修改别人的APK。由于这些APK反编译工具的存在,我们迫切地希望能有方法去防止别人来反编译我们的APK,从而保护自己的商业机密和利益。
主要讲了三种APK防反编译技术:
* 添加非法指令;
* 隐藏敏感代码
* 伪APK加密技术。
此外,还探讨了更高级的Dex和Native加壳技术来防止别人反编译我们的APK。
#### **添加非法指令**
* Step 1: 在APK包含一个无关类Bomb,该类有一个成员函数drop
* Step 2: 将APK的classes.dex解压出来,并且用dexdump进行反编译,找到Bomb.drop在classes.dex的偏移
* Step 3: 用vim以二进制方式打开classes.dex,转到Bomb.drop的偏移处,将前两个字节修改为FF FF(非法指令)
* Step 4: 重新打包和签名APK,用adb install命令安装,日志提示checksum不一致
> 注:
> vim编辑二进制文件
> 打开文件:`vim -b <file>`
> 编辑文件::%!xxd
> 编辑完成::%!xxd –r
> 保存文件::wq
> dexdump反编译APK
> `dexdump -d <classes.dex>`
> dexdump验证checksum
>` dexdump -c <classes.dex>`
> apktool反编译APK
> `apktool d <apkfile> <dir>`
* Step 5: 用dexdump验证APK的checksum,并且将正确的checksum替换原classes.dex的checksum
* Step 6: 重新打包和签名APK,用adb install安装,DONE
#### **隐藏敏感代码**
* Step 1:在APK包含一个无关类Bomb,该类有一个成员函数drop,前面留有18个字节的垃圾指令
* Step 2:将APK的classes.dex解压出来,并且用dexdump进行反编译,找到Bomb.drop在classes.dex的偏移
* Step 3:用vim以二进制方式打开classes.dex,转到Bomb.drop的偏移处,将前18个字节修改为以下指令
![](https://box.kancloud.cn/1dcfa149e9b25b7dc9456d695a4c540c_673x60.png)
> 注:第一条指令3200 0900表示向前跳9个code unit,一个code unit占2个字节,即向前跳18个字节,从3200 0900的偏移向前算,刚好就是下一条指令fill-array-data的payload偏移处,即hhhh hhhh后面那个字节
> 第二条指令中的00000005表示其payload位于5个code uint之后,即10个字节之后,即hhhh hhhh开始的那个字节
* Step 4: 用dexdump查看classes.dex的头部信息,找到class_def的偏移,以及Bomb类的class index
* Step 5: class_def的偏移,加上Bomb类的class index乘以32的积,即可得到用来描述Bomb类的class_def结构体偏移,再往前4个字节,即为其access_flags,将它的第16位设置为1,一般就是设置为0x10001,也就是将0100 0000设置为0100 0100,这样可以将Bomb类设置为已验证
> 注:用dexdump -f命令查看classes.dex的头部信息
* Step 6: 用dexdump验证APK的checksum,并且将正确的checksum替换原classes.dex的checksum
* Step 7: 重新打包和签名APK,用adb install安装,DONE
#### **伪APK加密技术**
* ZIP中的每一个文件都有一个2字节大小的全局方式位标记,其中第0位表示是否加密
* 如果ZIP中的一个文件标志为加密,那么在解压时,就需要指定解压密码
* APK默认都是不加密的,也就是APK在安装解压时,它里面的文件的加密位标志都会被忽略
* Apktool发现APK是加密的时候,会抛出一个异常出来
利用上述差异,就可以给APK设置一个加密标志,但不对其进行加密,从而阻止Apktool反编译
#### **总结**
* APK在安装时,会对APK进行验证,主要是checksum验证和指令合法性验证
* 安装通过验证的APK会被标记为已验证,并且会被优化
* 安装没有通过验证的APK仍然会被成功安装,但是它会被标记为未验证
* 未验证的APK的某个类在被加载时,会被验证,一旦验证失败,就会抛出异常
* 反编译工具会对APK的所有类进行验证,不管这个类安装后会不会被加载,一旦验证不通过,就会抛出异常
* 根据以上的APK安装、验证和加载流程,就可以通过以下两个方法来阻止反编译:
* 包含一个有非法指令(不能执行)的类,但是这个类保证永远不会被加载
* 包含一个有非法指令(能执行)的类,同时将该类预先设置为已验证的
#### **思考**
* 反编译工具,如Apktool,采用的是线性扫描算法来分析指令流,当遇到非法指令时,就会异常退出
* 如果遇到非法指令只是简单忽略,那么就仍能正常工作
* 如果反编译工具采用的递归遍历算法来分析指令流,那么就能将fill-array-data之类的伪指令反编译出来
* 如果反编译工具忽略掉APK的加密标志,那么就能将伪加密的APK也反编译出来
* 如果反编译工具更智能一些,那么一切皆可反编译…….
* 怎么办?
![](https://box.kancloud.cn/48ae14e8032b551a094b30da1876771d_966x671.png)
* Dex Code加密
* Android 4.0及以上的DexFile提供有加载内存dex文件的隐藏接口openDexFile和defineClass,通过它们就可以从内存中加载一个dex文件,在真正加载这块内存之前,可以对其进行加密
* Android 4.0之前的版本,可以用libdvm的导出函数来实现上述相同的功能
* Native Code加密
* 系统中的每一个so文件都是由/system/bin/linker来进行加载和解析的
* 参考/system/bin/linker,实现一个自己的linker,这个linker可以加载和解析内存so文件,从而实现加密处理
- 前言
- Android组件设计思想
- Android源代码开发和调试环境搭建
- Android源代码下载和编译
- Android源代码情景分析法
- Android源代码调试分析法
- 手把手教你为手机编译ROM
- 在Ubuntu上下载、编译和安装Android最新源代码
- 在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)
- 如何单独编译Android源代码中的模块
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序
- 在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序
- 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- Android源代码仓库及其管理工具Repo分析
- Android编译系统简要介绍和学习计划
- Android编译系统环境初始化过程分析
- Android源代码编译命令m/mm/mmm/make分析
- Android系统镜像文件的打包过程分析
- 从CM刷机过程和原理分析Android系统结构
- Android系统架构概述
- Android系统整体架构
- android专用驱动
- Android硬件抽象层HAL
- Android应用程序组件
- Android应用程序框架
- Android用户界面架构
- Android虚拟机之Dalvik虚拟机
- Android硬件抽象层
- Android硬件抽象层(HAL)概要介绍和学习计划
- Android专用驱动
- Android Logger驱动系统
- Android日志系统驱动程序Logger源代码分析
- Android应用程序框架层和系统运行库层日志系统源代码分析
- Android日志系统Logcat源代码简要分析
- Android Binder驱动系统
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
- 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析
- Android Ashmem驱动系统
- Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划
- Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析
- Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析
- Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析
- Android应用程序进程管理
- Android应用程序进程启动过程的源代码分析
- Android系统进程Zygote启动过程的源代码分析
- Android系统默认Home应用程序(Launcher)的启动过程源代码分析
- Android应用程序消息机制
- Android应用程序消息处理机制(Looper、Handler)分析
- Android应用程序线程消息循环模型分析
- Android应用程序输入事件分发和处理机制
- Android应用程序键盘(Keyboard)消息处理机制分析
- Android应用程序UI架构
- Android系统的开机画面显示过程分析
- Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析
- SurfaceFlinger
- Android系统Surface机制的SurfaceFlinger服务
- SurfaceFlinger服务简要介绍和学习计划
- 启动过程分析
- 对帧缓冲区(Frame Buffer)的管理分析
- 线程模型分析
- 渲染应用程序UI的过程分析
- Android应用程序与SurfaceFlinger服务的关系
- 概述和学习计划
- 连接过程分析
- 共享UI元数据(SharedClient)的创建过程分析
- 创建Surface的过程分析
- 渲染Surface的过程分析
- Android应用程序窗口(Activity)
- 实现框架简要介绍和学习计划
- 运行上下文环境(Context)的创建过程分析
- 窗口对象(Window)的创建过程分析
- 视图对象(View)的创建过程分析
- 与WindowManagerService服务的连接过程分析
- 绘图表面(Surface)的创建过程分析
- 测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- WindowManagerService
- WindowManagerService的简要介绍和学习计划
- 计算Activity窗口大小的过程分析
- 对窗口的组织方式分析
- 对输入法窗口(Input Method Window)的管理分析
- 对壁纸窗口(Wallpaper Window)的管理分析
- 计算窗口Z轴位置的过程分析
- 显示Activity组件的启动窗口(Starting Window)的过程分析
- 切换Activity窗口(App Transition)的过程分析
- 显示窗口动画的原理分析
- Android控件TextView的实现原理分析
- Android视图SurfaceView的实现原理分析
- Android应用程序UI硬件加速渲染
- 简要介绍和学习计划
- 环境初始化过程分析
- 预加载资源地图集服务(Asset Atlas Service)分析
- Display List构建过程分析
- Display List渲染过程分析
- 动画执行过程分析
- Android应用程序资源管理框架
- Android资源管理框架(Asset Manager)
- Asset Manager 简要介绍和学习计划
- 编译和打包过程分析
- Asset Manager的创建过程分析
- 查找过程分析
- Dalvik虚拟机和ART虚拟机
- Dalvik虚拟机
- Dalvik虚拟机简要介绍和学习计划
- Dalvik虚拟机的启动过程分析
- Dalvik虚拟机的运行过程分析
- Dalvik虚拟机JNI方法的注册过程分析
- Dalvik虚拟机进程和线程的创建过程分析
- Dalvik虚拟机垃圾收集机制简要介绍和学习计划
- Dalvik虚拟机Java堆创建过程分析
- Dalvik虚拟机为新创建对象分配内存的过程分析
- Dalvik虚拟机垃圾收集(GC)过程分析
- ART虚拟机
- Android ART运行时无缝替换Dalvik虚拟机的过程分析
- Android运行时ART简要介绍和学习计划
- Android运行时ART加载OAT文件的过程分析
- Android运行时ART加载类和方法的过程分析
- Android运行时ART执行类方法的过程分析
- ART运行时垃圾收集机制简要介绍和学习计划
- ART运行时Java堆创建过程分析
- ART运行时为新创建对象分配内存的过程分析
- ART运行时垃圾收集(GC)过程分析
- ART运行时Compacting GC简要介绍和学习计划
- ART运行时Compacting GC堆创建过程分析
- ART运行时Compacting GC为新创建对象分配内存的过程分析
- ART运行时Semi-Space(SS)和Generational Semi-Space(GSS)GC执行过程分析
- ART运行时Mark-Compact( MC)GC执行过程分析
- ART运行时Foreground GC和Background GC切换过程分析
- Android安全机制
- SEAndroid安全机制简要介绍和学习计划
- SEAndroid安全机制框架分析
- SEAndroid安全机制中的文件安全上下文关联分析
- SEAndroid安全机制中的进程安全上下文关联分析
- SEAndroid安全机制对Android属性访问的保护分析
- SEAndroid安全机制对Binder IPC的保护分析
- 从NDK在非Root手机上的调试原理探讨Android的安全机制
- APK防反编译
- Android视频硬解稳定性问题探讨和处理
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
- Android应用程序安装过程源代码分析
- Android应用程序启动过程源代码分析
- 四大组件源代码分析
- Activity
- Android应用程序的Activity启动过程简要介绍和学习计划
- Android应用程序内部启动Activity过程(startActivity)的源代码分析
- 解开Android应用程序组件Activity的"singleTask"之谜
- Android应用程序在新的进程中启动新的Activity的方法和过程分析
- Service
- Android应用程序绑定服务(bindService)的过程源代码分析
- ContentProvider
- Android应用程序组件Content Provider简要介绍和学习计划
- Android应用程序组件Content Provider应用实例
- Android应用程序组件Content Provider的启动过程源代码分析
- Android应用程序组件Content Provider在应用程序之间共享数据的原理分析
- Android应用程序组件Content Provider的共享数据更新通知机制分析
- BroadcastReceiver
- Android系统中的广播(Broadcast)机制简要介绍和学习计划
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序发送广播(sendBroadcast)的过程分析