iOS冰与火之歌番外篇 - 在非越狱手机上进行App Hook

0x00 序


冰指的是用户态,火指的是内核态。如何突破像冰箱一样的用户态沙盒最终到达并控制如火焰一般燃烧的内核就是《iOS冰与火之歌》这一系列文章将要讲述的内容。但在讲主线剧情前,我们今天先聊一聊分支剧情 - 在非越狱的iOS上进行App Hook。利用这个技术,你可以在非越狱的iOS系统上实现各种hook功能(e.g., 微信自动抢红包,自动聊天机器人,游戏外挂等),但写这篇文章的目的并不是鼓励大家使用外挂,更不是鼓励大家去卖外挂,所以千万不要用这个技术去做一些违法的事情。

《iOS冰与火之歌》系列的目录如下:

  1. Objective-C Pwn and iOS arm64 ROP
  2. 在非越狱的iOS上进行App Hook(番外篇)
  3. █████████████
  4. █████████████
  5. █████████████

另外文中涉及代码可在我的github下载:
https://github.com/zhengmin1989/iOS_ICE_AND_FIRE

0x01 Mach-O LC_LOAD_DYLIB Hook


要是看过我写的安卓动态调试七种武器之离别钩 – Hooking(上)/tips/?id=9300 和 安卓动态调试七种武器之离别钩 – Hooking(下)/papers/?id=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!”。

p1

在Products文件夹中我们能够看到IceAndFire.app这个文件,也就是编译完后的app:

p2

IceAndFire.app其实就是个文件夹,里面可以看到很多的资源文件(签名信息,图片等),但最重要的东西就是与文件夹同名的IceAndFire这个二进制文件了。我们可以用xxd命令来看一下里面的内容:

p3

这个二进制文件里保存了IceAndFire这个app的所有逻辑,但是直接看二进制编码太辛苦了,这里我推荐一个叫做MachOView的软件(可以在我的github里下载),通过这个软件就可以看到整个MachO文件的结构了:

p4

在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的注入,如图所示:

p5

现在我们再用MachOView看一下IceAndFire这个二进制文件就会看到hook1.dylib已经被我们成功注入进去了:

p6

@executable_path/hook1.dylib”的意思是二进制文件会在当前目录下对hook1.dylib进行加载,所以我们编译好的hook1.dylib要和二进制文件一起放到IceAndFire.app文件夹里,这样才能保证我们在运行app的时候hook1.dylib能够被正确的加载。

0x02 CaptainHook for Dylib


修改好了app二进制文件的Load Commands结构体后,我们再来看看如何构造进行hook的第三方dylib。因为app自己肯定不会主动调用第三方dylib中的函数,所以如果我们想要让第三方dylib进行hook操作就要把hook的逻辑写到构造函数里。实现构造函数很简单,只要在函数前声明 ”__attribute__((constructor)) static” 即可,我们先写个”Hello, Ice and Fire!”测试一下:

p7

编译好dylib文件后,我们将这个dylib文件与app一起签名、打包、安装。然后我们运行一下程序就可以看到我们注入的dylib库已经在程序启动的时候成功加载并执行了。

p8

下一步就是要实现对特定函数的hook。在这里我推荐使用CaptainHook这个framework。作者已经帮我们实现了hook所需要的各种宏,只要按照如下步骤就可以完成针对特定函数的hook:

  1. 使用 CHDeclareClass() 声明想要hook的class
  2. 在构造函数中用 CHLoadClass() 或 CHLoadLateClass() 加载声明过的class
  3. 使用CHMethod() hook相应的method
  4. 在CHMethod()中可以使用CHSuper()来调用原函数
  5. 在构造函数中使用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!”:

p9

0x03 签名、打包和安装


我们知道越狱后的iPhone有一个很重要的特性就是可以关闭app的签名校验,关掉签名校验后,App Store上的app(无论是收费的还是免费的)就可以随意盗版并且免费安装了。但是在非越狱的iPhone上,系统要求app必须要有合法的签名,负责无法进行安装。其实除了AppStore上的app有合法的签名外,我们还可以使用开发者证书或者企业证书来让没有合法签名的app拥有合法的签名。

当我们拥有开发者帐号并且在机器上安装了证书的话,就可以在Keychain Access这个工具中看到我们的签名信息:

p10

我们接下来要干的事情就是使用这个开发者证书来对我们修改后的IceAndFire .app进行签名。步骤如下:

  1. 首先先保证IceAndFire.app文件夹下有正确的embedded.mobileprovision文件:

    如果没有的话,可以去苹果的开发者中心(developer.apple.com)生成。如果是个人开发者要注意将iOS设备的UDID加到开发者的设备列表中再生成embedded.mobileprovision文件,如果是企业证书则没有设备数量的限制。

  2. 正确的编写签名时使用的Entitlements.plist:

    这里最需要注意的就是application-identifier要包含正确的Team ID (可以在开发者中心查看) 和对应的Bundle ID。

    p11

  3. 使用codesign对hook的dylib进行签名:

    #!bash
    codesign -f -s "iPhone Developer: [email protected] (XXXXXXXXX)" IceAndFire.app/hook1.dylib
    
  4. 使用codesign对app进行签名:

    #!bash
    codesign -f -s "iPhone Developer: [email protected] (XXXXXXXXX)" --entitlements Entitlements.plist IceAndFire.app
    
  5. 使用xcrun将IceAndFire.app打包成IceAndFire.ipa:

    #!bash
    xcrun -sdk iphoneos PackageApplication -v IceAndFire.app  -o ~/iOSPwn/hook/github/IceAndFire.ipa
    
  6. 使用itunes或者mobiledevice进行安装。

enter image description here

成功的话会显示”OK”。然后就可以在非越狱的手机上使用我修改后的app了。

0x04 Class-dump 和 ida


通过上面几节的介绍,我们已经将非越狱app hook的流程走过一遍了,但这时候有人会问:”你hook的app是自己写的,你当然知道应该hook哪个函数了,我想hook的app都是App Store上的,并没有源码,我该怎么办?”其实这个问题也不难解决。只要用好class-dump和ida即可。

Class-dump是一款可以用来dump头文件工具:

p13

比如我们想要dump XXX的头文件,只需要执行:

#!bash
./class-dump -H -o header XXX

经过dump后,所有的头文件都会保存在”header”这个文件夹中:

p14

每个头文件中都包含了类和方法的声明:

p15

可以看到,利用class-dump能够很好的帮助我们了解app的内部结构。但是class-dump只能获取app的头文件,并不能知道每个方法具体的逻辑,这时候我们就需要用到ida了。

利用ida我们可以获取到一个方法具体的逻辑,不过这需要你对arm汇编有一定的了解:

p16

比如上图所示的函数就是调用NSLog(@”%@\n”)来向控制台输出参数的内容。只有了解了某个函数具体是做什么的,我们能才知道如何hook这个函数。

0x05 微信自动抢红包的原理


至于微信自动抢红包的插件无非就是hook了接收微信消息的函数,然后判断消息中有没有红包,有的话就直接调用打开红包的函数即可。但因为这篇文章的主要目的是介绍非越狱手机的app hook,而不是鼓励大家使用外挂,所以具体实现的细节就不公布了,有兴趣的同学可以自己尝试写一个。虽然效果没有机械流那么酷炫,但的确省时省力啊。

p17

p18

0x06 总结


通过这篇文章我们可以看到,即使是在非越狱的iOS系统上依然可以玩出很多的花样,因此各大it厂商不要盲目的相信非越狱iOS系统的安全性。针对红包和支付等比较重要的逻辑一定要有混淆和加固,针对app本身一定要有完整性校验。不然好心的白帽子可能只是写个自动抢红包的外挂玩玩,但是黑客就可能利用这种技术开发各种外挂来牟取暴利或者让用户在无意当中安装上带有后门的app,随后会发生什么就只有天知道了。

最后感谢我的同事黑雪和耀刺对这篇文章的帮助和指导。

PS: 文中涉及代码可在我的github下载:

https://github.com/zhengmin1989/iOS_ICE_AND_FIRE

©乌云知识库版权所有 未经许可 禁止转载


30
itx 2016-06-12 11:46:07

@昨天
我也遇到了,请问有解决了吗

30
coco 2016-06-01 16:09:08

@海蓝 试了一下,重签名的时候,报错Entitlements.plist: cannot read entitlement data,可能因为一些原因还没有公布出来。

30
coco 2016-06-01 13:51:34

虽然MachOView闪退,用不了。但按楼主的步骤试了一遍,可以注入成功并安装。O(∩_∩)O谢谢楼主么么哒!

30
coco 2016-06-01 10:12:49

MachOView闪退什么鬼?

30
major 2016-05-26 16:33:04

@小禾吉 你在非越狱手机上成功dump了吗?

30
Sing9211 2016-05-18 15:36:38

@昨天 你的问题解决了吗?我遇到跟你同样的问题

30
c2y2 2016-04-29 16:57:23

这技术,好多年前在一个移动广告公司见过了,广告行业很早都在使用了

30
Visitor 2016-04-20 15:58:17

@zyzy 我就dump出一个CDStructures文件, 您找到原因了吗?

30
tw 2016-04-12 15:09:08

@昨天 我甚至无法安装,最后只好用ipa installer安装上了,但是安装完后还是闪退,系统9.0.2,怀疑是签名要求变高了
LZ求答疑啊

30
abd 2016-04-01 17:20:25

codesign -f -s "xxxxx" ./WeChat.app/PlugIns/WeChatShareExtensionNew.appex
codesign -f -s "xxxxx" --entitlements Entitlements.plist ./WeChat.app
执行上面两个命令时会出现下面的提示,导致最终的ipa都安装不上,为什么?
./WeChat.app: replacing existing signature
./WeChat.app: main executable failed strict validation

30
Onelong 2016-04-01 09:36:50

我使用MachOView查看yololib 修改的dylib显示不支持,我是在iphone上dumpdecrypted的文件。但是我自己没发布的是没有问题的。为什么呢?

30
ole 2016-03-23 18:15:45

签名过程完全follow一字不落啊,可是mobiledevice报错!AMDeviceSecureInstallApplication

30
Wendy 2016-03-01 10:07:10

卡在dylib的注入,git上下载的hook1项目编译不过,别的dylib注入不进去

30
anonman 2016-02-28 09:09:03

也就自己玩玩,打了别人签名的微信,你敢用嘛

30
海蓝 2016-02-25 18:15:09

问个问题,
把某个APP下载,然后注入一些dylib。
然后证书,签名什么的可以用自己的来代替原有的?可以这样么?

30
Bo 2016-02-24 11:30:26

按照教程用自己证书签完名以后还是安装不上呢

30
Bo 2016-02-23 17:39:34

xcode7 怎么创建静态库呢...

30
ruby 2016-02-23 12:50:33

学习了

30
Min 2016-02-23 09:47:38

楼主,系统原生的APP不知能否hook到?

30
X 2016-02-22 16:27:25

卡在dylib那里了 github上的无法编译 自己创建的运行闪退。。。

30
codeeagle 2016-02-20 11:12:17

请问下博主,重签名是一定要企业证书的么?还有,ipa 是从 iTunes 下获得的,不解密,直接重签有问题么。

现在我试了下,用个人证书重签 iTunes 下载的 ipa,安装成功,但是闪退。能指导下么

30
zyzy 2016-02-19 15:35:42

微信class-dump 不出头文件

30
小荷才露尖尖角 2016-02-19 15:11:37

赞,精华哥

30
昨天 2016-02-19 14:36:38

请教楼主大神,我按照楼主的步骤重新签名,可以安装成功,但是一打开就闪退,这是log:
kernel[0] <Notice>: AppleFairplayTextCrypterSession::fairplayOpen() failed, error -42022
com.apple.xpc.launchd[1] (UIKitApplication:com.ss.iphone.article.News[0x556f][3235]) <Notice>: Service exited due to signal: Killed: 9
assertiond[60] <Warning>: Unable to obtain a task name port right for pid 3235: (os/kern) failure (5)
SpringBoard[50] <Warning>: Unable to register for exec notifications: No such process
SpringBoard[50] <Warning>: Unable to obtain a task name port right for pid 3235: (os/kern) failure (5)
SpringBoard[50] <Warning>: Unable to obtain a task name port right for <FBApplicationProcess: 0x12fcdf110; com.ss.iphone.article.News; pid: 3235>
SpringBoard[50] <Warning>: Unable to get short BSD proc info for 3235: No such process
SpringBoard[50] <Warning>: Unable to get proc info for 3235: No such process
SpringBoard[50] <Warning>: Unable to register for exec notifications: No such process
assertiond[60] <Warning>: Could not set priority of <BKNewProcess: 0x155582e80; com.ss.iphone.article.News; pid: 3235; hostpid: -1> to 1, priority: No such process
SpringBoard[50] <Warning>: Unable to obtain a task name port right for pid 3235: (os/kern) failure (5)
assertiond[60] <Warning>: Could not set priority of <BKNewProcess: 0x155582e80; com.ss.iphone.article.News; pid: 3235; hostpid: -1> to 0, priority: No such process
SpringBoard[50] <Warning>: Unable to obtain a task name port right for <FBApplicationProcess: 0x12fcdf110; com.ss.iphone.article.News; pid: 3235>
SpringBoard[50] <Warning>: Unable to get short BSD proc info for 3235: No such process
SpringBoard[50] <Warning>: Unable to get proc info for 3235: No such process
请大神指导!

30
我是叉叉歪 2016-02-19 11:06:38

我怎么没效果 能运行 但是好像没有加载dylib

30
黄瓜 2016-02-18 16:52:30

跟走Demo走了一遍,目前卡在0x02 CaptainHook for Dylib 这里,hook1_Project 编不过,按照 http://blog.csdn.net/stackhero/article/details/9032891 上面的内容自己写了个创建了一个 hook1的Dylib 文件,不知会不会出问题。

30
sniperYJ 2016-02-18 16:04:21

我想请问下如果是别人的app的话embedded.mobileprovision文件用什么呢

30
毛猴 2016-02-18 14:40:33

6666666666666666

30
frank 2016-02-18 11:59:08

证书暴露了你目前就职于ali...嘻嘻

30
小禾吉 2016-02-18 11:15:52

群里抢红包永远是第一...

30
sxyzbbs 2016-02-18 11:11:55

顶!iOS安全2016年一定大火!

30
忧伤珲舞 2016-02-18 11:02:39

果然,现在不越狱也不安全了...

30
Kuuki 2016-02-18 10:36:10

82,666

感谢知乎授权页面模版