微信号:gh_37ebe37722aa

介绍:txx的笔记分享

iOS 10 Music 架构解析

2016-06-28 09:35 txx

前言

众所周知,iOS 10 发布了。然而可能大家并不知道,iOS 10 的刷机包并没有加密。我们可以通过解压后挂载 dmg 镜像的方法,装载 iOS 系统分区。


在这里,我们能做什么呢?作为一个 iOS / Android 双料开发者,我非常喜欢围观 Android 系统自带的 app 源码,毕竟那是 Google 的工程师认为的最佳实践。

而这次我们也能近距离的围观一下 iOS 内置的书写方式,于是这里我们选择了 Music.app 来做小白鼠。

Music.app

为什么是 Music? 因为在 WWDC 上 Chris 的 ppt 上有这张图:

Music 用 Swift 重写了,那么我们肯定要看看苹果是如何用 Swift 的!

在 /Applications 里面找到 Music.app 右键打开

瞬间一脸蒙逼:

Wut? JS?不过我们也知道 Music 有 Android 版本,大概是通过 JSB 来做跨平台吧。是不是对这个 App 的架构就更有兴趣了?

Framework

我们在看 Binary 的内部结构之前,要看看它都使用了那些 dylib, framework。以便我们更好的了解它的结构。

这个时候就又掏出了 Mach-O Viewer:

在这里,我们看到了非常多没见过的 PrivateFramework

点击这些 framework 详情的时候可以看到:

就连 Swift 的运行时都被集成在了 /System/Library/PrivateFrameWork 里面,看来 Swift 运行时集成到 iOS 10 中,即日可待。

当我们随便打开一个 Framework 的时候,例如 /System/Library/PrivateFrameWork/FuseUI.framework,发现:

对着目录结构看了好几遍,露出了这样的表情

Binary 呢?

经过查询系统文档,了解到在 iOS 3.0 之后,苹果为了优化动态链接库的启动速度,把所有的动态链接库全封到了一个包中:/System/Library/Caches/com.apple.dyld

既然被封装起来了,那么肯定是有办法解压的。非常有趣的是苹果开源了这部分代码: http://opensource.apple.com/source/dyld/

我们把其中的 dsc_extractor.cppdsc_iterator.cpp 单独拎出来创建个工程,写个 main 函数入口,做一个命令行工具。于是就成功的解压了这堆文件。

通过把 Framework 创建依赖关系拓扑图,我们可以得到这样的一个层级架构。


而,除了最上层的 Music,其他的都是 OC...苹果的团队也深受 OC Swift 混编之毒..

JavaScript

看完了 Framework 的依赖,我们去看 JavaScript 的结构。

通过阅读代码,我们可以发现整套 JS 代码很简陋,还有很多 ToDo 的标示。

基本上分为两部分,一部分是 BridgeObject 的子类,其中包括 View, Model, Controller。

另一部分 ViewModel 的子类,当然 ViewModel 本身也是 BridgeObject 的子类。

除了这两部分,项目里面还有两个额外的类,Native.js 和 NativeBridge.js

Native.js 用来管理全部的 JSClass 如图

NativeBridge.js 用来和原生代码进行通信。

Swift 逆向

我么大概知道了 JS 的架构,但我们并不知道它到底是和原生是怎么通讯的。

我们只能把 Music 的二进制塞入 Ida Pro。

然后就被狂拽炫酷的符号惊到了:

这看起来是一屏幕乱码的东西,但事实上它是有章可循的:

  • _T – The prefix for all Swift symbols. Everything will start with this.

  • F – Function.

  • C – Function of a class. (method)

  • 9swifttest – The module name, with a prefixed length.

  • 5Shape – The class name the function belongs to, again, with a prefixed length.

  • 17simpleDescription – The function name.

  • f – The function attribute. In this case it’s ‘f’, which is just a normal function. We’ll get to that in a minute.

  • S0_FT – I’m not exactly sure what this means, but it appears to mark the start of the arguments and return type.

  • ‘_’ – This underscore separates the argument types from the return type. Since the function takes no arguments, it comes directly after S0_FT.

  • S – This is the beginning of the return type. The ‘S’ stands for Swift; the return type is a Swift builtin type. The next character determines the type.

  • i – This is the Swift builtin type. A lowercase ‘I’, which stands for Int.

非常令人感动的是, Xcode 提供了把这个符号化的工具: xcrun swift-demangle

例如:

_TTSf4g_n___TFE5MusicCSo12NSHTTPCookiecfT15scriptingCookieCS_8JSCookie_GSqS0__

运行之后:


是不是比 OC 更容易看懂?

于是我们可以做个脚本,或者 ida 插件,把所有的函数符号化掉。得到了一个这样的东西:


经过一些搜索分析,我们会得出大概如下几个结论:

  • 所有 JSClass,如 FlowcaseItem.js 都会生成一个对应的 Swift Class,即截图中的 Music.JSFlowcaseItem 父类是 Music.JSScriptingInstantiatedClass

  • 所有的 Swift JS 对应类都实现了协议 JSScriptingDriven

  • JSScriptingDriven 定义了 invokeMethod, updateProperty 两个方法

  • 交互方式分两种,一种是通过 JSDrivenViewController 一种是通过诸如initWithScriptingCookie 这样的方法。

总结

通过这篇文章,我们能了解到:

  • iOS 10 ipsw 没有加密,可以随便乱搞

  • 苹果对系统 dylib 的加载做了很多优化 (我下一篇文章还会再提到他)

  • 我们可以通过 dyld 来解压系统库

  • Swift 在 ida 下是一览无遗的,而且通过还原符号,可读性比 OC 更强,毕竟是带着参数类型的

  • 苹果做的 JSB 非常原始,先不说 React Native,还不如 JSPatch 来写 UI



下一篇文章会写 WWDC 406 optimizing app startup time,满满地干货,敬请期待。不要犹豫,赶紧订阅我的公众号吧~





 
糖炒小虾 更多文章 另辟蹊径的网络协议分析方法 逆向分析网络协议 iOS 篇 给那些刚入行的 iOS/Android 开发新手们的一些建议 [一周一算法] 基础知识 如何正确理解 Bitcode
猜您喜欢 SORTING:可视化展示排序算法的原理,支持单步查看 平安金融科技移动技术周报(第十六期) 使用ViewPager动画来做出不一样的引导页 React移动Web极致优化 | 腾讯团队从0到1的经验总结 如何在2年内让收入翻两番?我用了700个夜晚就做到了!