SMM和如来佛手掌心

久未更新这个公众号了,很感觉愧疚。今天有些空闲,又静不下心写代码,那么就写篇文章吧,比虚度要好。

今天的题目是突然从大脑里里冒出来的,先冒出来的是“SMM”,后冒出来的是“如来佛的手掌心”。什么是SMM呢?一两句话真说不清楚。什么是如来佛的手掌心呢?大家都明白。且看《西游记》里的一段原文:

那大圣收了如意棒,抖擞神威,将身一纵,站在佛祖手心里,却道声:“我出去也!”你看他一路云光,无影无形去了。佛祖慧眼观看,见那猴王风车子一般相似不住,只管前进。大圣行时,忽见有五根肉红柱子,撑着一股青气。

用一句儿时逗趣常说话就是:“你孙猴子再厉害,也逃不出我如来佛的手掌心。”

那么什么是SMM呢?简单说,就是计算机世界里的“如来佛手掌心”。其实我是要写SMM的,为什么把如来佛的手掌心放进来,就是为了帮助大家用“已知”来理解“未知”。

说清楚SMM可不容易,尤其我想是让懂软件的人理解的很深,不懂软件的人也能看个大概(^_^)。

2018年6月,芯片巨头英特尔推出了一款型号很特别的CPU,8086K。还搞了个抽奖的活动,在全球发放礼盒套装。

这个活动是为了纪念40年前的一个产品,也就是真正的8086。长得就是上图中酒瓶子右侧卧倒那个那样。

1978年6月8日,8086问世,它的宣传海报上画了一轮冉冉升起的太阳,上面写着“8086的时代到了”。

这张小海报设计的太好了,它的预言也太灵验了。8086的时代真的到了,而且不仅8086非常成功,而且它的后代也一路走红,经过40多年的发展,繁衍出了一个强大的生态系统,或者称为x86阵营。

既然称为生态系统,那么就不能只有一个角色,一定是有很多个角色,分工合作。经过几十年的磨合,x86阵营中的角色定义已经非常成熟和稳定,各自的分工和任务也都非常清晰和明确。在这些角色中,有一半是偏向硬件的,比如ODM工厂,固件提供商,OEM等。另一半是偏向软件的,比如操作系统(OS)提供商和应用软件开发商。对于前一半,大多是很听话的(应该听说的大家都明白),因为可以通过很多手段来让他们听话。但是对于后一半,就不那么“听话”了。从计算机系统的工作过程来看,开机后执行的是固件的代码,一般是固件厂商提供的,这个阶段某种程度来说是在掌控内的。但是过了固件之后,便进了操作系统。而且大多数时间里,整个计算机系统都是在OS的控制之下。

很长的一段时间里,x86硬件上面的主要OS就是Windows。Windows是微软的,虽然Wintel关系不错,但毕竟是两家公司,有些事情让对方做总是不方便。举例来说,CPU的某些设计可能存在不足,需要在某些时候做个“缓解”动作。如果这样的补丁都要找微软来落实的话,一则麻烦,二则也容易泄露敏感信息和丢面子。

于是,一个问题摆在了英特尔架构师的面前,那就是如何在OS阶段仍然可以掌控自己的CPU,让CPU给“娘家做点事”。

在x86架构如日中天的90年代,英特尔的CPU设计团队里集结了很多超级大脑。对于这样的问题,当然轻松搞定。于是在1993年推出的486 SL中,便有了名为SMM的特殊模式。

现代CPU一般都有多种工作模式,不同的工作模式具有不同的功能,一般用于执行不同特征和复杂度的代码。以x86为例,刚开机时,总是进入实模式,这个模式下的逻辑地址可以简单的翻译为物理地址,不需要页表,所以适合开机早期使用。进入操作系统后,因为要支持多任务,所以要进入保护模式。所谓保护模式,就是要像人类社会一样,“保护”社会里的每个公民(程序/任务),万物共生而不相害,大道并行而不相悖。

在引入SMM时,x86 CPU有如下三种模式:

  • 实模式:开机时是这种模式

  • 保护模式:支持多任务,进了操作系统后,大多数程序使用的都是这种模式

  • 虚拟8086模式:用于偶尔执行老的8086程序,目的是兼容旧的软件

那么新引入的SMM模式,用来干什么呢?从名字来看,就是用于系统管理。名字的全称就是系统管理模式(System Management Mode)。操作系统不就是做系统管理的么?为什么又来一个系统管理?

这个情况很像是有人任命你是总经理,但是过两天又来了个总经理。因为这个原因,微软一看到SMM这个技术,老大的不高兴。“本来不是说好咱们俩合作的么,你搞硬件,我搞OS管理硬件和整个系统,现在你又整个‘系统管理’,这不是和我唱对台戏吗?如果一定要搞,到底是我权力大,还是它权力大呢?”

是的,如果一定要有两个经理,那么很关键的问题就是:“到底是我权力大,还是它权力大呢?”

很不幸,答案是新来的SMM权力更大。^-^

更确切的说,SMM在系统中拥有比OS更高的权力,可以随时打断OS的执行,让CPU进入SMM模式执行SMM中的代码。

实模式和保护模式的切换一般都是软件自己发起的,也就是主动的切换和权力交接。而进入SMM不是,是强制的,也就是不管CPU当前在干什么,只要一个神秘的SMI触发,CPU立刻就飞走了,飞进保护模式。

在著名的英特尔”软件开发者手册“(SDM)中,有一张模式切换图。它是理解x86架构的关键地图。在这幅图中,画出了x86 CPU所支持的所有工作模式,可以看到,所有模式和SMM之间都有连线,这意味着,从任何模式都可以切换到SMM。

引入SMM对于微软来说,明显是引入第三者,而且第三者的权力还更大。事实上,SMM的引入也确实给OS设计带来了一些麻烦。举例来说,OS在做一些敏感动作,本来以为是独占的,时间是连续的,但其实CPU可能飞走进SMM一会,这时刚才的逻辑就被打断了,可能被窥探,如果“测量时间”的话,测量就不准了。

回望历史,Wintel联盟后来逐渐破裂,这个SMM模式一定是有”贡献“的。当然更让微软不能接受的是英特尔后来大搞Linux。

尽管微软不喜欢,SMM还是成了事实,而且直到今天一直在起作用。虽然SMM一直存在,而且时不时的在工作,但是它却是不可见的。因为它的特权高,所以在OS中,不可以访问SMM的地址空间,一旦访问,就会触发异常。另一方面,SMM中的代码是可以访问OS的数据的。

在软件安全领域享有盛名的系统软件专家Joanna曾研究过SMM,并在论文中写下了这样意味深长的话:

System Management Mode (SMM) is the most privileged CPU operation mode on x86/x86_64 architectures. It can be thought of as of "Ring -2", as the code executing in SMM has more privileges than even hardware hypervisors (VT), which are colloquially referred to as if operating in "Ring -1".

Rafal Wojtczuk, Joanna Rutkowska

Attacking SMM Memory via Intel® CPU Cache Poisoning

用Joanna的话来说,SMM是x86架构中的最高特权。如果把OS内核所处的特权级别称为0层的话,那么SMM便是在-2层,数字越小,代表权限越高。

因为具有至高无上的特权,SMM空间中的代码和逻辑也一直披着极其神秘的面纱。除了一些做固件的工程师外,很少有人见到它的真容。

那么真的没有办法看到SMM的代码么?也不是绝对的,下面就介绍使用DCI调试的方法来探秘SMM。

使用USB3调试线把GDK7与主机相连,然后在主机上启动Nano Code,使用DCI Open方式开始内核调试会话:

type=usb3,proto=dcid,ipc=open,opt=rsn

点击Break发起中断,把目标机中断下来。执行k命令观察栈回溯,可以看到NT内核IDLE线程的执行过程:

Child-SP          RetAddr           Call Site fffff807`5709a7f8 fffff807`6b3ad3aa intelppm!C1Halt+0x2 fffff807`5709a800 fffff807`6b3a1424 intelppm!C1Idle+0x1a fffff807`5709a830 fffff807`5084ac1c intelppm!AcpiCStateIdleExecute+0x24 fffff807`5709a860 fffff807`5084a36e nt!PpmIdleExecuteTransition+0x70c fffff807`5709ab80 fffff807`509c5e94 nt!PoIdle+0x36e fffff807`5709ace0 00000000`00000000 nt!KiIdleLoop+0x44

执行rMFF观察全部寄存器,可以看到X86的大多数寄存器。

重点观察代表执行模式的CR0:

r cr0 cr0=0000000080050033

按位显示:

10000000 00000101 00000000 00110011

其中最低位的1代表目前启用了保护模式(PE),最高位的1代表了启用页管理(PG)。这表明此时是在保护模式下执行NT内核的代码。

那么如何观察SMM的代码呢?这有几个挑战:

  • 在普通保护模式下,不可以访问SMM空间

  • 进入SMM的时间很短,而且时间不固定,所以手工发起break是不可行的

那么有何办法呢?感谢英特尔CPU和调试设施的设计者们,在DCI模式下,可以启用进出SMM的事件,一旦CPU进入SMM便中断到调试器。

在Nano Code的View菜单选择JTAG Events打开专门设计的启用JTAG事件窗口,然后把SmmEntry和SmmExit设置为On。

执行g命令让目标机继续执行。本来想喝口茶“等CPU君入瓮”,可实际上1秒钟没到,SmmEntry事件就发发生了。

14:24:22#JTGE:JtagRunControlEvent:type=1 deviceid=4096 dc=1,name=SmmEntry type=SMM entry subtype= @8000 

其中的4096是0号CPU的设备号。

Nano Code的提示符变为如下特殊形式:

其中的16代表经典的16位实模式,0代表0号CPU。

执行r cr0观察cr0的内容:

r cr0 cr0=6e6f6974

可以看到最低位PE和最高位PG都为0,这意味着,保护模式和分页都没有启用。这正是SMM模式的特征。

通过View > Disassembly打开反汇编窗口,可以看到神秘的SMM代码。

接下来可以单步跟踪执行SMM的代码,看看CPU回”娘家“是为什么事情。如果单步跟踪结束,按g恢复执行,那么当CPU退出SMM模式时也会因为SmmExit事件而中断下来:

Break on event SmmExit is set to 0 on CPU 4096

这时可以看到CPU又回到了OS的领地。

那么理解SMM有何意义呢?首先从安全角度具有重要意义,因为SMM的权限高,一旦被黑客占领,那么它便像幽灵一样可以随时偷窥OS空间中的数据。另一方面,对我们深刻认识计算机系统也是非常有意义的。SMM客观存在而且在系统中起着关键作用,我们如果对其丝毫不知,那么在认识上便有了盲区。另外,理解SMM对于理解计算机产业的生态系统也是有价值的,这是非常生动的一个经典案例,屁股决定脑袋,伙伴之间有合作,也有制衡。

(对计算机系统感兴趣的朋友,欢迎参加即将开始的《在调试器理解计算机系统》系列讲座 http://advdbg.org/books/csdbg.pdf ,老雷20多年的心得体会,集结在10次讲座中,很多优惠政策,欢迎垂询)

***********************************************************

正心诚意,格物致知,以人文情怀审视软件,以软件技术改变人生

欢迎关注格友公众号

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值