脑残的PsSetCreateProcessNotifyRoutine

Vista之前的系统,XP及Server 2003只有8个坑,就是说前8个调用成功之后,后续的所有调用都会失败,看来通过注册callback的方式来监控进程非常不靠谱。

从内核角度来说,尽量少的调用不仅提高系统响应时间,也降低了不靠谱的驱动所可能带来问题,但限制为区区8个总不是解决办法吧,比如Symantec家的SEP动不动就占3个,腾讯家(Tencent)更牛B,安全管家要用几个,QQ也要用,就连浏览器也要搞个驱动并也要注册个进程创建的回调通知,这也太让人无语了吧。

好在从Vista开始,这个限制从8个变成了64个,翻了整整8倍,呵呵,这下够用了?!

下面是一个典型的XP系统实例,8个回调会被占满了,后起的驱动们只能想其它办法了:

0: kd> x nt!PspCreateProcessNotifyRoutine 80564a40 nt!PspCreateProcessNotifyRoutine = <no type information> 0: kd> dd 80564a40 80564a40  e101894f e15e4eb7 e2031ff6 e1e8b56f 80564a50  e20a8d9f e51c641f e52246b7 e5ad82cf 80564a60  00000008 00000000 86a85d58 8656fac0 80564a70  86b9b5a0 86be5208 86be45a0 00000000 80564a80  00000000 00000000 00000000 00000000 80564a90  00000000 00000000 00000000 00000000 80564aa0  00000000 6d6f7441 00000000 00000001 80564ab0  00000000 00000000 00000000 00000000 0: kd> .for (r $t0=0; $t0 < 8; r $t0=$t0+1) {r $t1 = poi($t0 * 4 + nt!PspCreateProcessNotifyRoutine); .if ($t1 == 0) {.continue;}; r $t1 = $t1 & 0xFFFFFFF8; r $t1 = poi($t1 + 4); r $t0; r $t1; u $t1; ln $t1;} $t0=00000000 $t1=f7310790 TsFltMgr+0x10790: f7310790 55              push    ebp f7310791 8bec            mov     ebp,esp f7310793 83e4f8          and     esp,0FFFFFFF8h f7310796 83ec14          sub     esp,14h f7310799 53              push    ebx f731079a 56              push    esi f731079b 8b35a07b31f7    mov     esi,dword ptr [TsFltMgr+0x17ba0 (f7317ba0)] f73107a1 57              push    edi $t0=00000001 $t1=f771a788 ghcore+0x3788: f771a788 8bff            mov     edi,edi f771a78a 55              push    ebp f771a78b 8bec            mov     ebp,esp f771a78d 33c0            xor     eax,eax f771a78f 390564b471f7    cmp     dword ptr [ghcore+0x4464 (f771b464)],eax f771a795 7508            jne     ghcore+0x379f (f771a79f) f771a797 39056cb471f7    cmp     dword ptr [ghcore+0x446c (f771b46c)],eax f771a79d 741a            je      ghcore+0x37b9 (f771a7b9) $t0=00000002 $t1=ed1a3b00 SYMEVENT+0xcb00: ed1a3b00 8bff            mov     edi,edi ed1a3b02 55              push    ebp ed1a3b03 8bec            mov     ebp,esp ed1a3b05 51              push    ecx ed1a3b06 53              push    ebx ed1a3b07 8b5d08          mov     ebx,dword ptr [ebp+8] ed1a3b0a 56              push    esi ed1a3b0b 33f6            xor     esi,esi $t0=00000003 $t1=ecfeb120 QQFrmMgr+0xe120: ecfeb120 8bff            mov     edi,edi ecfeb122 55              push    ebp ecfeb123 8bec            mov     ebp,esp ecfeb125 51              push    ecx ecfeb126 51              push    ecx ecfeb127 53              push    ebx ecfeb128 8b5d0c          mov     ebx,dword ptr [ebp+0Ch] ecfeb12b 56              push    esi $t0=00000004 $t1=ecd098a0 SysPlant+0x78a0: ecd098a0 55              push    ebp ecd098a1 8bec            mov     ebp,esp ecd098a3 83e4f8          and     esp,0FFFFFFF8h ecd098a6 51              push    ecx ecd098a7 53              push    ebx ecd098a8 56              push    esi ecd098a9 57              push    edi ecd098aa a12480d1ec      mov     eax,dword ptr [SysPlant+0x16024 (ecd18024)] $t0=00000005 $t1=866b41d0 866b41d0 90              nop 866b41d1 90              nop 866b41d2 e9e7c4f466      jmp     QMUdisk+0x26be (ed6006be) 866b41d7 90              nop 866b41d8 90              nop 866b41d9 90              nop 866b41da 90              nop 866b41db 90              nop $t0=00000006 $t1=ecaf8070 BHDrvx86+0x6c070: ecaf8070 8bff            mov     edi,edi ecaf8072 55              push    ebp ecaf8073 8bec            mov     ebp,esp ecaf8075 807d1000        cmp     byte ptr [ebp+10h],0 ecaf8079 750f            jne     BHDrvx86+0x6c08a (ecaf808a) ecaf807b 8b450c          mov     eax,dword ptr [ebp+0Ch] ecaf807e 8b0d48e0b8ec    mov     ecx,dword ptr [BHDrvx86+0x102048 (ecb8e048)] ecaf8084 50              push    eax $t0=00000007 $t1=ee461eba dekfs+0x4eba: ee461eba 8bff            mov     edi,edi ee461ebc 55              push    ebp ee461ebd 8bec            mov     ebp,esp ee461ebf 83ec10          sub     esp,10h ee461ec2 807d1000        cmp     byte ptr [ebp+10h],0 ee461ec6 53              push    ebx ee461ec7 56              push    esi ee461ec8 57              push    edi

Server 2008 X64系统已经可以支持64个注册回调了,这个限制是硬编码在

函数PsSetCreateProcessNotifyRoutine中的:

0: kd> u nt!PspSetCreateProcessNotifyRoutine nt!PspSetCreateProcessNotifyRoutine: fffff800`01c3fab0 48895c2408      mov     qword ptr [rsp+8],rbx fffff800`01c3fab5 48896c2410      mov     qword ptr [rsp+10h],rbp fffff800`01c3faba 4889742418      mov     qword ptr [rsp+18h],rsi …… fffff800`01c3fad4 bb01000000      mov     ebx,1 …… fffff800`01c3fb3e e89d3cf1ff      call    nt!ExDereferenceCallBackBlock (fffff800`01b537e0) fffff800`01c3fb43 4403e3          add     r12d,ebx fffff800`01c3fb46 4183fc40        cmp     r12d,40h fffff800`01c3fb4a 72ae            jb      nt!PspSetCreateProcessNotifyRoutine+0x4a (fffff800`01c3fafa) fffff800`01c3fb4c 66019fb4010000  add     word ptr [rdi+1B4h],bx fffff800`01c3fb53 7518            jne     nt!PspSetCreateProcessNotifyRoutine+0xbd (fffff800`01c3fb6d) ……

此系统上并未安装腾讯管家等类似的防毒程序,但是64个注册回调已有6个被使用,差不多全是M$自家给占用的:

0: kd> x nt!PspCreateProcessNotifyRoutine fffff800`019f8ee0 nt!PspCreateProcessNotifyRoutine = <no type information> 0: kd> dq fffff800`019f8ee0 fffff800`019f8ee0  fffff880`00008c4f fffff880`006d7acf fffff800`019f8ef0  fffff880`006f694f fffff880`007ff5cf fffff800`019f8f00  fffff880`098168af fffff880`0a30216f fffff800`019f8f10  00000000`00000000 00000000`00000000 fffff800`019f8f20  00000000`00000000 00000000`00000000 fffff800`019f8f30  00000000`00000000 00000000`00000000 fffff800`019f8f40  00000000`00000000 00000000`00000000 fffff800`019f8f50  00000000`00000000 00000000`00000000 0: kd> .for (r $t0=0; $t0 < 0x40; r $t0=$t0+1) {r $t1=poi($t0 * 8 + nt!PspCreateProcessNotifyRoutine); .if ($t1 == 0) {.continue}; r $t0; r $t1 = $t1 & 0xFFFFFFFFFFFFFFF0; r $t1 = poi($t1 + 8); r $t1; u $t1; ln $t1;} $t0=0000000000000000 $t1=fffff8000188dbd0 nt!ViCreateProcessCallback: fffff800`0188dbd0 fff3            push    rbx fffff800`0188dbd2 4883ec40        sub     rsp,40h fffff800`0188dbd6 833dc3a2160000  cmp     dword ptr [nt!ViVerifierEnabled (fffff800`019f7ea0)],0 fffff800`0188dbdd 0f8583b6fcff    jne     nt! ?? ::FNODOBFM::`string'+0x21140 (fffff800`01859266) fffff800`0188dbe3 4883c440        add     rsp,40h fffff800`0188dbe7 5b              pop     rbx fffff800`0188dbe8 c3              ret fffff800`0188dbe9 90              nop (fffff800`0188dbd0)   nt!ViCreateProcessCallback   |  (fffff800`0188dbf0)   nt!IopAllocateFileObjectExtension Exact matches: nt!ViCreateProcessCallback = <no type information> $t0=0000000000000001 $t1=fffffa6000e52ffc ksecdd!CredMarshalTargetInfo+0x8cc: fffffa60`00e52ffc 4883ec28        sub     rsp,28h fffffa60`00e53000 488364244800    and     qword ptr [rsp+48h],0 fffffa60`00e53006 4584c0          test    r8b,r8b fffffa60`00e53009 488bc2          mov     rax,rdx fffffa60`00e5300c 7546            jne     ksecdd!CredMarshalTargetInfo+0x924 (fffffa60`00e53054) fffffa60`00e5300e 488d542448      lea     rdx,[rsp+48h] fffffa60`00e53013 488bc8          mov     rcx,rax fffffa60`00e53016 ff15dc00feff    call    qword ptr [ksecdd!BCryptDestroySecret+0x191c8 (fffffa60`00e330f8)] (fffffa60`00e52730)   ksecdd!CredMarshalTargetInfo+0x8cc   |  (fffffa60`00e535f4)   ksecdd!AcquireCredentialsHandleW $t0=0000000000000002 $t1=fffffa600106f830 tcpip+0x69830: fffffa60`0106f830 4d85c0          test    r8,r8 fffffa60`0106f833 7405            je      tcpip+0x6983a (fffffa60`0106f83a) fffffa60`0106f835 e9860b0000      jmp     tcpip+0x6a3c0 (fffffa60`010703c0) fffffa60`0106f83a e911130000      jmp     tcpip+0x6ab50 (fffffa60`01070b50) fffffa60`0106f83f 90              nop fffffa60`0106f840 90              nop fffffa60`0106f841 90              nop fffffa60`0106f842 90              nop $t0=0000000000000003 $t1=fffffa600074e06c CI!I_PEProcessNotify: fffffa60`0074e06c 4584c0          test    r8b,r8b fffffa60`0074e06f 7528            jne     CI!I_PEProcessNotify+0x2d (fffffa60`0074e099) fffffa60`0074e071 53              push    rbx fffffa60`0074e072 4883ec20        sub     rsp,20h fffffa60`0074e076 488bda          mov     rbx,rdx fffffa60`0074e079 ff15f1d1f5ff    call    qword ptr [CI!_imp_IoGetCurrentProcess (fffffa60`006ab270)] fffffa60`0074e07f 488bc8          mov     rcx,rax fffffa60`0074e082 ff1530d0f5ff    call    qword ptr [CI!_imp_PsIsProtectedProcess (fffffa60`006ab0b8)] (fffffa60`0074e06c)   CI!I_PEProcessNotify   |  (fffffa60`0074e0a0)   CI!RSA32Alloc Exact matches: CI!I_PEProcessNotify = <no type information> $t0=0000000000000004 $t1=fffffa6002fac964 dekfs+0x6964: fffffa60`02fac964 48895c2408      mov     qword ptr [rsp+8],rbx fffffa60`02fac969 48896c2410      mov     qword ptr [rsp+10h],rbp fffffa60`02fac96e 56              push    rsi fffffa60`02fac96f 57              push    rdi fffffa60`02fac970 4154            push    r12 fffffa60`02fac972 4155            push    r13 fffffa60`02fac974 4156            push    r14 fffffa60`02fac976 4883ec50        sub     rsp,50h $t0=0000000000000005 $t1=fffffa600c545b2d peauth!I_PEProcessNotify: fffffa60`0c545b2d 48895c2408      mov     qword ptr [rsp+8],rbx fffffa60`0c545b32 57              push    rdi fffffa60`0c545b33 4883ec20        sub     rsp,20h fffffa60`0c545b37 e8cc6bfdff      call    peauth!WARBIRD::Stub_VerifyVerifierCheckSum (fffffa60`0c51c708) fffffa60`0c545b3c 90              nop fffffa60`0c545b3d 360000          add     byte ptr ss:[rax],al fffffa60`0c545b40 00fd            add     ch,bh fffffa60`0c545b42 140a            adc     al,0Ah (fffffa60`0c545b2d)   peauth!I_PEProcessNotify   |  (fffffa60`0c545fe1)   peauth!PEReturnCertChain Exact matches: peauth!I_PEProcessNotify = <no type information>

Security-Enhanced CRT,边界与潜规则

Windows Security-Enhanced CRT 相关函数(即_s后辍函数)并不是对老函数的直接替代,其中不仅有更严格的参数检查,还会有buffer的重置操作等,使用的时候要格外小心,一定要仔细阅读MSDN描述或者VC runtime源码 (以Visual Studio 2008为例: C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src)。

下面不妨测试3个代码片段:

测试代码【C1】:

void main() {
    char dst1[8];
    memcpy(dst1, NULL, 0);
    memcpy(NULL, NULL, 0);
}

测试代码【C2】:

void main() {

    char dst1[8];

    memcpy_s(dst1, 8, NULL, 0);
    memcpy_s(NULL, 0, NULL, 0);
    char *dst2 = (char *)malloc(0);
    if (dst2) {
        memcpy_s(dst2, 0, NULL, 0);
    free(dst2);
    }
}

测试代码【C3】:

void main() {

    char dst1[8];

    memcpy_s(NULL, 0, dst1, 8);

    char *dst2 = (char *)malloc(0);
    if (dst2) {
        memcpy_s(dst2, 0, dst1, 8);
        free(dst2);
    }
}

这几段代码实际上什么也没有做,只是参数有变化而已,但测试中会发现【C3】会导致程序崩溃。具体原因就是因为memcpy_s进行了更严格的参数检测,可对参考memcpy_s的源码,引用自Visual Studio 2008 runtime source memcpy_s.c:

/***
*  memcpy_s.c - contains memcpy_s routine
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*  Purpose:
*       memcpy_s() copies a source memory buffer to a destination buffer.
*       Overlapping buffers are not treated specially, so propagation may occur.
*
*******************************************************************/

#include <cruntime.h>
#include <string.h>
#include <internal.h>

/***
*  memcpy_s - Copy source buffer to destination buffer
*
*  Purpose:
*       memcpy_s() copies a source memory buffer to a destination memory buffer.
*       This routine does NOT recognize overlapping buffers, and thus can lead
*       to propagation.
*
*       For cases where propagation must be avoided, memmove_s() must be used.
*
*  Entry:
*       void *dst = pointer to destination buffer
*       size_t sizeInBytes = size in bytes of the destination buffer
*       const void *src = pointer to source buffer
*       size_t count = number of bytes to copy
*
*  Exit:
*       Returns 0 if everything is ok, else return the error code.
*
*  Exceptions:
*       Input parameters are validated. Refer to the validation section of the function.
*       On error, the error code is returned and the destination buffer is zeroed.
*
*******************************************************************/

errno_t __cdecl memcpy_s(
    void * dst,
    size_t sizeInBytes,
    const void * src,
    size_t count
)
{
    if (count == 0)
    {
        /* nothing to do */
        return 0;
    }

    /* validation section */
    _VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL);
    if (src == NULL || sizeInBytes < count)
    {
        /* zeroes the destination buffer */
        memset(dst, 0, sizeInBytes);

        _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL);
        _VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE);
        /* useless, but prefast is confused */
        return EINVAL;
    }

    memcpy(dst, src, count);
    return 0;
}

参考阅读:

1, _snwprintf_s的潜规则https://blog.dynox.cn/?p=791
2,   Security Features in the CRT:
      https://msdn.microsoft.com/zh-cn/library/vstudio/8ef0s5kh(v=vs.110).aspx

驱动的PE文件头校验和

众周所知,应用层PE程序的校验和一般为0,进程加载时系统并不检验,但驱动程序是要强制验证的,并且WinDDK在生成.sys文件时已经设置的校验和。

但是在写上篇blog时(https://blog.dynox.cn/?p=1391)发现系统并不必须对驱动程序文件进行CheckSum的验证。实验中发现系统只是针对 SERVICE_BOOT_START (0) 的驱动文件进行验证,而此时其实是Windows启动程序WinLoad.exe做的加载及验证。

签名文件的修改

已经签名的PE文件原则来说不再修改的,但总有需求要添加些数据在PE文件中,为了更文件分发等。经研究发现,签名的PE文件也是可以修改或追加数据的,当然追加的数据只能是纯数据,比如相关配置信息,或安装包的附加数据等。

我们先来看一下签名文件的格式及数据校验范围,此图引用自Microsoft的关于PE文件签名的文档[REF1]:

image

其中灰色部分是不进行签名校验的数据,但这三部分只有第三个区域才有追加数据的可能,因为第一部分是4个字节,是PE文件自有的校验数据,有兴趣的同学可以参阅 REF2;第二部分是PE文件头的数据目录,其结构是固定的8个字节(前4字节为偏移,后4字节为长度)。第三部分是签名数据部分,经有限观察,长度在3K字节左右。

实际实用中,最后“Remaining content”这部分并存在,签名数据就已经在文件尾了,所以这就给我们在签名数据中(亦是文件尾)加入我们自定义数据的可能。

下面不妨做个实验,以Intel显卡驱动igdkmd64.sys为例:

pic2.0

签名信息如下:

pic1

然后我们添加16个字符至文件尾: pic3

检查下文件长度,从3,828,152变为3,828,168:

image

此时右键打开文件属性就会发现签名信息认证没有了:

pic2

之后,我们还要修改数据目录,以增大签名数据区的大小。用PE Tool 1.0.0.5打开igdkmd64.sys,查看数据目录部分:image

所以我们只需要将文件偏移0x000001d0处的目录项中的长度从0x29B8改成029C8即可,即增加了16字节。修改好再来看文件属性,此时签名项的tab又出现了,即说明通过了Windows的签名检测:

image

不妨再用Windows签名工具检验一次,以确保签名数据的有效:

image

自此足以说明签过名的文件是可以修改的,当然只能做有限修改。对应用层PE程序,以上的修改便已足够,但对驱动程序来说,还要做一件事情,就是更新PE文件头的校验和。相关工具可以参见[REF2]中的工具,也可以通过我写了小程序[REF3]做校验和计算。

image

将新计算出的校验和 0x003A7A63更新至文件偏移0x180处即可,然后就可以用新文件替换掉老的,重启系统即可以加载新修改后的驱动了。

参考资料: REF1: Windows Authenticode Portable Executable Signature Format, Version 1.0  — March 21, 2008 http://www.microsoft.com/whdc/winlogo/drvsign/Authenticode_PE.mspx REF2:   An Analysis of the Windows PE Checksum Algorithm by Jeffrey Walton http://www.codeproject.com/Articles/19326/An-Analysis-of-the-Windows-PE-Checksum-Algorithm REF3:   PECheckSum: http://dynox.cn/soft/PECheckSum.zip

Ext2Fsd 0.52 was released !

Features implemented and bugfix since V0.51:
1, Feature: Windows 8 supported
2, Feature: Force-writing supported
3, FIXME: data loss with TeraCopy when moving directories
4, FIXME: ATTO Disk Benchnmark fails with direct i/o tests
5, FIXME: files become invisible with empty hidden pattens
6, FIXME: possible hang with concurrent access attempts
          upon the same file
7, FIXME: BSOD due to pagable code section
Supported Ext3/4 features by 0.52:
1, flexible inode size: > 128 bytes, up to block size
2, dir_index:    htree directory index
3, filetype:     extra file mode in dentry
4, large_file:   > 4G files supported
5, sparse_super: super block backup in group descriptor
6, uninit_bg:    fast fsck and group checksum
7, extent:       reading, writing with no extending.
8, journal:      only support replay for internal journal
9, flex_bg:      first flexible metadata group
Unsupported Ext3/4 features:
1, journal: log-based operations, external journal
2, extent: size truncating & expanding, file deletion
3, EA (extended attributes), ACL support
4, symlink creation
Features to be implemented in future:
1, EXT3/4 features support (extents, journal)
2, Documents improvement: clear and elaborate
3, Performance improvement, code optimization
4, Automatic check & update of new versions
5, LVM support, e2fsprogs porting for Windows
Files descriptions:
Ext2Fsd-0.52.exe:       setup wizard for Windows systems (Win2k, Winxp,
                        Vista, Win7, Win8, Server 2003, Server 2008/R2)
Ext2Fsd-0.52.7z:        Batch setup package in 7-zip
Ext2Fsd-0.52.zip:       Batch setup package in zip
Ext2Fsd-0.52.src.7z:    Source codes of Ext3Fsd and Ext2Mgr in 7-zip
Ext2Fsd-0.52.src.zip:   Source codes of Ext3Fsd and Ext2Mgr in zip
Download link:
http://sourceforge.net/projects/ext2fsd/files/Ext2fsd/0.52/ 
Files checksum:
C:\Works\Ext2fsd\0.52>sha1sum Ext2Fsd-0.52*
8921c8a8bc57e46f8775836359d8868437e8e857 *Ext2Fsd-0.52.7z
5a83af60fc2773feacb241dd68532075f6a74f1e *Ext2Fsd-0.52.exe
0fba60af536ca8edd0c7951433a6916ab4f0042b *Ext2Fsd-0.52.src.7z
0eed9235a845449e5e3d0fa0139182a78c2ecfb0 *Ext2Fsd-0.52.src.zip
d4d1a416409645dc27a328bf1acd44ebd669f671 *Ext2Fsd-0.52.zip
WARNINGS:
The driver may crash your system and ruin your data unexpectedly,
since there might be software conflicts and I could only test it
on some of the popular platforms. You should use it with care and
use it at your own risk!
Matt <mattwu@163.com>
http://www.ext2fsd.com

SSD到底快多少

做驱动开发的人都曾有过无数次测试重启后的等待,等待着新驱动在debug窗口传出的一串特定的字符,等待着下一个不期而遇的BSOD,等待着新代码终于工作时那一声惊人的呐喊。

等待的心情总是很复杂,或期盼,或疑惑,或焦急,或无奈。等待的状态同样无奇不有,或似无所事事的发呆,或白痴+花痴状直沟沟得盯着屏幕,或紧握鼠标迫不及待的要在第一时间挥出致命一击,或者做个忙里偷闲状伸个懒腰,抑或干脆走开…

等待的时间里,无论多短,总会觉得很长很长!随着硬件速度的提升,人的耐性却是直线式的下降。

于是,SSD来了。一周前我还在考虑要不要将测试机换上个SSD,然后周三就看到超能网上的SSD团购。第二天京东就送来了影驰战将240G。今天(周五)下午终于有时间折腾测试系统,从原来500G的ST7200.4上转移到这个容量只有一半大的SSD上。

我的测试机是一台较古老的Thinkpad X61 (T8100 2.1G双核, 内存5G),硬盘是ST Momentus 7200.4,装有xp, win7 32位,win7 64位,win8 64位及 Ubuntu 12.10共5个操作系统,但新购SSD只有240G,故舍弃了win7 32位系统,做了备份必要时可以随时恢复。

测试过程中发现用HDTunePro及ATTO Bench测试SSD时的最好I/O速率只有110MB/s。经过几番周折才发现X61的SATA接口竟然是SATA1的,联想在BIOS里做了人为限制。通过BIOS升级可以解除了SATA1的限制。SATA2的表现明显好于SATA1,性能平均要比SATA1高50%多。

下面是HDTunePro 5.50分别在SATA1及SATA2接口下的性能对比:

20140509-SSD-HDTUNE-sata120140509-SSD-HDTUNE-sata2

ATTO Bench 结果对比 (direct i/o, i/o comparison):

20140509-SSD-sata120140509-ssd-sata2

SATA2的I/O性能虽然好了很多,但在操作系统重启动时间的对比测试中,并没有带来很大提升。参见下面的各操作系统启动时间的对比图:

启动时间的测试,是从开启电源开始算,直接操作系统启动,自动登录,然后弹出我的一个测试程序的界面。关机时间的测试,是从点击“关机”按钮直到电脑电源关闭。

20140509-SSD-perf-booting20140509-SSD-perf-bootingdata

相对于原来的机械硬盘,SSD的表现还是非常给力的。至于SATA1及SATA2接口,虽然最大的I/O性能强了很多,但在系统启动及关闭的时间测试上,并没有很大差别。