Android 应用防止被二次打包指南

简介:

b273785583c061af59dd8de4ecd9420352fc04b5

“Android APP二次打包”则是盗版正规Android APP,破解后植入恶意代码重新打包。不管从性能、用户体验、外观它都跟正规APP一模一样但是背后它确悄悄运行着可怕的程序,它会在不知不觉中浪费手机电量、流量,恶意扣费、偷窥隐私等等行为。

正文

二次打包问题只是Android应用安全风险中的一部分, 一般是通过反编译工具向应用中插入广告代码与相关配置,再在第三方应用市场、论坛发布。

对于打包党对于移动App带来的危害有以下几种:

  • 1. 插入自己广告或者删除原来广告;

  • 2. 恶意代码, 恶意扣费、木马等;

  • 3. 修改原来支付逻辑。

上述恶意行为严重危害移动产品和用户利益,同时也影响企业口碑。

关于移动App破解、数据泄露风险问题,以金融行业为例:众所周知数据是金融类应用产品重要资源之一,关乎企业生存与发展、但移动应用经常被破解、数据被抓包,导致本地存储数据以及用户名、密码等重要信息泄露。下面举例说明数据泄露案例。

金融类本地存储数据泄漏

数据抓包,泄漏用户名和密码

面对二次打包不少公司都有自己的防范措施,知名公司的APP几乎都是自己在程序内部做过处理防止其APP被二次打包,一旦打包后重新运行则程序自动退出。接下来,我就来详解一下如何防止APP被二次打包。

如何解决移动App安全风险问题?

基于多年的移动安全经验积累,网易云易盾在移动APP安全风险问题上,从起始的开发阶段、中间的测试阶段再到结尾发布阶段,针对移动APP全生命周期进行安全防护。

开发阶段——移动应用开发时接入安全组件,保护数据安全。其中,针对安全通信方面,实现数据高强度加密,结合传统的对称、非对称加密算法和hash算法,客户端加密数据只有认证服务端才能解密,从而防止了数据泄漏、数据窃取和篡改。另外,为了实现加强数据的安全强度,安全组件结合自适应特征算法和随机切换算法,保证不同时间、不同终端的算法和密钥的差异性。

测试阶段——对移动应用进行人工渗透测试,发现漏洞解决产品修复相关问题,包括:APP渗透测试和服务端渗透测试。

发布阶段——APP上架之前针对应用做安全加固,提高安全防护等级,上架之后做盗版监测。网易云易盾可针对dex文件进行加固防护,防止被静态反编译获取代码逻辑;保护应用在被非法二次打包后不能正常运行;防止通过使用调试器工具对应用进行非法破解;提供自研高稳定的设备指纹,防止潜在的刷单风险;加密资源文件,防止apk资源文件被破解;对so文件进行加固保护,防止native代码被逆向分析;对游戏提供加固保护,让游戏免受破解、外挂等威胁。

要实现代码内部防止APP被二次打包首先得了解APK的机器识别原理,APK的唯一识别是依靠包名和签名来做鉴定的,类似豌豆夹的洗白白、360手机卫士等安全软件对APK的山寨识别,他们就是依赖包名来确定APK然后通过签名来确定其是否山寨。所以说自己的程序内部在启动的时候可以通过获取APK本身的签名然后和正确的签名做对比来识别自己是否被二次打包。

69083fe8ece7592f5c4ca59873fb0d66684965ea

通过PackageManag对象可以获取APK自身的签名。

234cbb9ec6dd1600bbff91a6993ba9f5584bf32e

过对签名的码的分解得到一串20左右的字符串,此字符串则是APK的签名的MD5值,通过获取的签名MD5值与正确的MD5值进行对比,就可以识别其APK是否被盗版。

下图是一些已做过保护的APP的代码块分析:

079711a901cbc038e5cca255d2b60aeb1518ea53

上图是“XX省电王“的防止二次打包的关键代码

6e95c9da16a2c44fff59537be326467e2ff94923

上图是”XX电池管家”的防止二次打包的关键代码

以上两处都是smali层的代码,以上2处代码的截图都是下载量非常高的APP所做的防止二次打包的处理,其处理的代码肯定会使用到的关键代码是

Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature。

此方法能够起到一定的安全作用,一般的打包党面对它是无可奈何的,如果你了解一些smali语法它的作用就等于0了。

Android 应用加固的技术细节

此外,针对如何加固的技术细节问题,网易云资深安全工程师钟亚平在安卓巴士全球开发者论坛的活动中也做过《安卓App逆向与保护》的主题演讲:

安卓App安全包含很多内容,包括混淆代码、整体Dex加固、拆分 Dex 加固、虚拟机加固等方面。事实上,这些内容也是国内近几年Android App安全保护的一种主要趋势。

一、混淆代码

Java代码是非常容易反编译的,作为一种跨平台的、解释型语言,Java 源代码被编译成中间“字节码”存储于class文件中。由于跨平台的需要,这些字节码带有许多的语义信息,很容易被反编译成Java源代码。为了很好地保护Java源代码,开发者往往会对编译好的class文件进行混淆处理。

混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。ProGuard就是一个混淆代码的开源项目,能够对字节码进行混淆、缩减体积、优化等处理。

Proguard处理流程图如下所示,包含压缩、优化、混淆、预检四个主要环节:

1、压缩(Shrink):检测并移除代码中无用的类、字段、方法和特性(Attribute);


2、优化(Optimize):对字节码进行优化,移除无用的指令。优化代码,非入口节点类会加上private/static/final,没有用到的参数会被删除,一些方法可能会变成内联代码;


3、混淆(Obfuscate):使用a、b、c、d这样简短而无意义的名称,对类、字段和方法进行重命名;


4、预检(Preveirfy):在Java平台上对处理后的代码进行预检,确保加载的class文件是可执行的。

混淆代码逆向分析

如果想要反编译混淆代码,钟亚平分享了一个国外的工具DEGUADR,它能够通过统计的方式来解混淆。虽然这个工具的正确率达不到100%,但是能在一定程度上帮助反编译代码。

com.xxxxx.common.util.CryptoUtil网站也提供了一种反编译服务,如下所示:

 

java.lang.String a(byte[]) -> encodeToString java.lang.String a(byte[],boolean,java.lang.String) ->a byte[] a(byte[],byte[]) -> encrypt byte[] b(byte[]) -> getKey byte[] b(byte[],byte[]) -> decrypt byte[] d(java.lang.String) -> getKey java.lang.String a(byte,char[]) -> a java.lang.String a(java.io.File) -> getHash java.lang.String a(java.lang.String) -> c java.lang.String b(java.lang.String) -> encode

二、整体Dex加固

为了加强Android保护强度,随着安全技术的发展,又出现了新型的“加固技术”。Dex加固是对Dex文件进行加壳防护,防止被静态反编译工具破解而泄露源码,最刚开始出现的是整体加固技术方案。

整体加固技术的原理如上所示,包括替换application/classes.dex、解密/动态加载原classes.dex、调用原application相关方法、将原application对象/名称设置到系统内部相关变量四大环节。其中最为关键的一步就是解密/动态加载原classes.dex,通过加密编译好的最终ex源码文件,然后在一个新项目中用新项目的application启动来解密原项目代码并加载到内存中,再把当前进程替换为解密后的代码,能够很好地隐藏源码并防止直接性的反编译。

整体Dex加固逆向分析

整体Dex加固逆向分析有两种常用的方法。其一是在内存中暴力搜索 dex\n035,再 dump。以下是在32位系统中的效果示例:

另一种方法就是通过Hook dvmDexFileOpenPartial(void addr, int len, DvmDex*)。

三、拆分Dex加固

随着业务规模发展到一定程度,不断地加入新功能、添加新的类库,代码在急剧膨胀的同时,相应的apk包的大小也急剧增加,那么简单的整体加固方案就不能很好地满足安全需求,在整体加固方案之外又出现了拆分加固的技术方案。

但是如上所示,Dex文件在加固时,针对中间缺失的一部分数据会以解密后的数据来替换,有的时候这种拆分替换也会导致数据不准确。那么到底应该拆分什么样的数据呢?就需要了解一下Dex文件的数据结构。

Dex文件结构极为复杂,以下图示选取了其中较为重要的内容。事实上,Dex文件是一个以class为核心组装起来的文件,其中最重要的是classdata和classcode两部分,有其特定的接口和指令数据,选取这两部分来拆分的话,即使拆分出来也不会泄露class数据和字节码数据,反编译出来也不完整,安全性较高。

拆分Dex加固逆向分析

对于Dex拆分加固的逆向分析,如下所示,可以用classdata替换从而组装成新的Dex文件,虽然和原来的Dex文件不会完全一致,但也在一定程度上复原了被拆分数据的样子。

但要注意的是,这种方法仅适用于被拆分出去的数据变形一次性完成,也就是说,在有其他保护思路的情况下尽量避免使用,而且即使有需要也尽量选在用到这个类的时候才去恢复。

此外还有一个更底层一些的工具dexhunter,这个工具较为前卫,但同时也有一些局限性,譬如部分指令数据会被优化,形成的代码界面不是很美观等等。

四、虚拟机加固

虚拟机加固也属于Dex拆分加固的一种,它是对字节做了一些变化处理。如下所示,这是一个正常安卓系统中的代码,在其中进行了虚拟机加固操作:

以add-int v0, v1, v2、sub-int v0, v1, v2、mul-int v0, v1, v2这三条指令进行替换,然后进行加固编译,这样子操作后,即使把替换后的数据恢复了,也不会以add-int v0, v1, v2、sub-int v0, v1, v2、mul-int v0, v1, v2这三条指令进行替换,然后进行加固编译,这样子操作后,即使把替换后的数据恢复了,也不会变形成为之前的字节码,安全系数较高。

虚拟机加固逆向分析—HOOK JNI 接口

这种方式下的逆向分析,一方面可以通过HOOK JNI 接口来实现,它有两种实现方式。

其一是类成员/静态变量操作相关接口,比如:

GetStaticDoubleField SetStaticDoubleField GetDoubleField SetDoubleField …

(byteobjectintlong…)

其二是反射调用类方法,比如:

*   CallVoidMethodA CallBooleanMethodA CallShortMethodA CallObjectMethodA …

*   CallStaticVoidMethodA CallStaticBooleanMethodA CallStaticShortMethodA CallStaticObjectMethodA …

*   (byteintlong,double …)

*   CallObjectMethodA(JNIEnv* env, jobject object, jmethoID method, …)

通过HOOK JNI 接口实现虚拟机加固逆向分析

通过HOOK JNI 接口不用逆向底层,就可以了解App大致的调用流程。但是对于复杂的调用过程,或者虚拟化方法数量较多的情况,这种逆向分析手段看起来会比较混乱;对于不需要返射到Java层执行的指令,如算术、逻辑运算等,则无法监控到。

虚拟机加固逆向分析—分析指令操作码映射

另一方面,也可以通过分析指令操作码映射来逆向分析。在同一加固版本,或者映射关系相同的情况下,可以采取以下所示的方法:

但在实际情况中,每次加固时的映射关系都是随机变化的,如下所示,这种情况下就无法直接建立映射关系。

不依赖于操作码的映射关系只与虚拟机结构有关,所以需要根据偏移关系建立映射关系,从而进行逆向分析。

安卓App逆向保护作为开发工作中的重要内容,一直是网易云易盾致力提供的应用服务。后续,我们将在SO加密保护方面进行更加深入地研究,对SO里面的逻辑进行分析,保护Native代码不被逆向分析

总结

Android应用做不到完全的防止二次打包。

1、简单型

最简单的就像签名验证。验证编译之后的dex签名,md5等数据。

2、微有点技术含量型

由native在运行时释放class到内存。释放bytes数据直接喂给classloader。

3、难度型

对native本身再进行一些加固,加逆向坑(暗桩)增加破解难度。

4、较难度型

Java代码执行代码的时候调用native操作,实现破解必须破解native部分。

最后如果需要,部分必要算法转移到云端执行,最大限度的去保证防被破解和二次打包


原文发布时间为:2018-11-21

本文作者:yijian2595

本文来自云栖社区合作伙伴“终端研发部”,了解相关信息可以关注“终端研发部”。

相关文章
|
6天前
|
XML Java Android开发
探索Android开发之旅:打造你的第一个应用
【9月更文挑战第4天】在这篇专为初学者设计的文章中,我们将一起踏上激动人心的Android开发之旅。从设置开发环境到实现一个简单的“Hello World”应用,每一步都充满了发现和学习。文章将引导你理解Android开发的基础知识,并鼓励你动手实践。让我们开始吧,创造你的第一款Android应用,开启技术世界的新篇章!
|
9天前
|
存储 缓存 搜索推荐
打造个性化天气应用:Android 平台上的天气预报小助手
【9月更文挑战第2天】在这篇文章中,我们将一起探索如何从零开始构建一个简单却功能强大的天气应用。通过这个指南,你将学会如何在 Android 平台上使用 Java 编程语言和相关 API 来创建你自己的天气预报小助手。文章不仅提供了代码示例,还深入讨论了设计思路、用户界面优化以及数据管理等关键方面,旨在帮助初学者理解并实现一个完整的应用项目。
|
11天前
|
搜索推荐 IDE 开发工具
打造个性化安卓应用:从零开始的Flutter之旅
在数字时代的浪潮中,拥有一款个性化且高效的移动应用已成为许多创业者和企业的梦想。本文将引导你使用Flutter框架,从零基础开始构建一个安卓应用,不仅涉及界面设计、功能实现,还包括性能优化的关键技巧。通过简洁易懂的语言和实用的代码示例,我们将一起探索如何让你的应用在众多竞争者中脱颖而出。 【8月更文挑战第31天】
|
11天前
|
存储 开发工具 Android开发
打造你的专属安卓应用:从零开始的Flutter之旅
【8月更文挑战第31天】在数字时代的浪潮中,拥有一款属于自己的应用不仅是梦想的启航,也是技术实力的展现。本文将引导你使用Flutter框架,轻松步入安卓应用的开发世界。无论你是编程新手还是希望拓展技能边界的开发者,跟随这篇指南,你将学会如何搭建开发环境、设计用户界面,并实现基本功能。让我们一起探索代码的力量,开启一段创造之旅吧!
|
11天前
|
移动开发 搜索推荐 开发工具
打造个性化安卓应用:从零开始的Flutter之旅
【8月更文挑战第31天】探索Flutter,一个革命性的UI工具包,它让开发者能够使用一套代码库构建美观、快速的原生应用。本篇文章将带你领略Flutter的魅力,通过实际示例揭示如何快速搭建一个安卓应用。无论你是新手还是有经验的开发者,这篇文章都将为你提供价值。
|
12天前
|
Android开发 UED 开发者
探索安卓应用的生命周期管理
【8月更文挑战第31天】在开发安卓应用时,理解并妥善处理应用的生命周期是至关重要的。本文将通过浅显易懂的方式,带你了解安卓应用的生命周期,并通过代码示例展示如何在实际应用中进行有效的生命周期管理。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和实用技巧。
|
3天前
|
开发工具 Android开发 iOS开发
探索安卓与iOS开发的差异:构建未来应用的关键考量
在数字时代的浪潮中,安卓和iOS这两大操作系统如同双子星座般耀眼夺目,引领着移动应用的潮流。它们各自拥有独特的魅力和深厚的用户基础,为开发者提供了广阔的舞台。然而,正如每枚硬币都有两面,安卓与iOS在开发过程中也展现出了截然不同的特性。本文将深入剖析这两者在开发环境、编程语言、用户体验设计等方面的显著差异,并探讨如何根据目标受众和项目需求做出明智的选择。无论你是初涉移动应用开发的新手,还是寻求拓展技能边界的资深开发者,这篇文章都将为你提供宝贵的见解和实用的建议,帮助你在安卓与iOS的开发之路上更加从容自信地前行。
|
11天前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
61 0
|
11天前
|
开发框架 Dart 搜索推荐
打造个性化安卓应用:从零开始的Flutter之旅
【8月更文挑战第31天】在数字化浪潮中,拥有一款个性化的移动应用是许多人的梦想。本文将引导你使用Flutter框架,快速入门安卓应用开发。我们会一起探索Flutter的基础概念,并通过一个简单的计数器应用示例,展示如何实现交互式界面。无论你是编程新手还是希望扩展技能边界的开发者,这篇文章都将为你开启一扇新窗,让你看到用代码创造美丽事物的无限可能。