好吧,我承认标题有点夸大,不介意的都进来BS我把
就像 qihoocom 大侠说的,“SMM XX早就几万年前就不是什么秘密了”,不过国内讨论这个的到是鲜见,希望这篇文章能抛砖引玉吧。
之前看到rootkit.com上 Implementing SMM PS/2 Keyboard sniffer 那个代码,狠狠震撼了一把。于是开始研究SMM,半月下来总算有些收获。这里将如何读写SMRAM的方法拿出来科普一下,希望更多人能迈入编写SMM Rootkit的大门。
文章后面提供可以在VPC和VMware两大虚拟机中运行的代码,将演示如何在WinXP(SP2)中读写SMRAM。(本文只考虑最简单的系统环境,不涉及 SMM Space Locked(D_LCK)=1 时无法读写SMRAM的情况)另外,按 Ivanov 大牛的说法,这种方法局限性很大,只能在没有执行 Intel 修补方案的主板上运用(感谢两大VM模拟的都是I440BX )。
对硬件方面接触尚浅,文中若有疏漏之处,欢迎指正。
--------------------------------------------------------------------------------------------------------
首先放下PCI相关的诸多知识,我用最短的篇幅叙述读写SMRAM的过程。希望这篇文章能带你迈出SMM Rootkit的第一步。
首先说说什么是SMM(System Management Mode)。System Management Mode Hack中说:SMM是专门为电源管理设计的执行规则。当进入SMM后,系统的各个部件可以被关闭或者使用最低的功耗。SMM独立于其他的系统软件,也可以被用在其他目的... 该文章中文版点这里
了解SMM是什么东西就够了,这篇文章不会涉及太多SMM的东西。相反,读写SMRAM更需要的是PCI配置空间(PCI Configuration Space)方面的知识。
先讲讲两个访问PCI配置空间的I/O端口:CF8h 和 CFCh
通过向 CF8h 端口写一个特殊的地址,我们就可以在 CFCh 端口上读写指定寄存器的值。这里要读的寄存器是位于配置空间偏移为 72h 的8bit寄存器SMRAM (System Management RAM Control Register)
首先要介绍一下 CF8h 这个I/O端口。实际上 I/O CF8h 写的是CONFIG_ADDRESS寄存器,所以 CF8h又叫CONFIG_ADDRESS。其布局如下[1]:
按上图格式,31位置1(enable),假设I440BX的北桥82443BX位于Bus: 0, Device:0, Func:0(后面将教你如何确定芯片类型以及取得这几个值),这样配置空间的基址就是0x80000000。
通过I/O指令向CF8h写入0x80000000,就可以从 CFCh(CONFIG_DATA)中读出82443BX配置空间偏移为0的一个DWORD值了。而这个DWORD的高低16位分别是VendorID和DeviceID,如图:
下面在我们去读配置空间偏移为72h的SMRAM前,首先注意一个特性。不知道你注意到没有,回头看看CONFIG_ADDRESS的低2位,它们被定义为0。且不谈PCI规范上的大道理,说白了这个地方为0是为了限制你给出的地址必须为4的整数倍。了解到这一点再看那个Register Number就比较好理解了,原来这个寄存器编号和偏移是这么对应的。
好了,那么偏移为72h (01110010) 的SMRAM,最后两位置零是70h (01110000),即位于编号为1C (11100)的寄存器上。所以只要向 CF8h 里写入0x80000070这个地址,此时从 CFCh 端口读出的数据就是包含SMRAM的一个DWORD了。
假设读出来的数据为DWORD 380A0000h (00 00 0A 38),对照上面82443BX寄存器表可知:
70h 00 71h 00 72h 0A SMRAM 73h 38 ESMRAMC
好了,SMRAM寄存器读出来了,下面进入正题:如何将SMRAM内容映射到0xA0000。
从文献[2]中了解到,只要D_OPEN=1时,对物理内存0xA0000的访问会变成这样:
D_OPEN位在哪?SMRAM = 0Ah又代表什么?根据文献[1]记载,SMRAM的各位意义如下(关于SMRAM更详细解释,见文章末尾补充资料不部分):
7 6 5 4 3 2 - 0 0 D_OPEN D_CLS D_LCK G_SMRAME C_BASE_SEG | 1 010 |-> 我们就是要设置 D_OPEN = 1
附带程序中整个映射SMRAM过如下:
1. 首先遍历PCI设备,找到I440BX的82443BX Host Bridge Controller。
(VMware Workstation 6.0.x中82443BX 的VendorID: 8086h DeviceID: 7190h)
(Virtual PC 2007 6.0.x 中82443BX 的VendorID: 8086h DeviceID: 7192h)
很幸运,这两个虚拟机中,82443BX都位于Bus:0, Device:0, Func:0,所以PCI配置空间基址都是0x80000000。
2. 以I/O伪代码为例,读SMRAM:
out( CF8h, 80000070h ) // 还记得0x80000070怎么来的吗?
in( CFCh, eax ) // 读出包含SMRAM的一个DWORD,如 380A0000h
shr eax, 10h // SMRAM的8bit在第三个字节处,右移16位(2字节)
// 此时AL中就是SMRAM内容了(0Ah)
3. 置D_OPEN为1,并且C_BASE_SEG设为010
(C_BASE_SEG在初始化时就是010了,不过为了防止意外,最好重设一下)
out( CF8h, 80000070h )
mov eax, 384A0000h // 写回D_OPEN置1后的SMRAM(4Ah)
out( CFCh, eax )
4. 此时对物理内存0xA0000-0xBFFFF读写,就是在SMRAM中了。写完试试D_OPEN=0隐藏看看,读0xA0000是不是又回到显存了?
注意:当SMM Space Lock(D_LCK)为1时,这种方法是无法修改SMRAM的,只能另辟蹊径。
另外,关于读出的SMRAM内容,一定会有人质疑0xA0000处真的是SMRAM?关于这点,可以去看看SMRAM的布局http://www.sandpile.org/ia32/smm.htm。
我一般是通过7FF0h (EIP) 和7FF4h (EFLAGS) 这两个DWORD判断的(SMBASE默认是0xA0000):
> dump [000A7FC0 - 000A8000]
000A7FC0 00 00 00 00 28 00 00 00 00 04 00 00 F0 0F FF FF
000A7FD0 E1 BB 7E 81 83 A0 00 00 B2 00 00 00 00 00 00 00
000A7FE0 20 42 E6 F9 20 42 E6 F9 80 C2 A1 F9 E0 E0 6E 80
000A7FF0 47 8B A1 F9 46 02 00 00 00 90 03 00 31 00 01 80
EIP EFLAGS
参考文献:
[1] Intel 440BX AGPset: 82443BX Host Bridge Controller
http://download.intel.com/design/chi...s/29063301.pdf
[2] Shawn Embleton, Sherri Sparks, Cliff Zou.
SMM Rootkits: A New Breed of OS Independent Malware
[3] Loic Duflot, Daniel Etiemble, Olivier Grumelard.
Using CPU System Management Mode to Circumvent Operating System Security Functions
[4] Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide
http://www.intel.com/products/processor/manuals/
[5] A tool for FreeBSD to discover SMRAM on i440BX based motherboards
http://unix.derkeiler.com/Mailing-Li...att-0448/smm.c
测试环境:
Intel Pentium D 3.0GHz 双核 + Virtual PC 2007(6.0.192.0) + WinXP(SP2)
Intel Pentium D 3.0GHz 双核 + VMware Workstation (6.0.4-93057) + WinXP(SP2)
AMD Athlon 64 X2 Dual 4000+ + Virtual PC 2007(6.0.192.0) + WinXP(SP2)
Virtual PC 2007下的运行截图:
由于手头没有I440BX的主板,无法使用真实机器测试。另外 AMD64 Architecture Programmer's Manual Volume 2: System Programming 也提及了SMM的相关细节,目前还没有仔细看。
如果你在其他芯片组上测试成功,欢迎给我来信:upbit@126.com
ps: 忘补上一个开发库了,程序里用到了WinIO,可以到这里http://www.internals.com/
WinIO这个开发库附带C和VB的例子,理论上我这里给的代码都能翻译成C或VB的,有兴趣的不妨试试
.