DroidSkynet:一种分析早期版本App漏洞的工具

robots

 

Android 平台的普及这导致开发商投入资源以维持需求的上升。不幸的是,随着利润潜力越来越大,这些App受到攻击的机会也越来越大。因此,开发人员提高了他们App的安全性,这限制了攻击者破坏App升级版本的能力。但是,开发人员无法增强已在 Play 商店中发布的早期版本的安全性。较早版本的App可能会受到逆向工程和其他攻击。在本文中发现攻击者可以将这些早期版本用作攻击媒介,从而威胁到受到良好保护的升级版本。通过分析Facebook、Weibo和Cloud-Driven等一些流行应用的升级版本,展示了如何对其早期版本存在的漏洞进行攻击。设计并实现了一个名为 DroidSkynet 的工具来分析和找出 Play 商店中存在漏洞的App。在从现实世界收集的1500个主流应用中,DroidSkynet显示攻击使用早期版本的应用的成功率为34%。还探索了可能的缓解解决方案,以在App更新过程的实用性和安全性之间取得平衡。

 

0x01 Introduction

随着智能手机的迅速普及,Android 操作系统已经占据了总市场份额的重要组成部分。这是由于 Android 为开发人员和供应商提供了易于加入的App开发社区。现在,开发人员通过创建大量App将他们的服务扩展到移动领域。截至目前,GooglePlay上的App已超过 260 万个,总下载量已超过 1970 亿。

然而,Android App的流行使其成为主要攻击目标,这可能会严重损害用户的信息安全和隐私。例如,中间人攻击 (MITM,Man-in-the-Middle attack) 可以在启用网络的App上启动,这可以让攻击者在用户不知情的情况下访问云中的用户信息。逆向工程允许攻击者探索源代码并提取与安全相关的算法,这有助于他们更轻松地设计攻击向量。例如,攻击者可以根据源代码发起重新打包攻击(repackage attack)。重新打包攻击会使App受到严重威胁。在这种攻击中,攻击者向App注入负载以重新打包木马版本,使良性App成为恶意App。

近年来,为了增强 Android App的安全性,开发人员和供应商采用了多种方法。为了防止 MITM 攻击,开发人员/供应商通过使用 TLS/SSL 或访问控制等技术来保护他们的App的网络通信。为了保护他们的App被逆向,开发人员使用代码保护方法来保护他们App的源代码,例如Java本地接口 (JNI, Java-Native-Interface) 和布局混淆(layout obfuscation)。

老实说,这些对策使App难以妥协。但由于所有这些对策仅适用于“升级版本”,因此这些App的旧版本仍然容易受到攻击。例如,著名的社交媒体 App facebook 有 200 多个版本,其中一些可能不像希望的那样安全。较早版本和升级版本可能共享相似或完全相同的功能。例如,尽管一些游戏App(例如,愤怒的小鸟、2048 等)可能会不断更新新功能,包括添加新角色或新场景以使其更有趣,但基本思想或规则如何玩游戏可能不会有太大变化。同时,为了保证开发效率,新版本的 App 可能根本就没有那么“新”。它们可能建立在较早的基础之上。因此,它们的源代码也可能相似。

基于这一观察,在本文中提出了不同的问题:与其分析最终安全的升级后的App,攻击者还可以通过分析其以前的易受攻击版本来做什么?早期版本中是否存在同样适用于这些升级版本的漏洞?如果有,如何探索?

事实上,在游戏App的情况下,很容易将源代码泄漏造成的威胁可视化,即使是早期版本也是如此。如果游戏公司的竞争对手可以通过逆向获得较早版本的游戏App的源代码和算法,他们可能会盗版新的App,从而威胁到原游戏公司的知识产权。在接下来的部分中,将展示攻击者可以通过利用早期版本中存在的漏洞发起更严重的攻击。

本文研究检查了如何发起此类攻击。在示例中,涉及两种类型的攻击向量。它们是弱接口分析和安全相关算法(或密钥)分析。在弱接口分析中,探索了早期版本和升级版本中都存在的一些不安全的接口。演示了基于Cloud-Driven的这种类型的攻击。通过对网络请求的分析,发现早期版本存在一个不安全的Restful API,可以在其上启动MITM并删除Cloud Drive上的文件,这可能严重威胁到新版本的安全。在安全相关的算法(或密钥)分析中,得到了在保护较差的App上进行App认证时使用的 HMAC 密钥和算法。使用它,攻击者可以构建一个木马化版本。

为了更好地理解这个问题,介绍了工具 DroidSkynet,它可以判断一个 App 是否受到早期版本带来的威胁。工具接受给定App的多个版本,并在可能的情况下从中提取源代码。 可运行分析确定较早版本是否仍在正常运行,而相似性分析返回较早版本的 App 是否与其对应的升级版本相似。如果两者都是肯定的,则漏洞分析会返回早期版本可用作攻击向量的可能性。

 

0x02 Backround and Threat Model

A.逆向工程和程序代码保护

Android 平台上的以下逆向工程和程序代码保护概念在工作环境中很重要。

(1)安卓逆向

Android 逆向是从 Android App中提取和重构原始 Java 源代码的过程。一个App的功能和实现细节信息可以通过Android逆向获得,这需要一些特定的工具,如APKTool、dex2jar和AXMLPrinter2。 jar帮助从App或二进制可执行文件中获取源代码和资源文件。

(2)Android 程序代码保护

Android 逆向工程的对立面是 Android 程序代码保护。 Android 程序保护是一种有效的技术,可以防止攻击者解析源代码。它通过使提取源代码和资源文件变得困难来保护源代码。实现Android程序代码保护的方法有很多。例如,Java 本地接口是一种标准使用的代码保护方法。它提供 Java 代码和本地代码之间的接口,并允许 Android App在 Java 代码层执行 C/C++ 代码。通过JNI技术,开发者将核心业务逻辑封装在C/C++库中,然后在Java代码层调用。 JNI 使逆向工程变得困难,因为 C/C++ 代码比 Java 代码更难逆向工程。作为另一种著名的代码保护方法,布局混淆可以有效地阻碍逆向工程过程。具体来说,源代码被一系列无意义的字符代替,这使得源代码对人类不可读,但对机器可读。

B.威胁模型

为了发起攻击,攻击者需要找到一个早期版本,攻击者可以利用它来携带恶意负载。这些攻击从受保护较差的早期版本中提取特定代码行或其他有用信息,然后可以将其用作其他攻击的构建块。

在本文中主要关注两种类型的漏洞,它们对应于两种攻击。 (i) 早期版本和升级版本都存在的弱接口。利用弱接口,攻击者可以探查App的设计缺陷并发动攻击。特别是专注于 MITM 攻击。 (ii) 揭示早期版本的安全相关算法或密钥。作为攻击者,他可以使用这些与安全相关的算法或密钥来分析和破解 App 与其服务器之间的身份验证协议。他还可以获得源代码的重要部分来构建木马化版本。

 

0x03 Motivating Examples

A.弱接口

升级版本使用加密来保护网络流量免受重放攻击和窃听攻击,而其早期版本可能容易受到各种攻击。此外,早期版本中使用的弱Restful API也可能可用,这可能对更新版本构成威胁。在 Web 安全中,如果探索了设计不佳的界面,黑客可以利用该界面破坏整个网站。

Cloud-Driven为用户提供安全存储服务,虽然加强了升级版本的安全性,但早期版本仍然面临威胁。现在演示攻击的工作流程,攻击的目标是找到一个存在于早期版本中并且仍然有效的不安全的 Restful API,然后将其用作攻击向量来发起 MITM 攻击。在实验中,使用“Fiddler”这个基于客户端代理的工具来分析网络流量并重放用户的操作会话。该工具具有重放特定请求的即开即用功能,可帮助顺利处理实验。将该工具应用于Cloud-Driven的多个版本,并手动触发每个操作,包括下载文件、删除文件、重命名文件。在这样的实验比较的帮助下,暴露了一个不安全的 Rest ful API。这个 Restful API 旨在最初删除用户云存储中不必要的文件。它可以在 1.2.2 版中找到,但已从 7.1.0 版中删除。通过使用这个不安全的 Restful API,攻击者可以删除文件。个别地,当用户尝试删除一个文件时,充当中间人并阻止请求。获取请求后,通过不安全的Restful API对其进行篡改,导致用户删除其他文件。更严重的是,通过编辑和重放包,攻击者即使在用户不知情的情况下也可以轻松进行此类攻击

B.揭示与安全相关的算法或密钥

使用代码保护的动机之一是避免泄露与安全相关的算法或密钥。一旦攻击者获得了这样的算法或密钥,攻击者就可以利用它们发起各种攻击。尽管较早的版本可能与较新的版本有所不同,但攻击者仍然可以从较早的协议中提取一些协议的设计思想。没有公司愿意在每次发布新版本时从零重新启动他们的App。如果攻击者足够幸运,他们甚至可能从早期版本中获得一个密钥,而这个密钥仍在升级版本中使用。

用户身份验证对于App非常重要,而发目标App中存在身份验证代码片段的漏洞。通常,实现用户身份验证的代码使用加盐(salted)密码哈希来增强安全性。加盐密码哈希是防止密码猜测攻击的首选方法。 加盐密码哈希的实现过程描述如下:当用户输入密码并按下登录按钮时,从硬编码的源代码文件中检索salt并附加用户输入的密码以创建一个新的哈希密码使用以保护原始输入密码。盐充当 HMAC 密钥,避免修改散列密码。此外,加盐密码哈希也是一种验证客户端身份的方法。例如,假设这个机制没有保证;攻击者可以仅通过网络流提取身份验证的所有特征。然后可以使用提取特征来伪造一个假客户。目标是获得早期版本中硬编码的秘密盐,可以用来发起上述攻击。

Weibo是一个类似推特的信息共享和交流平台。它是全球最受欢迎的社交网络作品之一,它让用户尽情享受互联网带来的便利。在全球范围内,Weibo拥有 2.22 亿月活跃用户,而日活跃用户高达 1 亿。通过观察,发现Weibo客户端尝试连接自己的服务器时,服务器会收到来自客户端的认证参数。需要三个认证参数,包括用户名、密码和一串字母和数字。通过分析,发现第三个参数在身份验证中起着至关重要的作用。如果没有它或在认证过程中用另一个替换它,登录请求将被服务器拒绝。对于特定用户,只要用户不更改密码,该参数就不会改变。

对于这些升级版的Weibo,由于使用了大量的代码保护,逆向工程过程变得无能为力。这促使检查它的早期版本。选择运行正常的早期版本,运行正常表示升级版本使用的认证机制与早期版本相同。

经过人工检测,发现Weibo早期版本(V2.4.0_1)的代码保护很差。请注意,只有在用户输入身份凭证并按下登录按钮后,才会发送登录请求。因此,将登录按钮按下操作作为突破点。为了捕捉这样的动作,需要找到源代码和用户交互之间的关系。为此,首先搜索布局文件以找出预期登录按钮的位置。布局文件提供了一种人类可读的结构来描述 UI 屏幕。每个布局文件对应一个Activity。 Activity 包含一组函数,当特定事件发生在相应布局文件所描述的 UI 上时,这些函数可以执行。在找到按下登录按钮的动作触发的函数后,将此函数作为入口点。从这个入口点开始,跟踪这个函数调用的其他函数。按函数名和返回值拆分每个函数。函数名暴露了它们的功能,这可以帮助更快地锁定目标函数。例如,函数“getLoginResponseContent”就是从服务器获取响应。经过几次失败的尝试,找到了用于生成上述第三个参数的算法。该算法将用户名、密码和常规盐作为输入,然后将这些输入提供给 MD5 函数。下图说明了该算法的详细实现。可以观察到,使用了一个名为“KEY”的静态字符串作为 MD5 哈希函数的盐。这个字符串可以通过逆向工程从类“Constants”中提取出来。

Facebook 是世界上最大的社交网络之一,拥有庞大的用户群。在全球范围内,Facebook 每月有大约 17.9 亿活跃用户 (MAU)。拥有如此多的用户,其客户端的安全性变得尤为重要,这引起了研究人员的关注。Facebook 的认证机制类似于微博,需要几个参数来构建一个有效的 URL。对升级后的版本(9.2版本)进行逆向工程失败,尝试对其早期版本进行逆向工程以提取核心引擎。不幸的是,逆向工程的过程并不像微博那么容易,因为 Facebook 早期版本的部分源代码也被混淆了。为了克服这个限制,使用 App 重新打包技术来构建恶意 App。攻击者经常使用重新打包技术将恶意负载注入普通App。编写了一个名为“Logger”的日志记录负载,并将其注入 Facebook(版本 1.9.2)。 Logger在Face book(1.9.2版本)的原始方法中注册了监听器,通过它可以记录感兴趣的值,包括输入、输出和特定函数生成的临时值。

Logger的执行过程如上图所示。 通过将“Logger”注入多个早期版本(已经测试了三个版本,包括“V1.91”、“V1.6”和“V2.2”) ,重构了一个算法。 Facebook使用的算法以用户名和密码作为动态输入,以“signatureKey” 为静态字符串作为MD5哈希函数的salt,最终返回MD5哈希算法的哈希值。

 

0x04 Analysis Strategy

通过观察上述攻击实例,总结分析和攻击步骤如下:

1) 早期版本发现:对于给定的升级后的 App,攻击者需要找到它的早期版本。基于这些,攻击者可以执行他的分析。

2) 可运行分析:当攻击者探索一个不安全的接口时,攻击者需要从他发现的所有早期版本中选择可以正常运行的早期版本。正常运行的早期版本表明仍在使用弱接口。

3) 相似性分析:攻击者需要确保他找到的早期版本与相应的升级版本相似。较早版本与升级版本相似度高,说明开发者并未过多改动本App的函数,攻击者仍可借此从较早版本中提取有用信息(即安全相关函数或key)。

4) 漏洞分析:攻击者需要进一步将选择的早期版本缩小到易受攻击的版本。

5)攻击:攻击者分析易受攻击的早期版本和升级版本之间的共同函数。在这个过程中可以探索漏洞。

已经有很多相关工作探索保护不良的App的漏洞能力,因此最后一个阶段超出了本文的范围。专注于前四个阶段,以确定可能成为候选的早期版本。给出了如算法 1 所示的基本算法。在开始描述算法之前,下表列出了一些使用的函数。将在以下部分详细介绍每个阶段。

A.早期版本发现

判断一个App是否是早期的,应该知道这个App发布的合适时间。一般来说,App的创建时间就是用户下载的时间,不包括App的开发者何时发布的信息。但是,有些下载页面记录了发布时间。另一方面,通过实验发现使用解压软件可以解压APK文件,解压后的文件表示App的创建时间。

B.可运行分析

回想一下,攻击者需要知道他发现的早期版本运行正常。基于一个简单的观察,这能够知道App是否正常运行。App可以分为两类:使用 Internet 连接的App和不使用 Internet 连接的App。对于不使用互联网的App,只要用户安装它,它就会始终工作,因为 Android 系统向下兼容。对于使用互联网的App,如果服务端停止向App提供服务,App就会停止工作。对于这些App,还需要考虑到服务器端。基于这一观察,在算法 2 (isRunnable(a)) 中提出。

在算法 2 中,将阈值定义为 50%,它表示可用 URL 占应用源代码中找到的总 URL 的比率。如果其可用网址占总网址的比例大于阈值,认为该App运行正常。如果App的源代码包含敏感 URL,则函数 containsSAURLðaÞ 将返回值 TRUE。具体而言,如果 URL 包含以下信息,则该 URL 是敏感的:

用户操作:在用户向服务器请求服务的过程中,用户动作表示用户请求服务器执行的命令。这种动作分为两类:操作请求和认证请求。操作请求是指用户希望对服务器上的资源进行操作,例如删除文件或查看文件。认证请求包括登录请求和注册请求。

操作sink:同样,操作的sink被认为是敏感的,可以知道用户想要操作哪些资源。

身份:用户的身份信息存在于系统中,例如电话号码、帐户、电子邮件地址和密码。

哈希值:如前所述,使用盐进行密码散列是保护密码完整性的首选方法。可以在 URL 中附加密码和用户名的哈希值。

例如,假设有这样一个格式的 URL:http://a.com?un=a&pwd=b&key=c&op=delete&fn=1.txt 。在此示例中,用户名“a”和密码“b”的用户想要删除(op=delete)其 cloudDrive 上名为“1.txt”的文件。参数键是生成的散列。在这种情况下,删除文件是用户操作,而文件名是操作sink。用户名和密码是他的身份信息。

C.相似性分析

为了了解早期版本和新版本之间的相似性,引入了 SimiDroid 来分析App。 SimiDroid是一个用于比较 Android App的框架。它可以识别和解释不同App之间的相似性和变化。它带有三个插件,它可以识别和解释不同应用程序之间的相似性和变化。这些插件是基于方法的比较、基于资源的比较和基于组件的比较。本文专注于基于方法的比较,因为它将提供有关开发人员是否更改其App功能的信息。基于方法的比较可以从两个不同的App中提取所有方法签名和语句的抽象表示,然后计算两个App之间的相似度。这些签名和描述不仅基于常量值(方法或参数的名称),还基于其结构。因此,即使开发者使用布局混淆技术来保护其源代码,结果也不会受到影响。

D.漏洞分析

应该确保攻击者可以破坏替代的早期版本。什么使App易受攻击?首先,源代码没有受到严格的保护。否则,攻击者无法从中获取足够的信息。其次,它不使用密码算法来保留其基本参数。

(1)源代码保护分析

为了解决第一个问题,需要知道App对其源代码的保护程度。首先将Android程序代码保护技术分为两类:逻辑保护(LP)和文件保护(FP)。 LP 通过降低源代码的可读性来保护源代码文件的逻辑功能。 LP 最常用的方法是布局混淆。 FP 防止源代码文件在 App 文件中泄露。它是一种防止攻击者提取所有源代码文件的方法。 FP 最常见的技术是 JNI。因此,在本研究中专注于 JNI 技术。

逻辑保护处理:App 的漏洞与其源代码的可读性密切相关。定义当应用布局混淆 (LP) 时,布局混淆率是决定 App 是否可以被攻陷的重要因素之一。布局混淆率 RLP 可以使用以下公式计算:

ClassNumLP 是开发人员在源代码中混淆的类数,而 ClassNumNOLP 是未混淆的类数。

文件保护处理:暴露给上层的 JNI 函数通常是基本的,它涵盖了其原生层的底层逻辑。当应用 JNI (LP) 时,攻击者可以直接使用 JNI-libs,而无需了解其逻辑。对于一些攻击者来说,他们并不关心是否使用了 FP。例如,在 Facebook 的情况下,使用原始 App 的源代码,包括所有 JNI-libs,重新打包恶意 App。在整个过程中,使用 JNI 库作为恶意App的构建块,但并不了解它们。然而,对于其他一些攻击者,他们可能也关心App的 JNI-libs 的实现。为了涵盖这两种情况,引入了 FP IFFP (IFFP小于1)的影响因子。 IFFP 将成为结果的一部分,但其值可以自定义。换句话说,可以检测是否有文件保护,但会让攻击者或开发人员决定它是否重要。

(2)密码算法分析

如前所述,攻击者可以从早期版本中提取不安全的接口。什么使接口不安全?不安全的接口通常接受纯文本作为他们的输入,并直接提交它而不需要任何加密过程。基于这一观察,引入了污点分析技术来追踪参数如何从一个函数传递到另一个函数。对于 Android App,污点分析能够构建从特定入口点(称为源)到特定出口点(称为sink)的路径。为了确定是否使用加密算法,将加密 API 的返回值作为源,将网络 API 的输入作为sink。污点技术可以识别在给定的 App 中是否有应用加密算法来保护接口,但它不能决定这个接口提交的参数有多少。因此,引入IFcrypto的影响因子来解决这个问题。开发人员或攻击者可以自定义此值。

现在可以决定App是否易受攻击。具体来说给出了 VunRate 的定义,它表明了攻击 App a 的可能性。 VunRate 可以描述如下:

 

0x05 DROIDSKYNET

基于算法 1实现了一个工具,可以识别App是否面临潜在的安全风险。将该工具命名为 DroidSkynet。在 Droid Skynet 的帮助下,试图向开发人员发出警报,即攻击者可以借助早期版本发起攻击。此外,DroidSkynet 还可以区分给定 App 上使用了哪种代码保护技术,并了解 App 保护技术的趋势。

A.概述设计

在本节中,将概述“DroidSkynet”并描述框架中采用的关键技术。上图展示了“DroidSkynet”的整个工作流程。DroidSkynet 由五个主要部分组成:基础信息分析、源代码提取器、可运行分析、相似性分析、漏洞分析。DroidSkynet 接受一个 App 的多个版本,并返回攻击该 App 的可能性。为了进行分析,DroidSkynet 需要将最新版本与每个早期版本一一比较。具体来说,基本信息分析组件解析最新版本和较早版本中的“AndroidMainfest.xml”文件,然后从中提取基本信息。该信息包括包名称、版本代码和版本名称。最新的基本信息会缓存在内存中,留待以后使用。这部分可以知道正在测试的App和版本,以及每个App的发布时间。源代码提取器从 APK 文件中提取源代码。

可运行分析使用算法 2 确定给定的 App 是否是可运行的。这两个组件仅适用于早期版本。之后,如果早期版本的App是可运行的,使用相似度分析工具来分析最新版本和较早版本的相似度。同时,漏洞能力分析组件分析较早版本是否受到保护。它返回一个值,指示攻击以前版本的App的可能性。最后,在对所有版本进行分析后,该工具会结合上述分析结果,得出App是否受到早期版本威胁的结论。

B.核心引擎实现

在所有组件中,基本信息分析、源代码提取器没有包含太多具有挑战性的问题,而相似性分析基于Simi Droid。因此,在本节中将详细介绍如何实现可运行分析和漏洞分析。

(1)可运行分析

对于不联网的App,只要用户安装它就会一直工作,而对于联网的App,需要测试App中使用的URL是否可用。为了识别 App 是否使用互联网,解析 Android App 的“AndroidMainfest.xml”文件。该文件记录了 App 的运行时权限。如果App使用互联网,它必须在此文件中的权限树上注册。换句话说,如果字符串“uses-permission android:name=”android.permission.INTERNET””可以在文件“AndroidMainfest.xml ”,App可能会使用网络连接。另一方面,由于 App 往往需要过多的权限,因此具有 INTERNET 权限的 App 无疑意味着该 App 需要网络连接 [23]。为了解决这个问题,引入了静态分析框架 Soot 来搜索互联网相关的 API。 Soot 是一个 Java 优化框架,可以处理来自给定 App 的 Android 源代码。它可以将 Android 源代码转换为 Java 实例。函数 getApplicationClasses() 和 getMethods()可以提取类和函数。搜索每个类以查找是否使用了与 Internet 相关的 API,例如 getInputStream() 和 openConnection()。

另一方面,DroidSkynet 遍历源代码文件并返回可用链接的数量。为了识别这些找到的 URL 是否可用,DroidSky 网络遵循 HTTP 状态代码的语义,用于在 HTTP 中传递状态信息。我们链接在源代码中找到的每个 URL,它代表连接操作的结果。根据状态码,可以判断连接是否可用。例如,状态码 200 是对成功请求的响应,而状态码 404 表示服务器没有找到与 Request-URL 匹配的任何内容。实际上,虽然一些 URL 请求可能依赖于其他先前的请求,但状态码仍然是一个可以接受的解决方案。例如,只有在认证请求完全通过后才能发送数据下载请求。当认证失败时,状态码为401。类似的状态码有403和407。也就是说,如果得到上面的状态码,就可以知道请求的URL处于保护状态,但仍然可用。另一方面,根据之前的讨论,无法通过分析可用链接的数量来轻松确定运行是否正常。还应考虑与隐私相关的 URL。每个 URL 代表一个潜在的敏感来源。
漏洞分析

(2)漏洞分析

保护方法分析:保护方法分析确定它使用的保护类型。 组件保护方法分析的一个必不可少的模块是APKTool,它也是设计源代码提取器的关键因素。 APKTool 是一个逆向工程 Android 应用程序的工具。 它将资源解码为几乎原始的形式,例如 AndroidMainfest.xml 和布局文件。 同时解析APK文件中的“classex.dex”,将DEX文件转换为SMALI文件。

提取源代码后,开始分析以识别 LP 和 FP。为了确定源代码是否受 LP 保护,重点介绍了布局混淆的识别方法。基本思想是检查提取的源代码文件的名称是否满足预定义的原则。将文件名作为标识信息,因为文件名可以完全保留原始程序源代码的字符。经过逆向工程后,源代码文件位于“smali”文件夹中。原来的类名转换成这个文件夹中的文件名,包名变成了目录名。在实验中,只考虑类名作为检查布局混淆的标识指示,因为很少发生App在类中混淆其有价值的名称而将类名保留为纯文本的情况。

布局混淆通常使用无意义或不可理解的有价值的名称而不是有意义的名称。例如,经过工具混淆后,代码的有价值的名称由小写字母组成,从一到三(以“abc”为例)。正则表达式将匹配特定格式的单词,用于搜索和替换单词的技术满足预定义的规则。 Java 库提供了现成的算法来查找这些混淆的词。此类单词的正则表达式可以表示为“[a-z]{1,2,3}$”。

另一方面,也有一些混淆的代码行,比如一些函数名,在 Apps 中不满足这样的正则表达式。这些混淆的函数名使用了一些特殊字符来代替原来的变量,导致第一个正则表达式匹配失败。存在一种称为驼峰命名法的通用命名规则来命名 Java 类。实际上,大多数使用驼峰命名规则的类名是由开发人员编写的,而不是由机器编写的。基于这样的事实,构造了一个函数来识别满足驼峰模式的类名。只在第一个正则表达式匹配失败后才使用该函数,以提高运行时的性能。如果程序源代码匹配第一种正则表达式,则代码受到混淆方法的保护,这意味着没有必要进行第二种正则表达式匹配。如果改变这两个函数的顺序,把第二种类型放在前面,需要遍历每个类名并检查它是否满足驼峰命名规则,只有在所有循环完成后才能得到结果。

对于这些使用 FP 来保护其源代码的 App,重点关注这些使用 JNI 技术的 App。如果使用 JNI 技术,可以在逆向源代码中找到调用本机接口的 C/C++ 库。并且这些库经常出现在App的相同位置(在目录根目录的“lib”文件夹中)并使用“. so”以他们的文件名结尾。

值得注意的是,也有很多App使用第三方库来服务(例如LBS服务)或盈利(例如展示广告视图)。在这种情况下,App本身不受保护方法的保护,但其库使用了一些程序代码保护。认为这样的App不应被视为受保护的,因为这些库不用于构建其核心逻辑或可公开访问。当确定App是否受保护方法保护时,这些库被排除在外。为了实现目标,在数据库中收集了常用的第三方库的名称。如果找到的所有库也在数据库中,则将被放弃。

最后,将反馈组件引入分析中以降低错误率。根据漏洞分析的结果,存在一个规律,即升级后发布的App漏洞更小,而不是早期的App。例如,如果发现 2011 年发布的 App 是安全的,但其 2018 年发布的升级版本不安全,那么分析可能有问题。在这种情况下将对这些样品进行标记,然后将手动执行以确认结果。

密码算法分析:污点分析能够确定是否使用了加密算法,将加密 API 的返回值作为源,将网络 API 的污点输入作为sink。本文工具扩展了 Amandroid 框架,它为污点分析提供了先决条件。现在介绍如何扩展 Amandroid。特别是,通过自定义配置文件“TaintSourcesAndSinks”,可以跟踪感兴趣的污点路径。关心以下源和sink。对于来源,关心可以处理加密或解密的函数,例如 cipher:doFinal()。污点sink涉及具有将数据发布到服务器的功能的网络 API 和函数。例如,污染了系统网络函数 urlConnection:getOutputStream():write()。

 

0x06 Experiments and Evalution

A.样本采集

需要选择合适的App,时间跨度是过滤条件。但是,分支所在的时间分区并不能简单地通过应用发布的年份来确定。例如,当一些App诞生时,另一个App已经发布了多个版本,即使它们属于同一类别。同时,对于近期发布的App来说,实验样本可能不够,导致缺乏深入的对比分析。因此,收集了每个App的三个版本。最新版本、能找到的最早版本、以及中间发布的版本。

基于这一原则,从三个分支(每个分支 50 个)中收集了前 10 个类别的 1500 个App,每个类别 150 个。这 10 个类别是:游戏、玩家、浏览器、下载管理器、金融、健身、消息、工具、个人、社交。从 Google Play 和一些第三方市场收集了样本,例如 UptoDown。下图显示了每个分支的发布时间。可以看出,大部分早期版本是在2013年发布的,中间版本是在2015年发布的,而升级版本是在2018年发布的。

B.可运行分析评估

首先执行可运行分析。为此,Droid Skynet 需要检查 App 的网络使用情况以及仍有多少 URL 可用。下表显示了不同类别中 URL 的分布数量。可以观察到,对于大多数使用互联网的App,一个App中存在的 URL 数量平均在 200 个左右。消息App包含的 URL 比任何其他类别都多。一个 App 中存在的 URL 数量平均在 330 个左右。一款名为“Email TypeApp”的App甚至包含 711 个 URL。 URL 的数量随着版本逐渐增加,这表明App变得越来越复杂。

下图提供了App网络使用情况的详细图片。从图中可以了解到,大多数 App 都需要网络连接。具体来说,在500个早期版本中,不需要联网的App只有64个。根据前面的讨论,这些App被认为是可运行的。

在下图中,显示了可用 URL 和敏感 URL 的平均比率。从图中可以看到,每个类别都有超过 50% 的 URL 现在仍然可用。在个人、健身下载管理器和播放器的情况下,甚至超过 70%。这表明这些App的大部分功能都运行正常。在所有可用的 URL 中,将近 30% 被认为是敏感的。所有这些可能包含敏感操作的 URL,例如登录服务器和删除用户的文件。

C.相似度分析评估

然后进行相似度分析。为此,Droid Skynet 结合了所有三个分支,并比较了不同版本之间的相似性。首先检查三个不同版本共享的方法。在这里考虑了两种情况:(i)这些方法在所有三个版本中都存在,没有变化。 (ii) 这些方法存在于彼此相似的所有三个版本中。后者用于描述共享相似方法签名性质和执行逻辑的方法。这些比较方法由 SimiDroid 提供。下图显示了结果。平均而言,对于每个类别的每个App,三个版本中都有超过 23,000 种方法没有改变。与它相比,类似的方法要少得多。这表明开发人员倾向于不加改变地使用这些方法,而不是重新实现它。在所有的 App 中,游戏的相同和相似的方法比任何其他类别都多,因为游戏通常比其他 App 更复杂。

然后检查早期版本和升级版本之间的相似性,以及中间版本和升级版本之间的相似性。下图显示了结果。平均而言,对于每个类别的每个App,早期版本和升级版本之间的相似度约为 30%(29.7%),而中间版本和升级版本之间的相似度约为 50%(47.3%)。在所有应用中,游戏与其他应用相比,每个版本之间的相似度更大。这证实了在介绍部分的陈述。游戏可能会添加新角色或新场景,使其更有趣。如何玩的基本思想可能不会改变太多。另一方面,微信和Whatsapp等消息应用与其对应的升级版本不太相似。对于这些App,用户对通信速度和用户体验,甚至安全性都有更高的要求。因此,这些App的开发者希望改进这些功能以满足用户的需求。

D.漏洞分析评估

为了证明 DroidSkynet 提供有关潜在攻击检测的高质量情报,使用手动方法对其进行评估。评估样本涵盖健身类别,共包含 150 个App。在手动方法中,关注保护方法分析的准确性。在实验中,DroidSkynet 可以无错误率地检测所有 LP 和 FP。因为只关心布局保护和JNI保护,这两个比较容易识别。在未来的工作中,工具将支持更复杂的 LP 和 FP 功能。

首先展示了所有三个分支中使用的保护方法。从上图中可以看出,没有任何保护的App正在逐渐减少。随着时间的推移,没有任何保护的数字在某些类别中甚至下降到零,这表明今天的开发人员比以前更加重视代码保护。因此,利用升级的App比利用早期的App要困难得多。下降最快的类别是金融,推断这些App涉及支付功能,这使得开发人员必须加强代码保护以防止攻击者。但是对于游戏、消息等其他的来说,他们的坡度比较平缓,一开始的位置比较低。这表明他们的代码在开发之初就受到了很好的保护。这些类别的App往往是由企业而不是个人开发者开发的原因。企业高度重视产品的安全性,拥有大量可用的软件开发资产,这使得个体开发者的创造在这些方面没有优势。相比之下,与其他类别相比,个人App中的创造力和创新特征比安全性更有意义,这导致这些类别的斜率下降得更慢,而它们的起点更高。

从上图可知,LP一般是前期首选的保护方式。这样做的原因是,布局混淆作为一种常用的LP方法,已广泛应用于其他程序代码保护领域。因此,将 LP 应用于 Android 代码保护是微不足道的。这三个数字都表明,虽然现在App得到很好的保护,但早期版本的保护很差是可能的。

上图显示了App使用的加密保护方法。可以观察到,加密保护的App版本逐渐增加,这表明破解升级后的App比破解早期的App要困难得多。在所有App中,游戏的开发者希望使用加密方法来增强他们的App。手游中使用的作弊工具很多,流行的作弊工具有几十种,打破了游戏的平衡。因此,涉及密码学方法是一种处理平衡问题的方法。

最后,基于以上所有因素和算法 1,可以计算出以早期版本为攻击向量的 App 攻击成功率。在例子中,IFcrypto 和 IFP 的值都设置为 0.5。上表显示了最终结果。 DroidSkynet 发现使用“中间”版本和早期版本攻击App的成功率分别为 21% 和 13%。使用较早版本攻击App的成功率总计为 34%。所有这些受影响的App也可以被利用来被动地公开各种类型的App数据,例如哈希盐,或者可能随后导致安全问题的不良 API。虽然实验中的某些类别没有受到太大影响,例如消息类别,但这并不意味着这些 App 就足够安全。原因之一是检测结果与样本集的大小有关。

 

0x07 Discussion

A.潜在威胁

已经知道早期版本的 App 可以用作攻击媒介。当早期版本被成功逆向时,攻击者还可以知道以下信息:

1) 核心引擎:明显的例子是在上一部分提到的游戏和工具App。获取早期版本的程序代码将帮助攻击者重建盗版App,从而威胁到原始开发者的知识产权。

2) 用户界面设计:一些软件的用户界面从一开始就发生了一些变化。布局描述是显示在位于文件夹 /res/layout/ 中的布局文件中的文本。通过使用逆向工程,攻击者可以窃取App的 UI 设计。

3) 编程风格:编程风格也是公司的隐私,可以从App中提取出来。很少有公司经常改变编程风格,而好的编程风格优化了编码效率。

4) 潜在的漏洞:正如之前讨论的,访问认证和一些弱接口可以用来发起攻击。更重要的是,一些攻击者可能会通过早期版本来破解App,绕过收费App的注册。

B.问题的根本原因

现在企业之间的竞争越来越激烈。一个没有良好可维护性和可扩展性的 App 是不会长久存在的。遗憾的是,版本升级是一个复杂的过程,会耗费大量的财务成本和资源。为了让版本更新更顺畅,开发者不仅要实现功能性,还要在设计过程中兼顾高内聚和低耦合。因此,当漏洞发生时,开发者通过调整模块而不是重写整个App来修补它,这使得大多数旧模块作为升级模块的一部分被重用。因此,早期版本存在的漏洞仍然保留在升级版本中。

在用户方面,老用户可能会拒绝升级App,因为他们无法承受升级版本提供更多服务带来的高额计算和存储成本。一些以前的用户可能不想更新他们的App,因为升级版本通常需要更好的设备、更多的计算能力和更多的存储空间。因此,旧版本中使用的早期 API 不能直接关闭,尽管它们可能不够安全。

C.缓解

由于开发者不能放弃不想升级他们的App的用户,因此很难防止App遭受此类攻击。在现实生活中,一些App希望每隔几周更新一次客户端,而服务器仍会支持早期版本,直到几个月后。这是安全性和便利性之间的正确平衡点。虽然有些App今天不能被攻破,但这并不意味着它在未来永远不会被逆向。随着逆向工程技术的进步,目前被认为是安全的App,可能有一天会被攻破。因此,持续保持程序代码保护的开发过程并定期关闭早期的API,可以缓解此类问题。

 

0x08 Conclusion

在本文中定义并研究了一个问题,即早期版本的 App 会使升级后的 App 面临被攻击的风险。 由于早期版本很容易受到逆向工程技术的影响,因此早期版本中存在的漏洞可以作为构建块对升级版本发起更严重的攻击。 在示例中对Cloud-Driven发起了 MITM 攻击,并破解了来自 Facebook 和Weibo的 HMAC 密钥。 此外,通过逆向工程技术设计了一个静态分析器DroidSkynet,以检测大量App中的此类潜在问题。 DroidSkynet 使用从现实世界中收集的 1500 个App进行评估。 实验结果表明,这些 App 中大部分都存在此类问题。 使用较早版本攻击 App 的成功率为 34%。 此外还提出了一些建议,以弥合 App 更新的实用性和安全性之间的差距。

(完)