安卓Dex壳技术探讨(1)
最近在研究安卓平台的加壳技术,以前以为只有原生层的代码才可以加壳,看了看网上的资料,才发现原来Java层也可以加壳,虽然与传统的壳有些区别,但就最终的效果来说,反静态分析的目的还是达到了的。
目前安卓市场上的大多数apk的保护方式都是对Java层进行代码混淆,将关键数据放在原生层,再用传统加壳手段对so文件进行加壳,这种方式的缺陷是Java层的代码安全完全依赖于代码混淆,实际上只要熟悉smali语法,代码混淆的意义就没有想象的那么大,对于那些资深的C/C++逆向工程师来说,逆向smali可比在一堆汇编代码里面按图索骥轻松多了。
传统的PE文件是怎么加壳的
看雪对PE文件的壳解释的很详尽,就不多作阐述了,大致原理是对源PE文件加密或压缩后,将数据嵌入外壳程序里面,外壳程序执行后将源PE文件解密加载,然后跳到源PE文件的入口(OEP)执行。静态分析加壳的程序,就只能看到外壳程序和加密的源PE文件。如果要获得源PE文件(脱壳),就只能运行外壳,让其将源PE文件解密,然后找到OEP,将解密后的PE文件从内存里dump下来,重建输入表,生成脱壳后的PE文件。软件安全工程师可以在壳上采用反调试(Anti-debug)和复杂化控制流等技术来阻止破解者寻找OEP。
可以看出,一个传统的“壳”需要具备以下特点:
1、源程序压缩或加密后内嵌在外壳程序内部;
2、外壳程序先于源程序运行,对源程序解密;
3、解密后的数据必须存放在内存中;
4、源程序加载后要能正常运行;
最为关键的是第3点,需要明白的是,只要投入足够的时间,壳最终是肯定会被破解的,壳的意义实际上在于增加破解成本,尽可能地拖延破解时间,要做到这一点,就必须把与破解者的对抗的关键点放到分析外壳程序的解密逻辑的困难性上,如果破解者有办法绕过分析外壳程序的步骤,直接拿到解密后的源程序,那么这个壳就是无效的。解密后的数据如果留在了文件系统里,破解者就能直接获取到源程序。为什么要单独把这个问题提出来说呢,传统的壳加载源程序,只要解密过后,重定位到OEP就可以了,安卓加载可执行文件却需要使用类加载器DexClassLoader,原型如下:
public DexClassLoader (String dexPath, String optimizedDirectory, String libraryPath, ClassLoader loader)
其中第一个参数dexPath是代表的一个路径,也就是说,DexClassLoader只能加载存放在文件系统里的可执行文件。问题就出来了,刚刚说,我们不能把解密后的源程序放在文件系统上,但是要用DexClassLoader 加载安卓可执行文件dex的话就必须先把它存放在文件系统上,这是对Dex文件进行加壳最大的难点。
为了解决这个问题,我想到了两个办法,第一个办法是减少暴露在文件系统里的时间,在DexClassLoader装载完源程序后,立即将其从文件系统中删除,这样破解者就必须动态调试,在源程序被删除之前断下来才能获得源程序。但是这种办法还是很不安全,我们需要一种彻底不在文件系统留下任何痕迹的方法。先回过头来看DexClassLoader,它虽然只提供路径作为参数,但其加载过程最终肯定有一个步骤是将文件转化成输入流,然后映射到内存,也就是说,DexClassLoader 最终还是要从内存中加载源程序。在网上查了资料,最终在http://www.strazzere.com/papers/DexEducation-PracticingSafeDex.pdf里找到了答案,原来安卓4.0以下的版本确实不支持内存加载Dex,4.0以上的版本实际上是提供了一个以byte数组为参数的接口openDexFile来从内存中加载类的,只不过这个接口并没有开放给SDK,因此需要利用Java反射机制来调用。细节等以后再说,本篇文章先讲讲怎么实现第一种方法。
将源APK嵌入外壳Dex中
我们知道Apk是安卓的安装包,本质是一个zip,需要安装后才能运行,APK里面的classes.dex才是真正的可执行文件,为什么要嵌入APK而不是classes.dex呢?因为classes.dex里并不包含资源文件,如果只加载classes.dex的话,运行后是没有任何资源的。
具体内嵌APK的方法参考了这篇博客:http://blog.csdn.net/androidsecurity/article/details/8678399。博主的做法是将APK加密后,添加到外壳的classes.dex尾部,然后加上APK的文件长度,最后修改classes.dex的dex文件头。这部分很简单,博主也提供了源代码,所以就不阐述了。
需要一提的是,如果把内嵌了源APK的外壳classes.dex直接放入外壳APK中,放进手机安装的话会出错,原因是这样破坏了APK签名,需要把外壳APK中的META-INF文件夹删掉,然后用signapk.jar重新签名,我的signapk.jar的下载地址如下:http://www.uzzf.com/soft/60860.html
在外壳中剥离源APK
外壳程序运行后,通过getApplicationInfo().sourceDir就能获取到外壳自身的APK地址,将其以文件形式打开后,输入到一个ZipInputStream流里,然后遍历zip找到classes.dex,将其输入到一个byte数组,利用byte数组的长度-4得到内嵌的源APK文件的长度,最后调用System.arraycopy将源apk拷贝出来,解密后,输出到文件系统里就可以了。读取壳自身apk的代码如下:
ByteArrayOutputStream dexByteArrayOutputStream = new ByteArrayOutputStream();
ZipInputStream localZipInputStream = new ZipInputStream(
new BufferedInputStream(new FileInputStream(
this.getApplicationInfo().sourceDir)));
利用DexClassLoader动态加载源APK
安卓是允许在不安装apk的情况下调用apk的可执行文件的,要实现这个,就得利用DexClassLoader,这是安卓专用的类加载器,它以APK路径作为参数,找到APK中的classes.dex文件,将里面的类加载进来,这样我们就可以调用源APK中的代码了。需要注意的是,直接用DexClassLoader加载进来的安卓组件类是死的,不具有生命周期,跟普通的类没有区别,也就是说我们不能直接像普通调用安卓组件的方式去调用DexClassLoader加载进来的组件。网上找了一会儿,在http://blog.csdn.net/singwhatiwanna/article/details/22597587上找到了一种解决办法,该博主是将源APK中的组件与调用APK的组件的生命周期绑定在一起,相当于将源APK的生命周期模拟了出来,这种调用技术可用于实现APK插件化,但是存在很多限制,最有效的解决方案其实是360提出的Proxy/Delegate框架:http://blogs.360.cn/blog/proxydelegate-application/这种解决方案是将调用APK的Application动态替换为源APK的Application(Proxy与Delegate),将其运用在Dex文件加壳上的话,这样就相当于替换了应用程序运行环境,运行中的外壳就完全变成了源程序,这时候只要调用源程序的Application.onCreate(),源程序就启动了。此外,需要在源程序的Application.onCreate()里加入启动MainActivity的代码,否则MainActivity是不会主动启动的。
未完待续……
安卓Dex壳技术探讨(1)的更多相关文章
- 安卓 dex 通用脱壳技术研究(一)
注:以下4篇博文中,部分图片引用自DexHunter作者zyqqyz在slide.pptx中的图片,版本归原作者所有: 0x01 背景介绍 安卓 APP 的保护一般分为下列几个方面: JAVA/C代码 ...
- 【腾讯Bugly干货分享】Android Linker 与 SO 加壳技术
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57e3a3bc42eb88da6d4be143 作者:王赛 1. 前言 Andr ...
- AndroidLinker与SO加壳技术之上篇
1. 前言 Android 系统安全愈发重要,像传统pc安全的可执行文件加固一样,应用加固是Android系统安全中非常重要的一环.目前Android 应用加固可以分为dex加固和Native加固,N ...
- android apk 防止反编译技术第一篇-加壳技术
做android framework方面的工作将近三年的时间了,现在公司让做一下android apk安全方面的研究,于是最近就在网上找大量的资料来学习.现在将最近学习成果做一下整理总结.学习的这些成 ...
- 七雄Q传封包辅助技术探讨回忆贴
前言 网页游戏2013年左右最火的类型最烧钱游戏,当年的我也掉坑了.为了边玩还满足码农精神我奋力的学习如何来做外挂.2013年我工作的第二个年头.多一半…介绍下游戏<七雄Q传>是北京游戏谷 ...
- Android Linker 与 SO 加壳技术
1. 前言 Android 系统安全愈发重要,像传统pc安全的可执行文件加固一样,应用加固是Android系统安全中非常重要的一环.目前Android 应用加固可以分为dex加固和Native加固,N ...
- AndroidLinker与SO加壳技术之下篇
点此查看上篇<AndroidLinker与SO加壳技术之上篇> 2.4 链接 链接过程由 soinfo_link_image 函数完成,主要可以分为四个主要步骤: 1. 定位 dynami ...
- Oracle数据库容灾备份技术探讨
Oracle数据库容灾备份技术探讨 三种Oracle灾备技术 对于Oracle数据库的灾备技术,我们可以从Data Guard,GoldenGate和CDP角度去考虑. Oracle Data Gua ...
- 新华三孟丹:NFV资源池实现中的技术探讨
近日,在第三届未来网络发展大会SDN/NFV技术与应用创新分论坛上,新华三解决方案部架构师孟丹女士发表了主题为<NFV资源池实现中的技术探讨>的主题演讲. 孟丹指出,新华三的NFV核心理念 ...
随机推荐
- 深入了解MongoDB
一.介绍: 数据库分为关系型数据库和非关系型数据库 关系型数据库是建立在关系模型上的数据库,主要的有Oracle MySQL Microsoft SQL Server NoSQL是非关系型数据存储的广 ...
- IOS 发布程序(打包上传)
• 发布程序的主要步骤 登录开发者主页 生成cer证书:cer是一个跟电脑相关联的证书文件,让电脑具备发布程序的功能 添加App ID:发布哪些app? 生成MobileProvision文件:生成一 ...
- PHP精度问题
PHP 为任意精度数学计算提供了二进制计算器(Binary Calculator),它支持任意大小和精度的数字,以字符串形式描述 bcadd — 加法bccomp — 比较bcdiv — 相除bcmo ...
- Yarn下分片和分块源代码分析
public class FileSplit extends InputSplit implements Writable { private Path file; private long star ...
- 使用android ndk编译x86 so在linux下使用的问题
一直以为android ndk编译x86 so库可以在linxu下运行,结果我试了几次都行不通.后来想了一下,android ndk编译的库应该只能在android设备或模拟器上运行才有效,后来改用 ...
- BZOJ3288: Mato矩阵(欧拉函数 高斯消元)
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 386 Solved: 296[Submit][Status][Discuss] Descriptio ...
- PHP自动生成分页链接
page.class.php <?php class Page { // 分页栏每页显示的页数 public $rollPage = 5; // 页数跳转时要带的参数 public $param ...
- 3.4.2 Undefined类型【JavaScript高级程序设计第三版】
Undefined 类型只有一个值,即特殊的 undefined.在使用 var 声明变量但未对其加以初始化时,这个变量的值就是 undefined,例如: var message; alert(me ...
- Python全栈day 01
Python全栈day 01 一.计算机认识 用户 软件,类似微信.QQ.游戏等应用程序,由程序员编写,在系统中运行,完成各种活动,方便人们使用. 操作系统,主要分为windows系统.Linux系统 ...
- Requests库:python实现的简单易用的http库
1.get请求: get(url, params, headers) 2.json 解析 3.content 获取二进制内容 4.headers 添加 5.post请求:post(url,data,h ...