由于内容过于长,所以第二部分又要分段了:第七世代的掌机和第八世代将在之后继续。
终于来到了比较现代的游戏机环节,之前的游戏机的安全措施基本上只能说是正版验证(除了 Xbox),并没有做出太大努力来防止用户运行大家不想看到的东西。但是更新的游戏机几乎都有了真正的操作系统,如果不限制用户运行别的代码,容易被持久化破解,所以之后的设备都大大加强了代码完整性检查这一块。
第七世代-安全大加强,还有大家不喜欢的 PowerPC
这一代游戏机和掌机基本上都有了真正的操作系统(除了喜欢用电子垃圾的那位小朋友,对说的就是你,任天堂)另外由于 IBM 爆了索尼金币做的芯片被二次转卖给了微软,所以微软也用上了 PowerPC,Wii 更是继承了上一代 GameCube 的法统,继续找 IBM 定制芯片。IBM 这时候可以说是形式不是一片小好而是大好啊,不过我们都知道了它后面的结局。
PlayStation 3
对于 PlayStation 3,索尼可谓是煞费苦心。索尼和 IBM 以及东芝一起研发了一款在当时可以说是达到了超级计算机等级的芯片:Cell。这款芯片通过超长流水线带来了 3.2 GHz的超高频率,并且采用了 8 核架构(实际上是 9 核,为了良率屏蔽了一核),八核心中有一个全功能处理器的 PPE,和七个作为协处理器的 SPE。这种一拖多的处理器是为了尽可能的拉高并行处理能力,主要应用于超算架构中(例如无锡高性能研究所的神威26010,这个型号不仅只是是模仿 Alpha 64 的命名,还表明了它内部的架构,260=4个控制核心+每个控制核心下64个运算核心,这一设计和 PS3 的 Cell 架构类似)。但这种高性能是有代价的:开发者需要精确控制协处理器上任务的调度才能发挥出这种设计的长处。大部分游戏开发者并没有管理这种调度的能力,因此选择让全功能的 PPE 控制 SPE。这样 设计简单,但 PPE 有限的调度能力成了性能的瓶颈。也有少数游戏选择了更困难的方式:让 SPE 自己控制自己。这样虽然开发变得困难,但更能利用 Cell 强大的性能。
另外,索尼为了不浪费这个产品的性能的同时减少破解的需求,而发布了继承了 PlayStation 2 的光荣传统的 OtherOS 功能。该功能支持在虚拟化环境下用最多六个 SPE 和一个 PPE 运行 Linux 或者其他操作系统。同时为了安全,OtherOS 并不能使用 GPU 和图形加速功能。
安全措施
处理器
PlayStation 3 的特权模型继承自 PowerPC,有两种状态:Problem State(等同于其他平台的用户态,这是 IBM 术语)和 Privileged State(特权态),其中特权态有两级,一级用于 PlayStation 3 的操作系统,一级用于 Hypervisor。这种完整的特权隔离设计让它的安全性远高于之前的任何游戏机。
启动流程和信任链
PlayStation 3 的启动流程从一颗主板上被称为 syscon 的 ARM 协处理器开始,就像最后几代 Intel Mac 上的 T2 芯片一样,它负责开始整个启动流程。这款芯片首先从它自己内部未加密的固件开始执行,先初始化设备里的各种电源系统,之后启动 Cell 这颗主处理器并通过 SPI 向它发送配置信息。
在被拉起后,主处理器 Cell/BE 会首先从芯片内部烧入的固件启动,从闪存中读取并解密第一阶段的引导器 bootldr,并在一个 SPU 中开始执行启动引导器,这一启动阶段会初始化 I/O 控制器,初始化并检测 XDR 内存,之后加载 lv0 启动阶段,新版本的机器还会在加载之前验证后者的完整性。
lv0 启动后,会将 CPU 频率提高到 3GHz,并初始化更多硬件,然后加载 metldr,也就是 meta loader,所有其它加载器的加载器,并在另一个 SPE 上运行。之后解密并验证其它几个加载器,然后发给 metldr 加载并运行,加载器中包含用于加载虚拟机管理程序、操作系统、游戏以及安全管理模块的几种。加载器验证并执行完成后会各自验证并执行自己对应的下一阶段程序,当对应的下一阶段程序都启动成功后,启动过程也就完成了。
过程中的信任链是这样的:工厂生产时会根据每台机器独特的密钥签署 bootldr 和 metldr,而其它组件则是由索尼签署,并在加载过程中被前两级加载器验证。每个机器使用不一样的密钥可以防止破解者破解一台机器后攻破所有设备,但也导致了 bootldr 和 metldr 这两个由机器密钥签名的组件相当于固化在机器中了,不能像其他组件一样空中升级。
拷贝保护
索尼在 PlayStation 3 上换装了蓝光光驱,并给游戏盘添加了一些防伪措施。首先,游戏的蓝光盘的 PIC (永久信息和控制数据)区域中写了认证信息和挑战信息,挑战信息会被蓝光光驱读取并要求主机回应,只有主机回应成功的情况下蓝光光驱才会继续读取光盘。另外,光盘内容还有另一层加密,你能买到的光盘上有一份被加密的内容解密密钥,这个密钥会被前面系统中的游戏加载器解密,并用于解密光盘中的游戏内容。
另外,为了防止有人修改或逆向蓝光光驱固件,索尼在每一台光驱和主机上都内置了一对相同的加密密钥,当需要升级光驱固件的时候升级的固件需要通过这个密钥加密才能被光驱接收,不同机器上的光驱不能交换使用。
破解
索尼在 PlayStation 3 上设计的安全机制确实强而有力,所以在初期破解者并没有获得有意义的进展,除了一个只能运行盗版游戏,不能运行自制程序还卖的很贵的假光驱之外,到 2008 年年初才有一个利用和前面梦幻之星差不多唐的游戏(抵抗:灭绝人类)的在线升级能力拿到任意代码执行的漏洞,但这个漏洞只拿到了用户态的执行权限。同年年底,索尼更新了一个售后用的恢复模式。有人发现了进入恢复模式的方法,等一下这个模式会成为降级固件从而用来破解的妙妙工具。
直到2009年底,PlayStation 3 的破解都没什么进展。在这一年快结束的 12 月 26 日我们终于迎来了一个突破:GeoHotz(也是那个越狱 iPhone 的人)想出了一个可能的破解方法,并在次年 1 月获得了成功:他通过软硬结合的方式进行攻击,利用 OtherOS 中的 Linux 不断申请并释放内存,同时在合适的时机干扰 XDR 内存总线,让系统在保留程序对这一块内存访问权限的情况下认为这一块内存已经被释放,之后不断申请内存,让内存中的映射表不断变长,直到它占用了之前被认为释放的内存块,这样 OtherOS 就拿到了读写内存映射表的权限,从而拿到了以高权限执行任意代码的能力。
索尼看到了这个报告,并且很不高兴,因此决定即使要给客户赔偿也要在新系统里移除 Other OS 权限,毕竟赔偿款相对于盗版游戏造成的损失只能算是九牛一毛。
2010 年 8 月,有家组织发布了一款不需要改机就能随便安装软件的破解器:只要把它插到 USB 口上,用户就可以在机器上为所欲为。这么神奇的产品大家当然想知道它是怎么做到的,于是大家就把它买来分析。分析表明它利用了 PlayStation 3 系统的 USB 功能的缺陷来破解。具体来说,PlayStation 3 在启动过程中会检测是否有用于进入恢复模式的小工具,这个检查功能对内存的处理有漏洞,于是这个破解装置会把自己模拟成一个 USB 扩展坞,通过不断的假装插拔设备构造特定的堆长度,然后在系统两次读取设备信息的时候卡点返回不同的设备描述长度,从而构造一个写入溢出,最终通过一系列操作让堆溢出,获得任意代码执行能力。
之后索尼不断尝试升级固件填补漏洞,破解者也不断更新通过恢复模式降级固件的工具,两方不断对抗,直到索尼推出了 3.55 固件把降级功能彻底干掉了。
但索尼还是索尼:在这次更新固件发布之后两天,有人发现索尼那个看起来很智慧的证书吊销列表机制又出了典中典问题:它没有检查吊销列表长度是否正确,而不知道为什么,索尼允许在非特权态修改吊销列表。因此破解者可以通过构造一个特制吊销列表来对这个模块进行溢出,从而拿到隔离模式的权限。拿到权限后把隔离模式能获取到的密钥偷出来也是顺手的事。
同年年底,fail0verflow(之后还会看到他们)发现索尼的工程师密码学水平可以说是妈妈生的,他们的 ECDSA 实现里的随机数生成器返回的结果是固定的 4(如果你冲浪多的话,大概看过那张图,你知道我说的是哪个),可能索尼的工程师觉得随机数拿骰子摇一个就完事了。所以说不要喷 Xbox 工程师,神中自有神中手,索尼这操作不比微软的厉害多了?由于 ECDSA 的算法,有了这个固定的随机数,索尼的 ECDSA 私钥就成为大家的私钥了。拿到了索尼的私钥之后索尼签名的全部组件就都能被任何人换掉了,你干的好啊索尼!
在索尼发现自己的私钥没那么私密之后,他们决定在 3.56 版本把整个系统所有的签名密钥全都替换掉。所以如果你不小心更新了系统那你就和破解或者降级无缘了。在 3.60 版本索尼发现虽然 metldr 这个东西没法升级,但是 lv1 可以升级。于是通过 metldr 的功能合并到 lv1 并将这个无能的丈夫组件移除来阻止通过 metldr 破解。升级之后,破解者之后只能通过破坏 lv0 的密钥验证才能制作自制系统。后期发布的新机器更是给 bootldr 进行了一个级的升,额外加入了对 lv0 的校验,从而让升级新系统或者买了新机器的倒霉蛋完全没法破解。
直到 2017 年,有人利用一个在别处发现的 WebKit 漏洞组合一个 PSV 同款的内核漏洞拿到了权限,旧版机器可以用这个方法不拆机刷回老版本,而新机器也可以临时获得运行自制软件的能力。考虑到这台机器商业价值已经基本归零,索尼只是象征性的修补了一下漏洞而并没有努力去阻止。
Wii
Wii 相比于前代的硬件升级不大。CPU 模块“百老汇”是一颗超频升级版的 GameCube CPU(Gekko),通过枯萎电子垃圾的再利用,任天堂不仅实现了降本增效,让产品的成本和售价更低,还简单实现了兼容上一代机器上游戏的功能。
安全系统
操作系统
Wii 是这一代唯一一个没有真正持续运行的操作系统的主机,而这一代掌机里的 NDS 也没有。这两个产品有什么共同点呢?都是任天堂做的。Wii 的系统菜单只是一个和其他游戏平级的普通用户程序而并非操作系统。
Wii 的所谓操作系统被称为 IOS,运行在 starlet 协处理器是上,这一协处理器隐藏在图形模块中,负责控制加解密、从光盘和硬盘等存储设备读取数据以及调用其它。不同于其它主机,Wii 并没有一个单一的 IOS 系统,而是每一代 SDK 使用不同的 IOS,这些系统会根据版本放到主机上的相应槽位上,并根据游戏需要的版本启动。除非任天堂发现其中有能被利用的漏洞,这些系统几乎不会被更新。
信任链
Wii 的启动过程从一个嵌入在图形模块“好莱坞”中的 ARM 处理器开始,这颗辅助处理器会读取固化的固件,并判断是否是在启动 GameCube 游戏从而选择两个启动流程之一:
正常启动时,会验证 boot1 这个下一阶段引导器的哈希,并与芯片内写死的哈希值做匹配(开发机中哈希值未被烧入,在此情况下则不进行校验),匹配成功后才会继续执行。boot1 会初始化内存,解密并验证下一阶段 boot2 的 RSA 签名并运行它。boot2 会让主 CPU 加载系统菜单,系统菜单可以让 IOS 校验并启动经过签名并带有运行许可的游戏或者软件。游戏的签名信息中包含游戏运行时能调用的权限列表。
在启动 GameCube 兼容模式时,游戏机的主 CPU 会重启一次,启动叫做 bc 的 GameCube 兼容模块,它会在启动时降低 CPU 频率,然后其它流程正常执行。直到进入 boot2,系统不会打开 Wii 的系统菜单,而是打开用来提供 GameCube 兼容性的 MIOS。
总结一下:启动过程的信任链如下:
硬编码的 boot0 启动闪存中生产时固化在机器中的 boot1,boot1 验证 boot2 的 RSA 签名并启动它,boot2 在 ARM 协处理器上启动系统菜单需要的 IOS,并让 PPC 主处理器启动系统菜单,系统菜单可以让 IOS 去校验并在 PPC 上启动其它游戏。
其中 boot0 需要重新投片才能升级,boot1 在工厂制造阶段可以升级,出厂后不能升级。IOS 可以在线升级。
光盘防伪
Wii 的光盘防拷贝和之前的技术很相似,采用了相近的冲切区编码识别和多层加密等技术,由于没有太多的创新性,只在这里简要提及一下。
破解
兼容性和一把镊子引发的血案
首先被研究的入口掉就是 GameCube 兼容性模块,上一篇提到过 GameCube 游戏完全没有签名机制,任天堂显然也不可能给它倒找出来一个。但任天堂为了防止它被利用,只允许 GameCube 游戏运行在游戏机功能被限制成和 GameCube 差不多的模式下。但是,Team Twiizer(后改名叫 fail0verflow,我们在上面 PS3 的故事已经见过了)发现重启过程中主内存内容并没有被完全清除而只是被 MMU 禁止访问。恰好 Wii 的硬件地址线可以通过短接来改变地址,一把镊子引发的血案就这样发生了——通过镊子短接地址线从而改变能访问到内存区域,并从中读取没被擦掉的内存内容。然后大家发现妈妈生的任天堂把软件和SD卡解密密钥,每台主机独有的加解密密钥等内容全都留在了内存里。但是这种方法只能导出能够伪造数据的密钥,这些密钥是每台机器独有的,不能拿来破解全部的机器。
妈妈生的密码学之第几次了?
任天堂在校验签名的时候只检验了哈希值的内容,并没有检验 RSA 指数之类的其他参数。这一操作虽然不是很好但也不是个大问题。然而它还有一个神人操作:他们做比较的时候用的是 strncmp,众所周知,C里面的字符串以 \00 结尾,而 strncmp 遇到比较两方中任意一个字符串的结尾就会终止匹配并根据之前的内容是否一致返回匹配结果。数学告诉我们:0 的任意乘方都只能得到 0,那我给 0 通过 RSA 签名的结果就是 0。配合前面的比较问题:把文件的 SHA-1 第一位给他弄成 0,就可以让任意文件都是有签名的。于是早期的 Wii 签名认证就被干掉了。
有了签名能力,我们还需要一个入口来把签名好的东西执行起来。塞尔达游戏的漏洞满足了这个需求:黄昏公主中玩家可以给自己的马依波娜改名,但改名功能并没有对马名字的长度做检验,于是可以给马起一个加长再加长的名字溢出游戏,拿到执行代码的能力。但任天堂为了防止用户通过修改存档利用游戏漏洞破解给存档做了校验功能。然而,之前的镊子破解把存档校验用的签名密钥导出来了,于是黄昏公主就成了执行代码的入口。
打补丁了吗?如打
之后任天堂当然是想把漏洞补上,但是尝试修补的过程比 Xbox 的拉锯战还抽象:
- 首先任天堂把那个签名校验问题修了,但只在一个新的系统里修了,由于多系统版本共存的设计,这个修复没有起到任何作用。
- 他们发现签名问题还是没修好,于是再修复了一次,还是没修好,这次多修复了系统菜单用的那个系统版本。他们也想把黄昏公主的存档溢出问题解决,但也没解决掉。
- 2008 年 10 月,他们终于把那个字符串漏洞的修复放进了所有系统版本。
- 然后就是黄昏公主漏洞的修复,但是没关系,妈妈生的游戏和软件还有很多,你的猪队友还有游戏王、星战、乐高等等动物朋友们。
系统组件也干了
但是上面这些漏洞都需要一个游戏来原神启动,那么有没有更方便更省钱的办法呢?破解者发现 Wii 系统里自带的公告板也干了:公告板里的消息存在外部设备上,而其中的内容加密密钥是全空字节,签名密钥更是直接拿 MAC 地址爆改出来的,于是只需要小手点一点就能再次原神启动。系统菜单里读收藏的 Channel 的过程中也有个差不多的问题,在此略过不表。
喂?我是你爸爸
之前不同的游戏使用不同版本的设计又发力了:切换版本需要重启,重启的时候无法保留状态。重启后读取数据就要重新签名和加密票据请求解密,但是加解密模块并没有验证加解密请求内容从哪里来到哪里去。恰巧主处理器也能发起解密请求,于是 IOS 就会开开心心的替我们签名修改后的东西。爆!
最后的彻底破解
由于 boot2 启动 IOS 的过程没做任何签名验证而只通过本机密钥做了完整性验证,所以利用上面签名问题可以轻易的替换掉 IOS 和系统界面,从而永久固化破解。
Xbox 360
吸取了 Xbox 的失败经验,微软这次选择不再直接从公开市场购买产品,而是去开发自己的定制芯片。由于 Intel 不愿意把自己的妙妙小工具提供给微软,这单生意就落在了 IBM 头上。可能是索尼没想到 IBM 会一鱼两吃,在当初东芝、索尼和 IBM 三方签订的合同里表明三方都拥有销售 Cell 的权限。而且微软也不知道当时索尼的 Cell 开发计划,所以 IBM 就把 Cell 中的安全技术和微软想添加的东西合成了一下生产出了 Xenon 这款定制芯片,最后这台白嫖了索尼技术的机器发布时间竟然比索尼还要早。而且微软为了简化编程模型没有使用 PPE/SPE 机制,而是制造了三个核都是通用处理器的芯片,使得成本和绝对性能更低的情况下,微软的产品体验反而更好。
微软急于上市,没有对这台机器中芯片的封装技术进行仔细测试,所以发生臭名昭著的三红事件:由于焊料的选择还有这款处理器恐怖的发热能力,早期的 Xbox 360 会在使用过程中造成 CPU /显卡内部焊点失效,让游戏机无法启动,必须送去维修。微软修复过多次但一直不彻底,直到后来机型通过换用改进了制程的芯片才解决。
顺带一提,为了在 Xenon 这款定制芯片出厂前开发系统,微软买了几台 PowerMac G5 初代双 CPU 版作为开发测试用机,所以你也可以搞一台 G5 刷成假的 Xbox 360 开发机。这几台 Mac 后来被擦掉系统折价卖给员工了。
安全机制
处理器
Xenon 作为和 Cell 同母异父的亲兄弟,安全模型非常接近,但微软并没有像索尼那样给操作系统一个单独的特权态,而是通过 Hypervisor 隔离操作系统和游戏,让它们都跑在用户态上。另外 Xbox 率先引入了用熔丝实现的回滚保护,一旦升级到某些版本的系统就无法降级到旧版本。
另外,Xenon 中存在一个有 32K ROM 和 64K SRAM 的外部安全加速器,负责对设备内存进行加密并添加校验,以防有人篡改外部内存内容。另外,和今天的 RISCV 与 现代 ARM 类似,Xbox 360 有 64 位的地址,但是内存空间比较小,不会使用全部 64 位地址位。内存的高位被挪用做内存地址是否加密的标志,让系统能同时处理加密和未加密的内存。
信任链
微软也同样采用了从内置于芯片中的固件开始的信任链,不过微软并没有设计一颗专门的安全处理器,而是把整个信任链都在 PPC 处理器上执行,密钥相关的安全和隔离保护由 Hypervisor 负责。
启动过程中,CPU 首先从内部的 1BL 开始,这一阶段会解密 CB 阶段的引导器,并验证它的 RSA 签名,验证通过后会把启动流程转交给 SA。
CB 阶段在不同机型上有些不同,在后期的机型上 CB 阶段分为 CB_A 和 CB_B 两部分,前一阶段负责检查后一阶段的哈希值是否和记录相匹配。但无论是新型号还是旧型号,都会进行内存和 PCIe 桥初始化等工作。完成初始化工作后,CB 加载 CD 阶段。
CD 阶段会首先解压并验证 CE 阶段,CE 是被压缩的 Windows 内核,解压并验证成功后,CE 还会探测 CF 阶段,其中是一个个的内核补丁,当全部补丁解压并应用完成后,CE 完成启动流程并将控制权交给 Hypervisor,之后由操作系统内核完成剩余的初始化操作,显示启动动画和主界面。
虚拟机和操作系统
不同于索尼单独的安全处理器核心,微软通过使用虚拟化来处理加解密操作。除了加解密操作,虚拟机还会检测并阻止游戏或操作系统作出不该作出的访问。具体来说,虚拟化层强制在内存中执行 W^X 策略,并且控制程序可以访问的内存边界,以防有人写出内存溢出。
另外,不像 PlayStation 3,Xbox 360 操作系统的绝大部分组件都是可以更新的。微软在处理漏洞方面的速度也比同行快到不知道哪里去了,几乎每个漏洞都会得到光速修复。
防复制
Xbox 360 的防复制措施和原版 Xbox 类似,区别在于前者使用了更接近普通 DVD 的格式,并且只是靠假的内容表欺骗光驱来防止读取。光盘上还存在冲切区但并不用来验证。
破解
买便宜货的后果
为了节省成本,Xbox 360 的光驱对通用光驱只做了很少一点点改造,光驱与主机之间的通信也是基于标准的 ATA 协议的,因此复制保护功能就很快被刷了固件的光驱干碎了。但破解的光驱只能让人玩盗版游戏,不能让人自己写。
荣誉提名:微软的后期机型为了避免刷光驱把 Flash 和 DSP 做了共封,但是 2011 年 8 月 12 日,Geremia 公布了用电钻在一个极其精确的位置打一个小洞打断某条线来关闭闪存写保护的方法。这个破解方法的名字神风,名字起得恰如其分啊。
DMA 的故事
Xbox 里不止有 CPU,也有其他外设,这些外设也需要通过 DMA 访问内存。但是加密并不是在真的 MMU 里实现的,外设在 DMA 时并不能读取和写入加密部分,因此需要有一部分内存保持未加密状态以供外设读写。组合上前面的高位加密标记和假光驱方法,这时候还需要一个有漏洞的游戏。
终于,在 23C3 上,一位未具名黑客展示了在 Xbox 360 上利用《金刚》运行 Linux 的操作,之后 SecurityFocus 在微软修复漏洞后披露了详情:通过利用该游戏处理着色器时的一个问题,黑客成功利用系统调用表检查时的漏洞把代码写入了未加密内存并执行,拿到了 Hypervisor 权限。
侧信道
在微软修复《金刚》问题后,人们想到最简单的办法就是想办法把固件降级到可利用的版本。但固件的版本和签名受到熔丝保护,无法随意修改。
这时微软工程师妈妈生的密码学水平又发威了,这台主机预留了生产时测试用的一些接口,能通过 SPI 写入 Flash,并会向外汇报开机状态码。而微软工程师由于妈妈生的密码水平,实现的 strncmp() 在验证成功和失败时的执行时间并不相同,这样就可以通过时间侧信道分析对签名进行暴力破解,从而修改固件。
又进厂了
很快微软又把上面的侧信道漏洞封锁了,阻止人们在新的固件上提取 CPU 密钥。但之前有人提取了启动过程中 CB 阶段的固件并进行了逆向,发现如果 CB 中某一部分密钥被清空,系统将会无视校验继续启动,而如果这个情况下更新包的密钥也是 0,则系统将会自动刷入这个更新。于是就有了把上述所有漏洞组合在一起并,自动启动漏洞版固件并利用金刚漏洞的 Modchip。
还得加大力度电
于是微软又把系统更新了,同时拉黑了有漏洞的 Hypervisor,但是游戏并没有结束。
在 2011 年的 8 月 28 日,GliGli 和 Tiros,公布了利用 CPU 的硬件漏洞绕过系统启动校验而破解的方法。该方法利用了 Xenon 的一个硬件问题,当 RESET 信号被短暂拉起时,CPU 不会完全重启,而是会带病继续运行。但这需要非常精确的控制拉起信号的时间。所幸,通过拉起一条信号可以将 CPU 的频率降低到一个非常低的水平,从而降低利用该问题的难度。
之后就是常规的拉锯战了,微软不断更新主板设计以加大利用难度,而黑客们也将破解方案不断改版并升级,直到 Xbox 360 失去商业价值,不再更新为止。
未完待续。
致谢
Xbox 相关内容主要来自 Console Mods Wiki 和 Free60,PlayStation 3 部分主要参考 PSDevWiki,Wii 部分主要来源为 WiiBrew 和 Team Twiizer (Fail0verflow) 在 ccc 的演讲。
