蒸米是谁?他是阿里的资深安全工程师,是最先对 XcodeGhost 进行样本安全分析的人(见:Xcode编译器里有鬼 – XcodeGhost 样本分析 )。实际上,XcodeGhost 这个名字,也是最先出自于蒸米的文章中。
在 XcodeGhost 作者跳出来说已经关闭了远程控制服务器后,他也是最先一个用实验证实可以伪造服务器进行「截胡」攻击的人(见:XcodeGhost截胡攻击和服务端的复现,以及UnityGhost预警 )。
这次,他发现了一个绕过非越狱 iPhone 沙盒的漏洞,并公布了相关视频,视频见:绕过非越狱手机沙盒漏洞被发现。
而公开漏洞并不是为了炫耀,而是为了最终推动 iOS 的安全发展,所以蒸米打算写一系列文章,介绍这里面涉及的相关技术,这些文章会首发在乌云上。我得到了蒸米的授权,转载于此。
许多人发现漏洞,都想的是如何利用漏洞给自己带来利益。而蒸米的想法却是:先公开视频,然后再提交给乌云(当然乌云会报告给厂商),然后再一点点介绍技术细节。等最终完整的技术细节出来的时候,这个漏洞应该已经无法有什么实质性的危害了。
这,就是一个「白帽子」的职业操守和理想。
感谢蒸米的分享和授权,本文的所有打赏归蒸米所有,以下是文章正文。
冰指的是用户态,火指的是内核态。如何突破像冰箱一样的用户态沙盒最终到达并控制如火焰一般燃烧的内核就是《iOS 冰与火之歌》这一系列文章将要讲述的内容。
但在讲主线剧情前,我们今天先聊一聊分支剧情 - 在非越狱的 iOS 上进行 App Hook。利用这个技术,你可以在非越狱的 iOS 系统上实现各种 hook 功能(e.g., 微信自动抢红包,自动聊天机器人,游戏外挂等),但写这篇文章的目的并不是鼓励大家使用外挂,更不是鼓励大家去卖外挂,所以千万不要用这个技术去做一些违法的事情。
《iOS 冰与火之歌》系列的目录如下:
在非越狱的 iOS 上进行 App Hook(番外篇)
█████████████
█████████████
█████████████
另外文中涉及代码可在我的 github 下载:
https://github.com/zhengmin1989/iOS_ICE_AND_FIRE
要是看过我写的安卓动态调试七种武器之离别钩 – Hooking(上)http://drops.wooyun.org/tips/9300 和 安卓动态调试七种武器之离别钩 – Hooking(下)http://drops.wooyun.org/papers/10156 的同学应该知道在 android 进行 hook 的方法可以是五花八本的。
其实在 iOS 上进行 hook 的方式也有很多,但是大多数都需要越狱后才能实现(比如大家最常用的 Cydia Substrate),今天我就来介绍一种不需要越狱就能 hook iOS app 方法,也就是Mach-O LC_LOAD_DYLIB Hook
。这种方法是通过修改 binary 本身来加载第三方 dylib 并实现 hook,具体思路是:
提取 ipa 中的二进制文件 -> 修改二进制文件的 Load Commands 列表,加入要 hook 的 dylib –> hook.dylib 在函数 constructor 函数中完成对特定函数的 hook-> 对修改后的 ipa 进行签名,打包和安装。
首先我们先来看一下我们将要进行注入的目标 app,这个 app 非常简单,就是调用上一章讲过的 talker 这个类输出一句”Hello, iOS!”。
在 Products 文件夹中我们能够看到 IceAndFire.app 这个文件,也就是编译完后的 app:
IceAndFire.app 其实就是个文件夹,里面可以看到很多的资源文件(签名信息,图片等),但最重要的东西就是与文件夹同名的 IceAndFire 这个二进制文件了。我们可以用 xxd 命令来看一下里面的内容:
这个二进制文件里保存了 IceAndFire 这个 app 的所有逻辑,但是直接看二进制编码太辛苦了,这里我推荐一个叫做 MachOView 的软件(可以在我的 github 里下载),通过这个软件就可以看到整个 MachO 文件的结构了:
在 Load Commands 这个数据段里,我们可以看到 IceAndFire 这个二进制文件会在启动的时候自动加载 Foundation, libobjc.A.dylib 等动态库。如果我们对 MachO 这个文件的 Load Commands 结构体进行修改,是不是就可以让 IceAndFire 这个 app 在启动的时候加载我们自定义的用来 hook 的 dylib 呢?没错,这个想法是可行的。并且我们只要在 dylib 的构造函数里完成相应的 hook 逻辑,就可以在 app 启动的时候对指定函数进行 hook 操作了。
那么如何修改 MachO 的结构体呢?用 010 editor 等二进制编辑器的确是一种方法,但实在是麻烦了点。好消息是金正日小分队已经把自动注入 dylib 的工具帮我们写好了。这个叫 yololib 的工具可以帮我们直接进行 dylib 的注入:https://github.com/KJCracks/yololib。但作者只放出了源码没有放出 binary,我帮大家编译了一份扔到了我的 github 上 (https://github.com/zhengmin1989/iOS_ICE_AND_FIRE)。
编译好 yololib 后,我们只需要在 mac 上执行:
#!bash
./yololib [binary] [dylib file]
./yololib [被插入 dylib 的二进制文件] [要插入的 dylib]
命令即可完成 dylib 的注入,如图所示:
现在我们再用 MachOView 看一下 IceAndFire 这个二进制文件就会看到 hook1.dylib 已经被我们成功注入进去了:
“@executable_path/hook1.dylib
” 的意思是二进制文件会在当前目录下对 hook1.dylib 进行加载,所以我们编译好的 hook1.dylib 要和二进制文件一起放到 IceAndFire.app 文件夹里,这样才能保证我们在运行 app 的时候 hook1.dylib 能够被正确的加载。
修改好了 app 二进制文件的 Load Commands 结构体后,我们再来看看如何构造进行 hook 的第三方 dylib。因为 app 自己肯定不会主动调用第三方 dylib 中的函数,所以如果我们想要让第三方 dylib 进行 hook 操作就要把 hook 的逻辑写到构造函数里。实现构造函数很简单,只要在函数前声明 ”__attribute__((constructor)) static
” 即可,我们先写个”Hello, Ice and Fire!” 测试一下:
编译好 dylib 文件后,我们将这个 dylib 文件与 app 一起签名、打包、安装。然后我们运行一下程序就可以看到我们注入的 dylib 库已经在程序启动的时候成功加载并执行了。
下一步就是要实现对特定函数的 hook。在这里我推荐使用 CaptainHook 这个 framework。作者已经帮我们实现了 hook 所需要的各种宏,只要按照如下步骤就可以完成针对特定函数的 hook:
使用 CHDeclareClass() 声明想要 hook 的 class
在构造函数中用 CHLoadClass() 或 CHLoadLateClass() 加载声明过的 class
使用 CHMethod() hook 相应的 method
在 CHMethod() 中可以使用 CHSuper() 来调用原函数
在构造函数中使用 CHClassHook() 来注册将要 hook 的 method
比如我们想要 hook Talker 这个 class 里的 say method,让 app 在调用 say 的时候修改 method 的参数,让 say 的话都变成”Hello, Android!”,我们只需要这样编写 dylib 的源码:
#!objc
#import <CaptainHook/CaptainHook.h>
CHDeclareClass(Talker);
CHMethod(1, void, Talker, say, id, arg1)
{
NSString* tmp=@"Hello, Android!";
CHSuper(1, Talker, say, tmp);
}
__attribute__((constructor)) static void entry()
{
NSLog(@"Hello, Ice And Fire!");
CHLoadLateClass(Talker);
CHClassHook(1, Talker,say);
}
CHMethod() 这个宏的格式是:参数的个数,返回值的类型,类的名称,selector 的名称,selector 的类型,selector 对应的参数的变量名。
CHClassHook() 这个宏的格式是:参数的个数,返回值的类型,类的名称,selector 的名称。
编写完代码后,我们对源码进行编译,将生成的 dylib 文件与 app 一起签名、打包、安装。然后我们运行一下程序就可以看到我们注入的 dylib 库已经成功的 hook 了 say method 了,原本应该输出”Hello, iOS!”,已经被我们成功的变成了”Hello, Android!”:
0x03 签名、打包和安装
我们知道越狱后的 iPhone 有一个很重要的特性就是可以关闭 app 的签名校验,关掉签名校验后,App Store 上的 app(无论是收费的还是免费的)就可以随意盗版并且免费安装了。但是在非越狱的 iPhone 上,系统要求 app 必须要有合法的签名,负责无法进行安装。其实除了 AppStore 上的 app 有合法的签名外,我们还可以使用开发者证书或者企业证书来让没有合法签名的 app 拥有合法的签名。
当我们拥有开发者帐号并且在机器上安装了证书的话,就可以在 Keychain Access 这个工具中看到我们的签名信息:
我们接下来要干的事情就是使用这个开发者证书来对我们修改后的 IceAndFire .app 进行签名。步骤如下:
首先先保证 IceAndFire.app 文件夹下有正确的 embedded.mobileprovision 文件:
如果没有的话,可以去苹果的开发者中心(developer.apple.com)生成。如果是个人开发者要注意将 iOS 设备的 UDID 加到开发者的设备列表中再生成 embedded.mobileprovision 文件,如果是企业证书则没有设备数量的限制。
正确的编写签名时使用的 Entitlements.plist:
这里最需要注意的就是 application-identifier 要包含正确的 Team ID (可以在开发者中心查看) 和对应的 Bundle ID。
使用 codesign 对 hook 的 dylib 进行签名:
#!bash
codesign -f -s "iPhone Developer: zhengmin1989@gmail.com (XXXXXXXXX)" IceAndFire.app/hook1.dylib
使用 codesign 对 app 进行签名:
#!bash
codesign -f -s "iPhone Developer: zhengmin1989@gmail.com (XXXXXXXXX)" --entitlements Entitlements.plist IceAndFire.app
使用 xcrun 将 IceAndFire.app 打包成 IceAndFire.ipa:
#!bash
xcrun -sdk iphoneos PackageApplication -v IceAndFire.app -o ~/iOSPwn/hook/github/IceAndFire.ipa
使用 itunes 或者 mobiledevice 进行安装。
成功的话会显示”OK”。然后就可以在非越狱的手机上使用我修改后的 app 了。
通过上面几节的介绍,我们已经将非越狱 app hook 的流程走过一遍了,但这时候有人会问:” 你 hook 的 app 是自己写的,你当然知道应该 hook 哪个函数了,我想 hook 的 app 都是 App Store 上的,并没有源码,我该怎么办?” 其实这个问题也不难解决。只要用好 class-dump 和 ida 即可。
Class-dump 是一款可以用来 dump 头文件工具:
比如我们想要 dump XXX 的头文件,只需要执行:
#!bash
./class-dump -H -o header XXX
经过 dump 后,所有的头文件都会保存在”header” 这个文件夹中:
每个头文件中都包含了类和方法的声明:
可以看到,利用 class-dump 能够很好的帮助我们了解 app 的内部结构。但是 class-dump 只能获取 app 的头文件,并不能知道每个方法具体的逻辑,这时候我们就需要用到 ida 了。
利用 ida 我们可以获取到一个方法具体的逻辑,不过这需要你对 arm 汇编有一定的了解:
比如上图所示的函数就是调用NSLog(@”%@\n”)
来向控制台输出参数的内容。只有了解了某个函数具体是做什么的,我们能才知道如何 hook 这个函数。
至于微信自动抢红包的插件无非就是 hook 了接收微信消息的函数,然后判断消息中有没有红包,有的话就直接调用打开红包的函数即可。但因为这篇文章的主要目的是介绍非越狱手机的 app hook,而不是鼓励大家使用外挂,所以具体实现的细节就不公布了,有兴趣的同学可以自己尝试写一个。虽然效果没有机械流那么酷炫,但的确省时省力啊。
以下是最终的实现效果视频:
通过这篇文章我们可以看到,即使是在非越狱的 iOS 系统上依然可以玩出很多的花样,因此各大 it 厂商不要盲目的相信非越狱 iOS 系统的安全性。针对红包和支付等比较重要的逻辑一定要有混淆和加固,针对 app 本身一定要有完整性校验。不然好心的白帽子可能只是写个自动抢红包的外挂玩玩,但是黑客就可能利用这种技术开发各种外挂来牟取暴利或者让用户在无意当中安装上带有后门的 app,随后会发生什么就只有天知道了。
最后感谢我的同事黑雪和耀刺对这篇文章的帮助和指导。
PS: 文中涉及代码可在我的 github 下载:
https://github.com/zhengmin1989/iOS_ICE_AND_FIRE
全文完。
赞助商: