The Wall, The Blog, The World

Sadly, Microsoft decided to shutdown live space and move all blog users to wordpress. Thanks to the easily tool provided by wordpress, I can move all my data to here.

But, the Wall still exists, I’m still hard to access and update my blog in future. And people in main land will not easily to read my articles too.

So, I plan to write articles in english for the future, friend all over the world will read them without trouble.

这年头连萝卜都靠不住了

一早起来就看到:

9月28日,微软正式宣布将终结自己前景黯淡的 Windows Live Spaces(共享空间)博客服务,近3000万原有帐户将被强制性迁移到主流的博客服务 WordPress.com。

嚯!几年前还以为微软总不会做什么朝三暮四的事情(当然手机什么的就算了),结果说倒就倒。

好吧,先用用wordpress,第一印象就是,真慢阿。

gDbgLoad

现在的破解组织也越来越不敬业了,破解个软件,RSA Key替换了,KEYGEN也写了,结果最后留个尾巴,得在调试器里面才能用被破解的软件……真够可以的。

得了,还是自己写个调试器,把软件Load起来吧。

gDbgLoad for gDebugger 5.x

第一财经周刊:书店的黄昏

如果三联韬奋图书中心是一家单纯的书店就好了,那样即便它干脆关门大吉,也不至于让人牵肠挂肚。但它不是。它是北京的文化地标,这个周边环境远远谈不上优雅的所在,是北京的读书人心目中真正的城市门面,也是他们的精神家园。可能不止是北京人,这个王府井大街走到头儿、夹在中国美术馆与已经衰败了的隆福寺之间的书店,也是很多读书人到北京来的必到之处,这里有读书味道。

他们难以想象这样一座文化地标的坍塌。第三极书局倒闭了,他们只是感慨一下书店业的衰落,但是没关系,还有三联韬奋图书中心呢,现在如果它也没了,他们可能就真的失落了。

虽然他们自己本身去书店的次数也在减少,但是这里关于阅读的温暖回忆会被他们放大。从事IT行业工作的田野曾经最喜欢一楼通向二楼的那些台阶,“人多的时候,每隔一级台阶靠墙一侧都会有一个读者席地而坐。阅读者神情专注,经过者小心翼翼。”

民科评语:很有意思的一个现象,书店尊重那些店里看书却从不花钱买的尊贵读者,却以卑劣的服务对待准备买回家仔细品读的顾客。

每每总有书店在指责网络的冲击,却从没有哪家撒泡尿照照自己的服务态度,尤以西单图书大厦和中关村图书大厦为甚。

发表在 Book. 1 Comment »

一块六

昨天下班,琢磨了一下,坐公交能省一块六,而且下车就是家门口,中间只需换一次。

于是我就傻x呵呵的坐公交了……到新街口换车……OMG!!!他妈的这么多人。算了以后我还是老老实实的跟西直门坐地铁到鼓楼走回家吧……

PS Jailbreak 原理分析

很久没有写技术文章了,最近PS3破解比较火热,我就分析一下。

首先需要介绍一些破解用到的底层技术:

  • Heap overflow

Heap(堆)是所有编程语言底层内存管理的基础,即便用汇编可以胡乱搞,写大程序也肯定还会用到堆管理器。在cc++里面,当我们用malloc、free、new、delete之类的内存操作函数,我们就和堆管理器打交道了。堆管理器的实现有很多种,算法各有不同,有用红黑树,也有简单的linklist,还有为了提高性能只能分配固定尺寸的内存池。

这些不同的实现大多数有一个典型特征:对齐。由于现代计算机体系结构的缘故,对齐的数据才有较高的访问速度,在某些硬件体系架构上,访问非对齐内存甚至会直接导致machine check。由于对齐,比如我们请求100字节,其实堆管理器会自动选取一个对齐的尺寸,然后分配那么大的一块,比如说128字节,来返回给我们。当然这个描述是不精确的,下面解释一下。

堆管理器需要维护它所管理的每一块内存,也就是说,要维护每块内存的相关信息,比如长度,向前向后指针,状态(未分配,已分配等),那么这个状态怎么维护呢?一种很常见的做法是,放在这个内存块的首部。

假设现在程序员申请100字节,内存块信息本身16字节,那么堆管理器就会找一个128长度的内存块(如果没有这么大的,它会按照一定的算法,比如根据每块内存的信息合并未分配块),把这块内存的首指针+16返回给程序员,于是程序员很高兴,他有了100字节的内存。注意,在古老的系统上其实他可以安全的访问128-16字节。在现代系统上就不行了,堆管理器会在这100字节前后做特殊标记,在硬件页的尺度上也会设定一定的保护(请参考NXDEP),如果你写过了100,当free这块内存的时候,堆管理器会发现标记被破坏,也就是heap overflow了。

如果我们在这100字节的内存上写了256字节的数据呢?一个极大概率的事件是:我们破坏了邻近的内存块的信息。这就为恶意攻击制造了机会。

  • USB

USB是一种不对等总线,也就是有主机和客户机的区别,所有的操作都由Host发出。USB有两个比较重要的概念:地址,端点。

先说地址,Host是没有地址的,只有设备才有。类似的概念是MAC地址,局域网用普通hub大家连在一起,所有的数据包都会经过你的网卡,只有符合你的MAC的数据包网卡才会接受(注意这是最原始的情况,请网络帝指正)。

当一个新的USB设备插入host,比如优盘,由于USB接口上的电平变化,HOST控制器得知有设备插入并且区分出是1.x还是2.0(上拉下拉电阻不同),此时设备(优盘)的USB地址是0,HOST控制器和这个地址通信,并给设备指定一个新的USB地址,范围在1~~127(可以想象是DHCP过程),随后HOST控制器就用新的USB地址来访问设备了,每一个新插入的设备都会这么处理,于是你插上两个一样的优盘,它们也会得到不同的USB地址,于是系统就能区分开两个优盘了。

USB HOST控制器给设备分配了新的USB地址以后,就开始问:你是什么东西啊,你有什么功能阿如此如此,设备会用描述符(descriptor)的方式应答(descriptor格式USB规范里面有):我的VID是xx,我的PID是yy,我的名字叫zz……如此如此。

刚才说到了USB地址,这个数值USB收发器控制电路会保存下来用于今后的通信,但是因为这个东西比较特殊,所以大多数的芯片是不能手工修改自己的USB地址的。

端点是真正执行数据通信的端口,端点0是始终可以用的,被称为控制端点,具体就不细说了。

ok,上面废话这么多,下面开始说主题:PS Jailbreak。

一句话概括:PS Jailbreak通过精心构造的特殊USB描述符,使PS3处理这些描述符的时候Heap overflow,导致代码注入进而获取了GameOS的访问权限。

下面详细介绍PS Jailbreak(以下简称JB)攻击过程

(绝大多数翻译自http://ps3wiki.lan.st/index.php/PSJailbreak_Exploit_Reverse_Engineering,并加上必要的解释说明):

JB设备的外形(注意不是物理外形,是技术上的)是一个“六口 USB Hub”,注意我用了双引号,这东西只是对外宣称自己是Hub,实际上只是为了满足USB协议的需求,并没有完整地实现USB Hub的全部功能。

PS3开机的时候,在特定的情况下会在USB接口上搜索官方的JIG设备(我不知道这玩意的具体功能,操作方法是按POWER后200ms内按Eject),JB利用这个特性在开机检测JIG的时候在其虚拟的六个USB Port上轮番插拔6个设备(…………),由于系统需要为每个设备的处理过程分配内存,通过精心构造的USB描述符,实现了Heap overflow。

Port1:Hub初始化以后,第一个设备插入,pid/vid 0xAAAA/0x5555,有4个配置,每一个长度都是0xf00,由于这个长度没有超过4K的页面,所以推测PS3系统的malloc会为每一个配置分配一个4k的内存页。为什么要4个呢,因为可能已经有空闲内存了,用4个是保证有足够大的概率把页面对齐到4k边界上。然后JB重新报告其配置为18字节。其实在这个比较长的配置里面包含有payload(也就是用于注入攻击的功能代码)。

Port2:PS3读取完成1号设备的描述符以后,JB切换回Hub USB地址,然后谎称第二个设备插入,pid/vid 0xAAAA/0xBBBB,这个设备有一个22字节的描述符,只有前18个字节是有意义的,最后4个意义不明。

Port3:随后这个设备插入,pid/vid 0xAAAA/0x5555,和第一个一样但是描述符不一样,他有两个配置描述符,每一个长度为0xa4d,大部分的数据被认为是垃圾。按照对堆管理器的猜测,这些描述符会被放在一个新的4k页面上,紧随之前的两个设备。

Port2:拔出。这个设备的拔出导致一个显而易见的结果,第一个设备和第三个设备之间分配的内存被释放了。

OK,上面这样的折腾,准备好了真正的攻击环境上下文。

Port4:连接。pid/vid 0xAAAA/0x5555,有三个配置描述符。

配置描述符A,18字节的正常描述符。

配置描述符B,和A一样的描述符,但是当PS3初次读取它之后,它把自己的长度变成了0字节。这是破解的关键之处,但是其具体含义含混不清,它导致了配置描述符C后面的数据覆盖了某一个malloc的边界标志,很可能是属于Port3的。但是这个溢出的详细原因恐怕得看攻击代码本身了。

配置描述符C,这个描述符开始和A是一样的,但是最后多了14个字节。

.. .. 3e 21 00 00 00 00
fa ce b0 03 aa bb cc dd
80 00 00 00 00 46 50 00
80 00 00 00 00 3d ee 70

前六个字节被认为是占位(但是我不这么认为,by hyperiris),接下来是一个magic number,fa ce b0 03 aa bb cc dd,用英语来看就是FACEBOOK AABBCCDD,随后的数据是一个指针,它覆盖了malloc块的边界标记,这会导致malloc在之后处理这个块的时候发生错误,使其按照攻击者的意愿在指定的位置操作内存。(这是两个64位的指针,by hyperiris)

Port5:当Port4完成工作以后,假的JIG被插入到了Port5,它和SONY官方的JIG PID/VID 0x054C/0x02EB 是一样的,推测和官方的配
和端点一致。

可以猜测由于这个玩意(JIG)是PS3已知的设备,PS3系统不会为它在堆上分配内存。

随后PS3发送64字节的数据要求JIG进行认证,然后JB返回64字节的应答。PS3将会分配内存来保存这个应答(!!!!),由于之前malloc块的边界标记已经被Port4的插入所修改,所以这次内存分配将会在一个设计好的位置,也就是某一个函数的前面,(某函数24字节偏移之前),然后函数的前面被这64字节覆盖了(!!!!)

由于系统的JIG认证代码没有被patch,所以JB返回的数据被验证无效。

Port3:拔出。JB现在通知PS3,Port3拔出,这导致PS3释放为Port3设备配置描述符分配的内存,也就是被Port4设备描述符覆盖的那个。

于是Shell code此刻被调用,R3寄存器现在指向的是Port3配置描述符的内存边界标记位置。

Shellcode:

ROM:00000018                 ld      %r4, -0x10(%r3)
ROM:0000001C                 ld      %r3, -8(%r3)
ROM:00000020
ROM:00000020 loc_20:                               # CODE XREF: sub_18+14�j
ROM:00000020                 ld      %r5, 0x18(%r3)
ROM:00000024                 addi    %r3, %r3, 0x1000
ROM:00000028                 cmpw    %r4, %r5
ROM:0000002C                 bne     loc_20
ROM:00000030                 addi    %r6, %r3, -0xFE0
ROM:00000034                 mtctr   %r6
ROM:00000038                 bctr

R4保存的就是0xfaceb003aabbccdd,然后R3加载0x8000000000465000,然后shellcode从0x8000000000465000开始搜索每一个4k边界,直到在某一个位置发现0xFACEB003AABBCCDD,发现之后,shellcode跳转到那里,从偏移0x20处开始执行。

清理:现在一切都清静了,Port5,4,1都将被拔出。Payload应该在Port1拔出之前将自己复制到一个不会被释放的内存块里。

Port6:这个设备没有任何的实际意义/功能,vid/pid 0xAAAA/0xDEC0,只响应一个控制传输0xAA,当PS3给这个设备发送这个控制传输,JB就知道自己成功了,并点亮LED。

在原始的JB里面,payload会检测这个设备是不是被拔掉,如果拔掉了,就调用LV1_Panic宕机。PSGroove把这个傻逼功能去掉了。

至于payload代码,和PS3版本有关,具体资料没有,因为需要ps3 main memory dump。