首页
社区
课程
招聘
[原创]从p0sixspwn源码看越狱流程、原理、目的
发表于: 2014-10-31 13:00 25406

[原创]从p0sixspwn源码看越狱流程、原理、目的

2014-10-31 13:00
25406

本文word版本: 从p0sixspwn源码看越狱流程、原理、目的.docx.7z

p0sixspwn的源码在:
e37K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6H3x3s2y4A6P5s2y4H3N6$3&6Q4x3V1k6H3x3s2y4A6P5s2y4H3N6$3^5`.
这个工具可以实现iOS6.1.3~6.1.6的越狱。

本文的目的在于针对p0sixspwn源码,分析越狱操作的流程、然后理解原理,最终总结出通用的东西例如目的、理念等。

流程和原理:
1.        首先检查iOS设备是可以越狱。
检查产品类型,固件版本。不支持,结束。
2.        检查iOS设备是否已经越狱。
检查是否可以启动afc2、检查是否/Applications目录是一个符号连接、检查是否存在/private/etc/launchd.conf文件
已越狱,结束。
Note1:越狱前/Applications目录是一个正常目录,当Cydia第一次运行完之后就成了符号链接。
Applications -> /var/stash/_.k0EtTL/Applications/
这是因为/Applications目录下的文件被移动到了用户分区下,这样做是为了给系统分区节省空间,来放别的东东。
参考:c4aK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4c8Z5k6h3W2H3K9r3!0F1k6i4N6A6K9$3W2Q4x3X3g2U0L8$3#2Q4x3V1k6%4K9h3E0A6i4K6u0r3i4K6u0r3M7s2u0A6N6X3q4@1k6g2)9J5c8Y4k6S2M7W2)9J5c8Y4y4@1j5i4y4Z5
Note2:launchd.conf是越狱后写入的,目的是让iOS版本的init程序(/sbin/launchd)来加载执行内核内存补丁程序:/private/var/untether/untether,该程序主要目的是去掉内核对执行文件的完整性检查(Apple Mobile File Integrity),可写的内存区域就不会有执行权限,等限制。
这里要注意的是用户分区是挂接在/private/var目录下的:
/dev/disk0s1s2 on /private/var
在没有越狱的情况下/etc目录也是一个符号连接到/private/etc
/etc -> /private/etc/
所以/private/etc/launchd.conf就是/etc/launchd.conf,但这个文件又是只读的,因为他属于root分区,fstab定义root分区是只读的:
/dev/disk0s1s1 / hfs ro 0 1
Note3:检查有没有越狱只要看能不能开启afc2就够了。至于Cydia有没有运行过,或者untether程序有没有放置只是辅助。
3.        越狱的第一步,利用com.apple.mobilebackup2漏洞,创建文件:/var/db/launchd.db/com.apple.launchd/overrides.plist,内容如下:
char* overrides_plist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"47cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3q4H3M7r3I4W2i4K6u0W2j5$3!0E0i4K6u0r3c8q4c8p5M7#2)9J5c8W2m8J5L8%4m8W2M7Y4c8&6e0r3W2K6N6q4)9J5k6o6q4Q4x3X3f1H3i4K6u0W2k6s2c8V1i4K6g2o6">\n"
"<plist version=\"1.0\">\n"
"<dict>\n"
"    <key>com.apple.syslogd</key>\n"
"    <dict>\n"
"        <key>Disabled</key>\n"
"        <true/>\n"
"    </dict>\n"
"</dict>\n"
"</plist>\n";
字面上看是要关闭syslog服务。
Note1:com.apple.mobilebackup2漏洞利用的方法类似于在游戏上经常使用的存档漏洞。
流程是:首先生成备份。在PC端对备份文件进行修改。通过恢复修改后的备份文件触发漏洞。
这个漏洞的原理并不是堆栈溢出,而是恢复备份时对存在的符号链接的情况没有做安全过滤。
例如创建/var/db/launchd.db/com.apple.launchd/overrides.plist的流程:
a.        Create backup
b.        backup_mkdir("Media/Recordings")
c.        backup_symlink("Media/Recordings/.haxx", "/var/db/launchd.db/com.apple.launchd")        也就是/var/db/launchd.db/com.apple.launchd -> Media/Recordings/.haxx
d.        backup_add_file("Media/Recordings/.haxx/overrides.plist")
e.        restore backup
Note2:使用afc对文件操作的范围仅限于:/private/var/mobile/Media,而且只能是普通用户(501、mobile)的权限
/usr/libexec/afcd --xpc -d /private/var/mobile/Media
com.apple.mobilebackup2程序,也就是/usr/libexec/BackupAgent2,虽然是root权限,但也不能写只读的分区,例如/private/etc/launchd.conf。
/System/Library/Lockdown/Services.plist:
        <key>com.apple.mobilebackup2</key>
        <dict>
                <key>InstanceLimit</key>
                <integer>5</integer>
                <key>Label</key>
                <string>com.apple.mobilebackup2</string>
                <key>ProgramArguments</key>
                <array>
                        <string>/usr/libexec/BackupAgent2</string>
                        <string>--lockdown</string>
                </array>
        </dict>
Note3:我不明白关闭com.apple.syslogd有什么实质意义。
4.        越狱的第二步,利用漏洞DeveloperDiskImage race condition
先交代背景:
把iPhone同你的Mac连上, 打开Xcode, 点击 “User For Development”, 一个磁盘映像就会上传到你的iPhone中。它就是所谓的 DevelopeerDiskImage.dmg
这个DMG可以在你的Mac机器上找到, 比如
/Developer/Platforms/iPhoneOS.platform/DeviceSupport/3.1.3/DeveloperDiskImage.dmg
通过SSH登录到iPhone上,运行mount命令
#mount
/dev/disk1 on /Developer (hfs, local, read-only) Note1:这个/Developer目录是iOS系统原始情况下就有的
扩展应用就是:可以挂接任何dmg到这个/Developer目录,只要同时具有这个dmg文件的有效签名。
例如:0dcK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4H3M7r3I4V1L8X3I4V1i4K6u0W2j5i4m8H3L8r3g2Q4x3X3g2U0L8$3#2Q4x3V1k6A6e0#2x3$3i4K6u0r3x3o6b7I4i4K6u0V1z5o6f1I4z5q4)9J5k6e0t1H3x3e0t1I4x3o6t1&6i4K6u0W2b7@1y4J5N6o6W2Q4x3V1k6A6e0#2y4g2M7r3c8S2N6r3g2J5i4K6u0W2K9i4m8S2
解开获取:iOSUpdaterHelper.dmg、iOSUpdaterHelper.dmg.signature
运行下面命令同样可以完成挂接:
$ ideviceimagemounter.exe -t Developer ./iOSUpdaterHelper.dmg
Uploading ./iOSUpdaterHelper.dmg --> afc:///PublicStaging/staging.dimage
done.
Mounting...
Done.
Status: Complete
这个race condition是说,按正常流程将dmg和其签名,通过lockdown告诉了com.apple.mobile.mobile_image_mounter之后的某个时刻,如果用另外一个dmg的内容替换了afc:///PublicStaging/staging.dimage,会怎么样?
结果是,如果这个时间点拿捏的比较好的话,另一个dmg(hax.dmg)会取代iOSUpdaterHelper.dmg被挂接到/Developer目录!
而这个时间点就是com.apple.mobile.mobile_image_mounter完成了dmg完整性校验,但还没有开始挂接dmg文件。
从程序上看,这个时间点是1000 ~ 3900(1000+29*100)us,程序会以100us为步长,通过29轮来尝试这个碰撞。
我印象中race condition都很短,有的甚至用FPGA之类的硬件来实现,例如xbox360。估计现在的版本apple不会再留这么多的时间间隔了吧...

这个hax.dmg hfs文件系统镜像里面只有2个plist文件:

貌似/usr/libexec/lockdownd程序非常关注这个"/Developer/Library/Lockdown/ServiceAgents"目录。


5.        越狱的第三步,通过lockdown运行r.plist和com.apple.afc2.plist
简单说就是通过root权限执行下面两条命令,第一条remount让root分区具有写权限(android的root,:-)),第二条启动熟悉的afc2服务
/sbin/mount –u –o rw,suid,dev /
/usr/libexec/afcd --lockdown -d /

r.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "a0cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3q4H3M7r3I4W2i4K6u0W2j5$3!0E0i4K6u0r3c8q4c8p5M7#2)9J5c8W2m8J5L8%4m8W2M7Y4c8&6e0r3W2K6N6q4)9J5k6o6q4Q4x3X3f1H3i4K6u0W2k6s2c8V1">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>r</string>
        <key>ProgramArguments</key>
        <array>
                <string>/sbin/mount</string>
                <string>-u</string>
                <string>-o</string>
                <string>rw,suid,dev</string>
                <string>/</string>
        </array>
</dict>
</plist>

com.apple.afc2.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "706K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3q4H3M7r3I4W2i4K6u0W2j5$3!0E0i4K6u0r3c8q4c8p5M7#2)9J5c8W2m8J5L8%4m8W2M7Y4c8&6e0r3W2K6N6q4)9J5k6o6q4Q4x3X3f1H3i4K6u0W2k6s2c8V1">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>com.apple.afc2</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/libexec/afcd</string>
                <string>--lockdown</string>
                <string>-S</string>
                <string>-d</string>
                <string>/</string>
        </array>
</dict>
</plist>
6.        越狱的第四步,类似于第一步继续使用com.apple.mobilebackup2漏洞上传untether payload和Cydia安装包(当然afc2都起来,没有必要一定需要利用这个漏洞了)
例如/etc/launchd.conf、/private/var/untether/_.dylib、/private/var/untether/untether
# cat /etc/launchd.conf
unload /System/Library/LaunchDaemons/com.apple.MobileFileIntegrity.plist
bsexec .. /sbin/mount -u -o rw,suid,dev /
load /System/Library/LaunchDaemons/com.apple.MobileFileIntegrity.plist
setenv DYLD_INSERT_LIBRARIES /private/var/untether/_.dylib
bsexec .. /private/var/untether/untether
unsetenv DYLD_INSERT_LIBRARIES
bsexec .. /bin/rm -f /var/untether/sock
bsexec .. /bin/ln -f /var/tmp/launchd/sock /var/untether/sock
        目的是每次系统启动后,都可以通过/sbin/launchd来执行上面这些命令。
7.        到此越狱结束。

其实还要再说几句,因为还有几个漏洞的利用没有登场。
第一个是AMFID_code_signing_evasi0n7
untether本身的目的是在内存上patch掉内核的限制。但_.dylib和untether都是没有签名的程序,在没有被patch之前又如何运行呢?
_.dylib里_TEXT是空的,他也就没有签名,他存在的真实目的告诉动态库加载器dyld,用CoreFoundation里的_CFEqual函数来替换掉libmis.dylib里的_MISValidateSignature
我理解re-export只是一个特征,基于这个特征的确是比较危险,算他是漏洞吧。
    $ dyldinfo -export _.dylib
    export information (from trie):
    [re-export] _kMISValidationOptionValidateSignatureOnly (_kCFUserNotificationTokenKey from CoreFoundation)
    [re-export] _kMISValidationOptionExpectedHash (_kCFUserNotificationTimeoutKey from CoreFoundation)
[re-export] _MISValidateSignature (_CFEqual from CoreFoundation)
参考CoreFoundation的源码:
845K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3!0H3k6h3&6K6L8%4g2J5j5$3g2Q4x3X3g2S2M7s2m8D9k6g2)9J5k6h3y4G2L8g2)9J5c8Y4c8S2M7X3u0S2L8r3I4K6i4K6u0r3b7@1k6Q4x3V1k6o6c8W2)9J5k6o6R3#2y4g2)9J5k6e0p5%4i4K6u0W2N6r3q4J5i4K6u0W2k6%4Z5`.
Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) {
    if (NULL == cf1) { CRSetCrashLogMessage("*** CFEqual() called with NULL first argument ***"); HALT; }
    if (NULL == cf2) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT; }
    if (cf1 == cf2) return true;
    CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf1, isEqual:, cf2);
    CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1);
    __CFGenericAssertIsCF(cf1);
    __CFGenericAssertIsCF(cf2);
    if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false;
    if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) {
        return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2);
    }
    return false;
}
libmis.dylib里的_MISValidateSignature是这样的:
int __fastcall MISValidateSignature(int a1, int a2)
{
  return MISValidateSignatureAndCopyInfo(a1, a2, 0);
}
因为a1和a2是不同的东西,所以CFEqual一定返回false也就是0。对于MISValidateSignature,0就是校验通过!

虽然
setenv DYLD_INSERT_LIBRARIES /private/var/untether/_.dylib
bsexec .. /private/var/untether/untether
这两句看样子是说在untether执行的时候做这个符号替换,但实际这个_.dylib真不是为他准备的。untether根本就不会去调用MISValidateSignature函数!
事实上_.dylib是给amfid这个程序准备的。因为内核在加载untether做校验时,启动了用户态程序amfid来判断是否合法,不知道apple为什么这样设计,但事实就是这样。
这样amfid总会告诉内核,他在加载的程序是合法的,于是untether就运行了。
这里摘录《D2T1 - Pod2g, Planetbeing, Musclenerd and Pimskeks aka Evad3rs - Swiping Through Modern Security Features.pdf》说明amfid的调用关系:

Note: lauchd加载untether程序流程
1. lauchd调用fork(spawn)
2. 在fork的子进程里调用execv
3. 内核装载器调用amfid检查untether有效性,通过后进行装载
4. 内核装载器发现untether是要用到动态库的,就顺便装载dyld,把返回用户态后的fork出来的进程的pc指向dyld的入口函数
5. dyld完成剩下dylib的加载(包括执行dylib里的init函数),最后执行untether的入口函数。

剩下的漏洞利用在于untether执行起来之后如何去找到对应的指令进行patch,据说因为ASLR的存在,这个事情很难办到。
目前还没有看到这部分,无法确认细节,据说是下面这两个:
posix_spawn kernel information leak (by i0n1c)
posix_spawn kernel exploit (CVE-2013-3954) (by i0n1c)

最后做下小结
越狱的目的是什么?或者说越狱对iOS设备造成了什么影响?
目的就是突破iOS上的限制。
1.        Remount rootfs获取写权限
2.        启动afc2访问所有文件
3.        Patch内核,去除执行文件完整性检查机制(unsigned code to run)、可写的内存区域没有执行权限(MobileSubstrate可以工作)、…
4.        安装Cydia(Appstore不是唯一来源)


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 3
支持
分享
最新回复 (12)
雪    币: 341
活跃值: (153)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
2
顶。。。
2014-10-31 13:12
0
雪    币: 16711
活跃值: (2783)
能力值: ( LV9,RANK:147 )
在线值:
发帖
回帖
粉丝
3
前排留名,以后有时间再学习下..感谢楼主分享
2014-10-31 13:22
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
嗯!写的不错,有机会是否可以共同交流一下。
2014-10-31 13:54
0
雪    币: 131
活跃值: (98)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
5
求交往,楼主求联系方式
2014-10-31 15:21
0
雪    币: 236
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
不明觉厉~~!致谢一个先
2014-10-31 15:57
0
雪    币: 507
活跃值: (420)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
前排支持。。不过现在一般用盘古的直接越,自己写工具,太纠结了。。
2014-10-31 16:26
0
雪    币: 215
活跃值: (51)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
支持楼主科普帖子~学习mark!
2014-10-31 16:27
0
雪    币: 14983
活跃值: (5324)
能力值: ( LV15,RANK:880 )
在线值:
发帖
回帖
粉丝
9
顶~~~~
2014-11-3 17:14
0
雪    币: 15447
活跃值: (4919)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
分析不错。支持。
2014-11-6 22:26
0
雪    币: 244
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
人好少啊...好好努力了哈.
2014-11-18 15:58
0
雪    币: 74
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
认真的拜读了下楼主的分析,收获很大!
可惜最后的untether内核patch部分没有看到细节,这方面有相关的源码吗?
2016-3-23 14:37
0
雪    币: 43
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
这个强大,花一些时间来学习。
2016-4-15 09:17
0
游客
登录 | 注册 方可回帖
返回