由于内容过于长,所以第二部分又要分段了:第七世代的掌机和第八世代将在之后继续。
终于来到了比较现代的游戏机环节,之前的游戏机的安全措施基本上只能说是正版验证(除了 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 的高性能的发挥。也有少数游戏选择让 SPE 自己控制自己,这样开发更困难,但更能利用 Cell 强大的性能。还有极少数游戏选择绕过操作系统,直接控制 SPE,这样极端困难的开发也带来了能将 Cell 性能发挥到极限的优势。
另外,索尼为了不浪费这个产品优秀的性能,同时也是为了减少破解过程的参与者,而发布了继承了 PlayStation 2 的光荣传统的 OtherOS 功能。该功能支持在虚拟化环境下用最多六个 SPE 和一个 PPE 运行 Linux 或者其他操作系统。不过为了安全,OtherOS 并没有被允许访问图形功能。
安全措施
处理器
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 内存总线,让系统在保留程序对这一块内存访问权限的情况下认为这一块内存已经被释放,之后不断申请内存,让内存中的映射表增长,直到映射表占用了之前被认为释放的内存块,从而让程序获得修改映射表的权限,并最终拿到了以高权限执行任意代码的能力。
索尼显然也看到了这个报告,并且很不高兴,因此决定即使要给客户赔偿也要在新系统里移除 Other OS 权限,毕竟赔偿款相对于盗版游戏造成的损失只能算是九牛一毛。
2010 年 8 月,有家组织发布了一款不需要修改机器就能安装任何软件的破解装置,只要插到 USB 口上就可以让用户在机器上想干什么就干什么。然后有人就买来设备进行逆向工程,发现它利用了 PlayStation 3 系统的 USB 功能的缺陷来执行代码,具体来说,PlayStation 3 在启动过程中会检测是否有用于进入恢复模式的妙妙小插件,然而这个破解装置会把自己模拟成一个 USB 扩展坞,通过不断的插拔设备构造特定的堆长度,然后在系统两次读取设备信息的时候返回不同的设备描述长度,从而让内存分配的信息被覆盖掉,最终通过一系列操作让堆溢出从而执行注入的代码。
之后索尼不断尝试升级固件填补漏洞,而有人做出了用恢复模式后门降级固件的工具,两方不断对抗,直到索尼推出了 3.55 固件,终于彻底封堵了降级。
在这次更新固件发布之后两天,有人发现索尼那个看起来挺聪明的证书吊销列表机制又犯了那个经典的错误:它没有检查吊销列表长度是不是对的,而不知道为什么,索尼允许在非特权态修改这个吊销列表。这样破解者就可以通过写进去一个假的吊销列表拿到隔离模式的权限,并用这个权限把隔离模式下的密钥全给偷出来了。
同年年底,fail0verflow(之后这个名字会经常出现的)发现索尼的工程师密码学水平可以说是妈妈生的,他们的 ECDSA 实现里的随机数生成器返回的结果是固定的 4(如果你冲浪多的话,大概看过那张图,你知道我说的是哪个),可能索尼的工程师觉得随机数拿骰子摇一个就完事了。所以之前说不要喷 Xbox 工程师,索尼这操作不比微软的神人多了?有了这个固定的随机数,索尼的 ECDSA 私钥就成为大家的私钥了,这样,整个系统里所有不是每台机器签名的东西就都可以被任何人替换掉。你干的好啊索尼!
然后索尼就爆了,他们在 3.56 版本把整个系统所有的签名密钥全都替换成了新的,包括系统升级用的,所以如果你不小心更新了系统,新的系统既不能降级到能破解的版本,也不能被破解。在 3.60 版本又推出了进一步的改造:索尼发现 metldr
这个东西没法升级,但是 lv1
可以升级啊,所以就把 metldr
的功能放到了 lv1
里,干掉了 metldr
这个无能的丈夫,从而要求用户只有破解了 lv0
这个组件的密钥才能做出新的自制系统来。而且后期发布的新机器甚至给 bootldr
进行了一个级的升,加入了对 lv0
的校验,这样,更新了新系统或者买新机器的倒霉蛋就完全没法破解了。
然后就是漫长的等待,直到 2017 年,有人利用索尼未修复的在别处发现的 WebKit 漏洞组合一个 PSV 同款的用后释放内核漏洞拿到了权限,旧版机器可以用这个方法不拆机刷回老版本,而新机器也可以临时获得运行自制软件的能力。考虑到这台机器已经没什么商业价值了,索尼象征性的修补了一下漏洞,但实际上并没有起到什么作用。
Wii
Wii 的硬件升级不大,CPU 模块“百老汇”是一颗超频升级版的 GameCube CPU(Gekko),这样的电子垃圾再利用带来的好处自然是更便宜的成本和更低的售价。而且由于硬件没有太大改动,只需要用特殊固件简单处理一下就能让它兼容 GameCube 游戏。
安全系统
操作系统
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
时检测到启动时为兼容模式,下一阶段从系统菜单变为用来提供 GameCube 兼容性的 MIOS
。
总结一下:启动过程的信任链如下:
硬编码的 boot0
启动闪存中生产时确定版本的 boot1
,boot2
在 ARM 上启动系统菜单 IOS
,并让 PPC 主处理器启动并给用户显示软件界面,软件界面可以让 IOS
去校验并在 PPC 上启动其它游戏。其中 boot0
需要重新投片才能升级,boot1
在工厂制造阶段可以升级,出厂后不能升级。IOS
可以在线升级。
光盘防伪
Wii 的光盘防拷贝和之前的技术很相似,采用了相近的冲切区编码识别和多层加密等技术,由于没有太多的创新性,只在这里简要提及一下。
破解
兼容性和一把镊子引发的血案
首先被研究的就是 GameCube 兼容性模块,上一篇提到过,GameCube 游戏完全没有签名机制,任天堂显然也不可能给它倒找出来一个。但任天堂为了防止它被利用,只允许 GameCube 游戏在只能访问有限内存且没有高级功能的模式下运行。但是,Team Twiizer(后改名叫 fail0verflow,我们在上面 PS3 的故事已经见过了)发现重启过程中主内存内容并没有被清掉,只是通过类似 MMU 的机制禁止访问了而已,而 Wii 的硬件地址线可以通过短接来重新映射,于是就有了一把镊子引发的血案——通过镊子短接地址线备份出来了内存中没有被擦掉的内容,然后发现妈妈生的任天堂把软件和SD卡解密密钥,每台主机独有的加解密密钥全都留在了内存里。
但是这种方法只能导出能够伪造数据或者每台主机独有的密钥,没办法破解全部主机。
妈妈生的密码学之第几次了?
任天堂在校验签名的时候只检验了哈希值的内容,并没有检验别的,但这本身并不构成致命问题。然而任天堂的软件里还有一个神人操作:他们做比较的时候用的是 strncmp
,众所周知,C里面的字符串以 \00
结尾,而这个函数遇到结尾就会终止匹配,认为结果是相同的。那么这里有一个事实,0 的任意乘方都会得到 0,那我把文件的 SHA-1 第一位给他弄成 0,不就弄个啥东西都能签名通过了?
于是早期的 Wii 签名认证就被干掉了。
这个漏洞提供了伪造签名的能力,但还需要一个入口点来执行任意代码。这时候塞尔达就来了,黄昏公主中允许玩家给自己的马依波娜改名,但并没有对名字的长度做检验,于是就有了一个溢出漏洞。但任天堂为了防止用户通过改存档利用游戏漏洞破解,给存档也做了校验功能。然而这个校验功能也炸了,前面镊子大法把这个签名密钥导出来了,于是就有了一个能利用的入口点。
打补丁了吗?如打
之后任天堂当然是想把漏洞补上,但是尝试修补的过程比 Xbox 的拉锯战还抽象:
- 首先任天堂把那个签名校验问题修了,但还记得之前的系统那段说的多
IOS
吗?他们只在一个新的系统里修了,能起到什么作用我不好说。 - 之后他们还试图再修一次签名问题,还顺便试图修复黄昏公主漏洞,然而签名问题只在用来跑系统菜单的
IOS
里修了,黄昏公主漏洞更是修了个寂寞。 - 2008 年 10 月,他们终于把那个字符串漏洞彻底在所有 IOS 里修复了。
- 然后就是黄昏公主漏洞的修复,但是没关系,妈妈生的游戏和软件还有很多,你的猪队友还有游戏王、星战、乐高等等动物朋友们。
系统组件也干了
但是上面这些玩意都需要一个游戏来原神启动,那么有没有更方便的办法呢?人们发现 Wii 系统里自带的公告板也干了:公告板里的消息存在外部设备上,而其中的内容加密密钥是全空字节,签名密钥更是直接拿 MAC 地址爆改出来的,于是只需要小手点一点就能再次原神启动。系统菜单里读收藏的 Channel 的过程中也有个差不多的问题,在此略过不表。
喂?我是你爸爸
IOS
还有个抽象的设计问题:因为兼容性问题,不同的游戏需要不同版本,而切换版本需要重启,重启的时候并没有保留状态。这时候要开启游戏,就要重新用签名和加密票据请求解密,但是解密模块并没有验证解密请求请求的是什么东西或是从哪发过来的。恰巧主处理器也能发起请求,于是 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 开发机。
安全机制
处理器
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 的演讲。