Xcode 7 Bitcode的工作流程及安全性评估

2015-12-18 06:13 编辑: suiling 分类:iOS开发 来源:FreeBuf黑客与极客

简介

随着 Xcode 7 的发布,苹果为 Xcode 增加了一个新的特性 Bitcode [1]:

新的特性往往意味着新的攻击面。本文首先介绍什么是 Bitcode 及 Bitcode 相关的工作流程,在熟悉了 Bitcode 的工作流程后,接下来是评估 Bitcode 相关的攻击面,最后介绍针对各个攻击面的测试方法及目前的测试结果。

什么是 Bitcode

简单来说,Bitcode 是 LLVM-IR 在磁盘上的一种二进制表示形式。关于 Bitcode 详细描述,请参考[2],这里会用例子来让大家对 Bitcode 有个感性认识。

先写一个简单的 C 程序,功能是计算两个数的和,代码如下:

1
2
3
4
5
int add(int a, int b)
{
      int c = a + b;
      return c;
}

将如上程序保存为 add.c,然后我们将源程序编译成 Bitcode:

1
clang -emit-llvm -c add.c -o add.bc

执行如上命令会生成 add.bc,我们使用二进制编辑器打开生成的文件,查看文件内容:

由于 Bitcode 是 LLVM-IR 的二进制表示形式,如上图,在不了解编码方式的前提下基本不可读。下面我们把 Bitcode 转换成文本形式:

1
llvm-dis add.bc -o add.ll

用文本编辑器打开 add.ll,可以看到 add 函数的 LLVM-IR 内容如下:

对比源码与已经注释过的 add() 函数的 LLVM-IR 表示,大家应该对 LLVM-IR 有个感性认识了,下面我们一起看下 Bitcode 的工作流程。

工作流程

苹果关于工作流程的描述:

“ When you archive for submission to the App Store, Xcode compiles your app into an intermediate representation. The App Store then compiles the bitcode down into the 64- or 32-bit executables as necessary.”

如上的工作流程可以分为两个阶段:

  1. 在将应用上传到 AppStore 时,Xcode 会将程序对应的 Bitcode 一起上传。

  2. AppStore 会将 Bitcode 重新编译为可执行程序,供用户下载。

下面会将 Bitcode 相关的完整的工作流程分解为如下几个问题或子过程并分别做说明:

  1. Where is the Bitcode?

  2. 嵌入 Bitcode 的方法

  3. 从 Bitcode 生成可执行程序的方法

Where is the Bitcode?

参考苹果的描述,只有在 Archive 时才会生成 Bitcode,于是建立了一个测试工程:

执行 Archive,然后查看生成的包结构:

经过分析在如上的目录中并没有直接找到 Bitcode,接下来检查生成的 MachO。使用 MachOView 加载生成的 MachO,结果如下图:

从上图可以看到最终的可执行程序中多了 LLVM 相关的 Segment 与 Section。继续查看对应的 Section 的信息:

如上图,Section __bundle 中保存的是一个 xar 文档,提取出 xar 文档,然后使用如下命令解开文档:

1
解开:xar -x -f XXX.xar

解开后,可以看到 Bitcode 文件。

总结:程序对应的 Bitcode 被 Xcode 打包成 xar 文档,嵌入的 MachO 中。

下面我们看下在 MachO 中嵌入 Bitcode 的方法。

嵌入 Bitcode 的方法

方法一

通过对比 Archive 与非 Archive 时的编译参数,发现只要在如下图所示的位置添加编译参数:-fembed-bitcode,即可让 Xcode 普通编译时也在 MachO 中嵌入 Bitcode:

方法二

方法一虽然很方便,但是 IDE 做了太多工作,不便于理解具体过程,接下来我们自己编译可执行文件。从源代码生成可执行程序主要分为:编译、链接两个过程,为了控制这两个过程,下面会讲解 Makefile 的配置,及这两个过程用到的参数。

在使用 Makefile 编译 iOS 程序时,有些通用的配置,如下的通用配置,供大家参考:

以 main.m 为例说明编译需要的参数:

将 main.o,AppDelegate.o,ViewController.o 链接成可执行程序的参数:

大家把如上的 Makefile 片段稍加修改,整理到一个 Makefile 文件中,就可以通过 make 命令嵌入 Bitcode 到可执行程序。

方法三

在这个方法中我们会将上面的步骤进一步分解,具体过程为:

源码→Bitcode→xar→可执行程序

源码→Bitcode

在这个过程中我们将 iOS 应用的源码编译成 Bitcode,下面会 main.m 为例来说明使用的参数:

完成这个过程后,我们可以得到三个Bitcode 文件:

  • main.bc

  • AppDelegate.bc

  • ViewController.bc

Bitcode→xar

在这一步我们会将如上得到的三个 Bitcode 文件打包到一个 xar 文档中。打包没什么特别,需要注意的是需要与 Xcode 生成的 xar 保持兼容,具体参数如下:

生成:xar –toc-cksum none -c -f BC.xar main.bc AppDelegate.bc ViewController.bc

xar→可执行程序

为了简化过程,这里我们会跳出 Makefile,使用 Xcode,首先清除如下的编译参数:

将刚刚生成的 BC.xar 拷贝到测试工程的根目录:

编辑工程设置的 Other Linker Flags,添加:-Wl,-sectcreate,__LLVM,__bundle,$(SRCROOT)/BC.xar,如下图:

编译程序,查看生成的 MachO 文件,可以看到 Bitcode 已经被添加到了 MachO 中。

如上我们介绍了在 MachO 中嵌入 Bitcode 的方法,对应的是第一个过程:“在将应用上传到 AppStore 时,Xcode 会将程序对应的 Bitcode 一起上传”,下面我们说明第二个过程。

从 Bitcode 生成可执行程序的方法

第二个过程为:“AppStore 会将 Bitcode 重新编译为可执行程序,供用户下载”。第二个过程是在苹果的 Server 上进行的,我们没法直接获得细节,但是应该都是基于相同的工具链,我们可以模拟这个过程。

从 MachO 中提取 Bitcode

AppStore 拿到我们上传的 IPA 后,首先需要从 IPA 内的 MachO 文件中提取出包含 Bitcode 的 xar 文档。在 Xcode 的工具链中有个工具 segedit 可以用来从 MachO 提取 Section,提取 xar 的具体参数如下:

提取到 xar 后,解开 xar:

得到如下几个 Bitcode 文件:

还可以使用 llvm-dis 工具将如上文件处理成可读形式,从而了解每个文件的内容。

生成可执行程序

在有了 Bitcode 后,接下来需要将 Bitcode 编译成可执行程序,分为两个过程:将 Bitcode 编译成 Object 文件;链接 Object 文件到可执行程序。

  • 将 Bitcode 编译成 Object 文件

Makefile 片段如下:

  • 链接 Object 文件到可执行程序

如上我们已经从 Bitcode 重新生成了可执行程序 XBCTest。

攻击面

我们先回顾下 Bitcode 在本地的工作流程:Xcode 将嵌入了 Bitcode 的 MachO 上传到 AppStore。通过分析可以发现这里存在两个问题:

1.MachO 与其中嵌入的 Bitcode 的一致性问题。即:能否把 程序B 的  Bitcode 嵌入到 程序A中。

2.AppStore 是否信任了 Xcode,而没有检查一致性问题,从而允许将   Malformed MachO 上传到 AppStore。

在分析了可能存在的问题后,我们认为如果 Bitcode 流程与功能存在缺陷,便可以对两个目标形成威胁:普通用户、苹果。

普通用户

由于 Bitcode 对普通用户是透明的,因此无法通过其弱点直接攻击用户。但是一致性问题是可能对普通用户造成威胁的,试想:如果提交 AppStore 审核的 程序A 中嵌入了含有恶意代码的Bitcode,普通用户就有可能从AppStore 下载到含有恶意代码的程序。

对于这种攻击方式我们将其叫做 Bitcode Injection,下文会详细介绍这种攻击的实施方法,及我们的测试结果。

苹果

如果 Malformed MachO 可以被上传到苹果的服务器,苹果的服务器相较于之前,主要需要进行两个额外的操作:解开 xar;编译 Bitcode。如果这两个过程出现问题,轻则可以在苹果的服务器上造成 DoS,重则可以在苹果的服务器上造成任意代码执行。

另外,Bitcode 原本是 LLVM-IR 的一种序列化形式,而 LLVM-IR 是一种中间形式,之前没有被直接暴露出来,现在完全开放了,而且又是二进制格式,这是很容易出问题的。从 Bitcode 生成可执行文件的过程主要由如下几个子过程组成:

1.基于平台无关的 IR的代码优化。

2.IR的平台相关化、合法化。

3.平台相关的优化、代码生成。

这些原本是编译器的内部过程,由于各种原因,传统的对编译器的测试主要集中在前端的 Parser 与 Lexer,现在借由 Bitcode 如上的一些中间或者后端过程也暴露了出来,如果如上的过程出现问题最糟糕的结果是可以控制编译器的指令生成。

以上是关于攻击面的分析,后文会介绍测试 xar 及 Bitcode 的思路,以及发现的问题。

Bitcode Injection

上文在介绍 Bitcode 工作流程时已经介绍了实施 Bitcode Injection 的方法,但是上面提到的方法不够简练,这里我们再介绍一种更简单的方法,主要的思路就是最大限度的利用 Xcode,这个方法的具体实施步骤为:

  1. 用 Xcode 建立工程XBCTest:

2. 复制工程XBCTest,得到工程XBCTest2:

3. 修改工程XBCTest2的源码,嵌入恶意代码:

4. Archive 工程XBCTest2:

5. 获得 MachO,利用 segedit 从 MachO 中提取出含有 Bitcode 的 xar:

提取xar: segedit ./XBCTest -extract "__LLVM" "__bundle" BC.xar

6. 修改工程XBCTest的链接标记,将提取的 xar: BC.xar 嵌入到工程XBCTest的 MachO文件中。

7. 禁用工程XBCTest的 Bitcode 特性,Archive 并上传 AppStore:

我们在测试的过程中并没有嵌入恶意代码,而是从网上找个两个完全不同的应用,将其中一个的 Bitcode 嵌入到另一个的 MachO 中,并提交到AppStore。

在将应用提交到 AppStore 的过程中主要会进行两个方面的检查:Xcode 在本地进行静态分析;提交后,苹果的服务器还会进行检查。但是使用 Bitcode Injection 构造的应用可以通过这两项检查:

经过漫长的审核后,我们的应用被拒了,理由是:我们的应用与描述不符。在描述中我们的应用应该长成如下样子:

但是苹果的审核人员安装后,程序却长成这个样子:

这至少可以说明三个问题:

1.我们使用的 Bitcode Injection 方法没有问题。

2.苹果的审核人员审核的是从 Bitcode 编译出来的程序。

3.一致性是靠人肉区分的。如果嵌入对 UI 没有影响的恶意代码,还是有可能绕过审核的。

测试xar

思路

对 xar 进行模糊测试,生成数据的方法是基于标准的 xar 文档进行变异。

测试结果

目前主要 Fuzz 出一些空指针解引用问题。

测试 clang

思路

对 clang 中的Bitcode 到 Object 的功能进行模糊测试,也是采用变异的方法生成测试数据。

测试结果

通过对 clang 的 Fuzz 我们发现了一些堆损坏相关的问题。

总结

1. The Xcode 7 bitcode feature has opened a huge attacking surface, Apple should do something to narrow it, for example: checking the bitcode is identical to the related MachO file.

2. 在上文中我们详细介绍了所考虑到的攻击面,及针对每个攻击面的测试思路,希望这些对大家研究 Bitcode 相关的攻击面及安全性有帮助。

参考资料

[1] What’s New in Xcode

[2] LLVM Bitcode File Format

作者:360NirvanTeam(企业账号)

(转) Xcode 7 Bitcode的更多相关文章

  1. 深究Xcode的bitcode设置

    深究Xcode的bitcode设置 转发至:http://www.jianshu.com/p/f42a33f5eb61 前言 做iOS开发的朋友们都知道,目前最新的Xcode7,新建项目默认就打开了b ...

  2. 深入理解iOS开发中的BitCode功能

    前言 做iOS开发的朋友们都知道,目前最新的Xcode7,新建项目默认就打开了bitcode设置.而且大部分开发者都被这个突如其来的bitcode功能给坑过导致项目编译失败,而这些因为bitcode而 ...

  3. 【转】iOS bitcode实战 -- without full bitcode

    原文网址:http://www.voidcn.com/blog/GrowingGiant/article/p-5012705.html 关于bitcode的介绍,直接看下边两篇: 理解Bitcode: ...

  4. 升级到iOS9之后的相关适配

    iOS9AdaptationTips(iOS9开发学习交流群:458884057) iOS9适配系列教程[中文在页面下方]转自@iOS程序犭袁 (截至2015年9月26日共有10篇,后续还将持续更新. ...

  5. iOS.AppThinning-iOS9-new-feature-for-app-thinning-bitcode-odr-slicing

    Bitcode 0. Introduction to Bitcode 1. Build static library or framework via Xcode 7, while user buil ...

  6. iOS9适配系列教程

    链接地址:http://www.open-open.com/lib/view/open1443194127763.html 中文快速导航: iOS9网络适配_ATS:改用更安全的HTTPS(见Demo ...

  7. Xcode7 *** does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE)

    *** does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE ...

  8. Xcode 7.0升级后的bitcode

    iOS 9.0中加入了一个新的功能,bitcode, 使用bitcode优化的app,体积可以变得更小. Apple可以在提交app后,向9.0及以上版本用户提供优化的小体积版本,向其他用户提供常规版 ...

  9. Xcode命令行生成Bitcode静态库

    近两三年一直在做静态库开发 1.在Xcode工程中创建静态库的Target,最初是手动Build出真机的.a文件,模拟器的.a文件,然后再用命令行合并 2.后来一些特殊的开发者,要求加入特殊的功能,或 ...

随机推荐

  1. 在update时用触发器插入数据

    CREATE trigger [dbo].[Debt_Insert] on [dbo].[Debt] for insert as declare @tmpOrderID1 varchar(30)sel ...

  2. [转]搭建高可用mongodb集群(四)—— 分片

    按照上一节中<搭建高可用mongodb集群(三)—— 深入副本集>搭建后还有两个问题没有解决: 从节点每个上面的数据都是对数据库全量拷贝,从节点压力会不会过大? 数据压力大到机器支撑不了的 ...

  3. Linux 设备驱动程序 proc seq

    不能再简化 #include<linux/module.h> #include<linux/init.h> #include<linux/seq_file.h> # ...

  4. asp.net ajax控件tab扩展,极品啊,秒杀其它插件

    说明:asp.net ajax控件tab要设置width和height,而且在线文本编辑器放能够放入tab中,也必须是asp.net的控件型在线文本,例如fckeditor,下面是我设置好的配置. & ...

  5. 伪静态重写模块rewrite.dll及httpd.ini文件参考下载

    伪静态重写模块rewrite.dll及httpd.ini文件参考下载 http://www.ledaokj.com/download/rewrite.rar 服务器端开启伪静态,可以查看以下文章< ...

  6. json转类

    JavaScriptSerializer js = new JavaScriptSerializer();T detaile = js.Deserialize<T>(json);

  7. μC/OS-Ⅲ系统的源代码文件组织结构

  8. Swift运算符

    运算符分类 运算符分类 一元运算符 1.负号运算符 var number1 = var number2 = -number1 2.正号运算符 //正号运算符不做任何操作 var number3 = + ...

  9. HTML5 History API 实现无刷新跳转

     在HTML5中, 1. 新增了通过JS在浏览器历史记录中添加项目的功能. 2. 在不刷新页面的前提下显示改变浏览器地址栏中的URL. 3. 添加了当用户单击浏览器的后退按钮时触发的事件. 通过以上三 ...

  10. android 测试 Monkey 和 MonkeyRunner 的使用

    一.Monkey的使用 Monkey使用起来比较简单,简而言之就是模拟手机点击效果,随机发送N个点击动作给手机,主要对于程序的稳定和承受压力的测试. 1.首先连接上你的手机或者启动模拟器: 2.运行C ...