雨过天晴 发表于 2017-6-1 13:34:02

Win7 x64动态开启DSE

本人研究这些东西没有人一起讨论 不支持研究的方向对不对 如果有误还请指出 我的联系方式:ilovexibayaever@gmail.com


加载驱动 返回0xC0000428


IDA搜索立即数0xC0000428
地址                   Function                           指令                  
----                   --------                           ----                  
.text:00000001400EE0F0 MiResolveTransitionFault         mov   eax, 0C0000428h
.text:00000001400EE10F MiResolveTransitionFault         mov   eax, 0C0000428h
.text:00000001400EE3E3 MiResolveProtoPteFault             mov   eax, 0C0000428h
PAGE:00000001402E89E4SeValidateImageHeader            mov   eax, 0C0000428h
PAGE:00000001403A5168SeValidateImageData                mov   eax, 0C0000428h
PAGE:00000001404F6F37PipCallDriverAddDeviceQueryRoutine cmp   eax, 0C0000428h
PAGE:00000001404F6F8DPipCallDriverAddDeviceQueryRoutine cmp   ebx, 0C0000428h
PAGE:00000001404F716FPipCallDriverAddDeviceQueryRoutine cmp   ebx, 0C0000428h

发现有这么几个地方
看SeValidateImageHeader

int __fastcall SeValidateImageHeader(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5)
{
PVOID v5; // rax@2
int result; // eax@2


if ( g_CiEnabled )
{
    if ( g_CiCallbacks )
      result = g_CiCallbacks(a1, a2, a3, a4);//我们可以去看看它干了什么 这个 其实就是CiValidateImageHeader
    else
      result = 0xC0000428;//这个情况是因为是安全模式
}
else
{
    v5 = ExAllocatePoolWithTag(PagedPool, 1ui64, 0x68506553u);
    *(_QWORD *)a5 = v5;
    result = v5 == 0i64 ? 0xC0000017 : 0;
}
return result;
}


很明显一个全局变量在影响这个判断 g_CiEnabled
看看那个地方在操作g_CiEnabled 发现是SepInitializeCodeIntegrity

__int64 SepInitializeCodeIntegrity()
{
signed __int64 v0; // rbx@1
signed int v1; // edi@2
__int64 v2; // rax@2
bool v3; // zf@6


v0 = 0i64;
if ( InitIsWinPEMode )
{
    g_CiEnabled = 0;//如果是安全模式就为0
}
else
{
    g_CiEnabled = 1;
    v1 = 6;
    g_CiCallbacks = 0i64;
    qword_1402256A8 = 0i64;
    qword_1402256B0 = 0i64;
    v2 = *(_QWORD *)&KeLoaderBlock_0;
    if ( *(_QWORD *)&KeLoaderBlock_0 )
    {
      if ( *(_QWORD *)(*(_QWORD *)&KeLoaderBlock_0 + 152i64) )
      {
      if ( SepIsOptionPresent(*(_QWORD *)(*(_QWORD *)&KeLoaderBlock_0 + 152i64), "DISABLE_INTEGRITY_CHECKS") )
          v1 = 0;
      v3 = SepIsOptionPresent(*(_QWORD *)(*(_QWORD *)&KeLoaderBlock_0 + 152i64), "TESTSIGNING") == 0;
      v2 = *(_QWORD *)&KeLoaderBlock_0;
      if ( !v3 )
          v1 |= 8u;
      }
      if ( v2 )
      v0 = v2 + 48;
    }
    LODWORD(v0) = CiInitialize_0((unsigned int)v1, v0, &g_CiCallbacks);
}
return (unsigned int)v0;
}


这跟我们研究下面没有太大的关系 因为如果在这里path已经迟了 这个函数在系统启动的时候就运行了 当然如果要静态过DSE的话就在这里path
根据SeValidateImageHeader的反汇编可以看到 只需要对g_CiEnabled就行置0即可
在看看SeValidateImageData

int SeValidateImageData()
{
int result; // eax@1


result = 0;
if ( g_CiEnabled )
{
    if ( qword_1402256A8 )
      result = qword_1402256A8();
    else
      result = 0xC0000428;
}
return result;
}


这里也做了判断
这个函数其实没多大的作用qword_1402256A8其实就是CiValidateImageData的地址指针可在在windbg中查看 这个函数在ci.dll中
其它出现mov xxx,0xC0000428我在windbg双机调试中没有出现(加载驱动的时候没有断下)
还有一种方法不对g_CiEnabled处理 下面就调用了
result = g_CiCallbacks(a1, a2, a3, a4);
这个就是CiValidateImageHeader 我们去看看

__int64 __fastcall CiValidateImageHeader(__int64 a1, __int64 a2, unsigned int a3, unsigned int a4, PVOID *a5)
{
signed int v5; // ebp@1
unsigned int v6; // er12@1
__int64 v7; // r14@1
unsigned int v8; // ebx@1
__int64 v9; // r13@1
bool v10; // zf@1
int v11; // er15@1
unsigned int v12; // edi@1
int v13; // eax@2
int v14; // eax@4
__int64 v16; // r9@29
__int64 v17; // r8@29
__int64 v18; // rdx@29
__int64 v19; // rcx@29
int v20; // eax@30
signed int v21; // eax@43
__int64 v22; // rdx@46
int v23; // er11@55
__int64 v24; // rdx@65
__int64 v25; // rdx@76
PVOID v26; // rax@82
__int16 v27; // @1
__int16 v28; // @1
PVOID P; // @1
unsigned int v30; // @1
unsigned int v31; // @2
int v32; // @1
char Dst; // @1


v5 = 0;
v6 = a3;
v7 = a1;
LOBYTE(v8) = a4;
v9 = a2;
v30 = a4;
v32 = 0;
memset(&Dst, 0, 0x14ui64);
v10 = *a5 == 0i64;
v27 = 0;
v28 = 0;
P = 0i64;
v11 = v10;
v12 = CiInitializePhase2();
if ( (v12 & 0x80000000) == 0 )
{
    v13 = CipFixImageType(v9, &v31, &v30);
    v8 = v30;
    v12 = v13;
    if ( v13 >= 0 )
    {
      if ( v30 & 2 )
      {
LABEL_4:
      v14 = 1;
      goto LABEL_12;
      }
      if ( *a5 && v30 & 5 )
      {
      v14 = 0;
      }
      else
      {
      if ( v30 & 4 || g_CiOptions & 4 && _bittest(&v8, 0x1Fu) )
          goto LABEL_4;
      v14 = v30 & 1;
      }
LABEL_12:
      v12 = 0;
      if ( !v14 )
      goto LABEL_81;
      if ( v30 & 5 )
      {
      if ( v31 > v6 )
      {
          v12 = 0xC0000023;
LABEL_16:
          if ( *a5 && v11 )
          {
            ExFreePoolWithTag(*a5, 0);
            *a5 = 0i64;
          }
          goto LABEL_19;
      }
      v6 = v31;
      }
      v16 = v30;
      v17 = v6;
      v18 = v9;
      v19 = v7;
      if ( !(v30 & 5) )
      {
      v20 = CipValidatePageHash(v7, v9, v6);
      if ( v20 >= 0 || v8 & 2 )
          goto LABEL_34;
      v16 = v8;
      v17 = v6;
      v18 = v9;
      v19 = v7;
      }
      v20 = CipValidateFileHash(v19, v18, v17, v16);
LABEL_34:
      v12 = CipCallPeauth((unsigned int)v20);
      if ( (v12 & 0x80000000) == 0
      || g_CiOptions & 4 && _bittest(&v8, 0x1Fu)
      || g_CiOptions & 2 && v8 & 1
      || v8 & 4
      || v8 & 2 )
      {
      v5 = 0;
      }
      else
      {
      v5 = 0;
      if ( v8 & 1 )
      {
          v21 = P ? 0 : CipQueryFileName(v7, &v27);
          if ( v21 >= 0 )
          {
            v22 = (__int64)CiRevokedDriverLoaded;
            if ( v12 != 0xC0000603 )
            v22 = (__int64)CiUnsignedDriverLoaded;
            CiLogFileEvent(&v27, v22);
            CiAudit(&v27, 5038i64);
          }
      }
      v12 = 0;
      }
      goto LABEL_52;
    }
}
LABEL_52:
if ( v12 == 0xC0000428 || v12 == 0xC0000603 )
{
    if ( P )
      v23 = 0;
    else
      v23 = CipQueryFileName(v7, &v27);
    if ( !(v8 & 2)
      && !(v8 & 4)
      && !(g_CiOptions & 0x10)
      && (_BYTE)KdDebuggerEnabled == 1
      && !(_BYTE)KdDebuggerNotPresent )
    {
      if ( v23 >= 0 && !(unsigned __int8)PsIsCurrentThreadPrefetching() )
      {
      if ( v12 == 0xC0000603 )
      {
          v24 = (__int64)CiRevokedDriverLoadedInDebugger;
      }
      else
      {
          v24 = (__int64)CiImagePageHashNotFoundDebuggerAttached;
          if ( v8 & 1 )
            v24 = (__int64)CiImageFileHashNotFoundDebuggerAttached;
      }
      CiLogFileEvent(&v27, v24);
      CiAudit(&v27, (v8 & 5) != 0 ? 5038 : 6281);
      }
      if ( !(unsigned __int8)PsIsCurrentThreadPrefetching() && g_CiOptions & 1 )
      {
      DbgPrint("Code Integrity violation:%d\n", 446i64);
      __debugbreak();
      }
      v12 = 0;
      goto LABEL_81;
    }
    if ( v23 >= 0 && !(unsigned __int8)PsIsCurrentThreadPrefetching() )
    {
      if ( v12 == 0xC0000603 )
      {
      v25 = (__int64)CiRevokedDriverNotLoaded;
      }
      else
      {
      v25 = (__int64)CiImagePageHashNotFound;
      if ( v8 & 5 )
          v25 = (__int64)CiImageFileHashNotFound;
      }
      CiLogFileEvent(&v27, v25);
      CiAudit(&v27, (v8 & 5) != 0 ? 5038 : 6281);
    }
}
if ( (signed int)v12 < v5 )
    goto LABEL_16;
LABEL_81:
if ( !*a5 )
{
    v12 = 0;
    v26 = ExAllocatePoolWithTag(PagedPool, 0x70ui64, 0x63734943u);
    *a5 = v26;
    if ( v26 )
    {
      memset(v26, 0, 0x70ui64);
      *(_DWORD *)*a5 = 0;
      *((_DWORD *)*a5 + 1) = 0;
      *((_DWORD *)*a5 + 2) = 0;
      *((_DWORD *)*a5 + 3) = 0;
      *((_DWORD *)*a5 + 20) = 32772;
      *((_DWORD *)*a5 + 22) = 0;
    }
    else
    {
      v12 = 0xC0000017;
    }
}
LABEL_19:
if ( P )
    ExFreePoolWithTag(P, 0);
MincryptFreePolicyInfo(&v32);
if ( (v12 & 0x80000000) != 0
    && v12 != 0xC0000023
    && !(unsigned __int8)PsIsCurrentThreadPrefetching()
    && v12 == 0xC0000428
    && g_CiOptions & 1 )
{
    DbgPrint("Code Integrity violation:%d\n", 518i64);
    __debugbreak();
}
return v12;
}


这里还是直接找立即数吧 看看ci.dll是怎么 返回0xC0000428的
地址                  Function                                    指令                                 
----                  --------                                    ----                                 
PAGE:000007FF404CA15B CiInitializePhase2                            cmp   dword ptr , 0C0000428h
PAGE:000007FF404CA350 CipInitialize                                 cmp   r12d, 0C0000428h               
PAGE:000007FF404CA3F4 CipInitialize                                 mov   edi, 0C0000428h               
PAGE:000007FF404CAEED CiValidateImageHeader                         cmp   edi, 0C0000428h               
PAGE:000007FF404CB063 CiValidateImageHeader                         cmp   edi, 0C0000428h               
PAGE:000007FF404CB560 CiValidateImageData                           mov   ebx, 0C0000428h               
PAGE:000007FF404CB826 CipCallPeauth                                 mov   eax, 0C0000428h               
PAGE:000007FF404CB958 CipFindFileHash                               mov   ebx, 0C0000428h               
......         

找了半天 CiValidateImageHeader 决定加载驱动的代码是   
v20 = CipValidateFileHash(v19, v18, v17, v16);

LABEL_34:
      v12 = CipCallPeauth((unsigned int)v20);
      if ( (v12 & 0x80000000) == 0
      || g_CiOptions & 4 && _bittest(&v8, 0x1Fu)
      || g_CiOptions & 2 && v8 & 1
      || v8 & 4
      || v8 & 2 )
      {
      v5 = 0;
      }
      else //必须要else
      {
      v5 = 0;
      if ( v8 & 1 )//如果是驱动
      {
          v21 = P ? 0 : CipQueryFileName(v7, &v27);
          if ( v21 >= 0 )
          {
            v22 = (__int64)CiRevokedDriverLoaded;
            if ( v12 != 0xC0000603 )
            v22 = (__int64)CiUnsignedDriverLoaded;
            CiLogFileEvent(&v27, v22);
            CiAudit(&v27, 5038i64);
          }
      }
      v12 = 0;
      }
      goto LABEL_52;
    }
   

g_CiOptions 默认是4 | 2 = 6 如果是6这就成立了 所以必须不为6 为0即可




另外一种解释


内核驱动初始化时调用SepInitializeCodeIntegrity
如果不是安全模式就走下面
注意下面这个v1 它决定了是否关闭DSE或测试模式

__int64 SepInitializeCodeIntegrity()
{
__int64 v0; // rbx@1
signed int v1; // edi@2
__int64 v2; // rax@2
bool v3; // zf@6


v0 = 0i64;
if ( InitIsWinPEMode )
{
    g_CiEnabled = 0;
}
else
{
    g_CiEnabled = 1;
    v1 = 6;
    g_CiCallbacks = 0i64;
    qword_1402256A8 = 0i64;
    qword_1402256B0 = 0i64;
    v2 = *(_QWORD *)&KeLoaderBlock_0;
    if ( *(_QWORD *)&KeLoaderBlock_0 )
    {
      if ( *(_QWORD *)(*(_QWORD *)&KeLoaderBlock_0 + 152i64) )
      {
      if ( (unsigned int)SepIsOptionPresent(
                           *(const char **)(*(_QWORD *)&KeLoaderBlock_0 + 152i64),
                           "DISABLE_INTEGRITY_CHECKS") )
          v1 = 0;
      v3 = (unsigned int)SepIsOptionPresent(*(const char **)(*(_QWORD *)&KeLoaderBlock_0 + 152i64), "TESTSIGNING") == 0;
      v2 = *(_QWORD *)&KeLoaderBlock_0;
      if ( !v3 )
          v1 |= 8u;
      }
      if ( v2 )
      v0 = v2 + 48;
    }
    LODWORD(v0) = CiInitialize_0((unsigned int)v1, v0, (__int64)&g_CiCallbacks);
}
return (unsigned int)v0;
}


看CiInitialize_0 sub函数

int __fastcall CiInitialize_0(__int64 a1, __int64 a2, __int64 a3)
{
return CiInitialize(a1, a2, a3);
}


看CiInitialize 注意第一个参数a1
.idata:00000001401AD370 ; Imports from CI.dll
.idata:00000001401AD370 ;
.idata:00000001401AD370               extrn __imp_CiInitialize:qword

去初始化ci.dll中的CiInitialize去看看 还是注意a1参数

__int64 __fastcall CipInitialize(int a1, __int64 a2, __int64 a3)
{
__int64 v3; // rbp@1
__int64 v4; // rsi@1
__int64 v5; // rax@1
PVOID *v6; // rbx@1
unsigned int v7; // edi@1
__int64 v8; // rbx@2
int v9; // er12@3
int v10; // er14@3
PVOID v11; // rax@6
__int64 v12; // r13@6
__int64 v13; // rax@7
__int64 v14; // rdx@13
__int64 v15; // rax@13
PVOID v16; // rcx@14
__int64 v18; // @1


v18 = a3;
v3 = a3;
v4 = a2;
g_CiOptions = a1;//给了g_CiOptions
LODWORD(v5) = PsGetCurrentProcess();
//............
// ............
//大量代码
return v7;
}


来看看加载驱动是会调用哪些函数
.text:00000001400EE0F0 MiResolveTransitionFault         mov   eax, 0C0000428h
.text:00000001400EE10F MiResolveTransitionFault         mov   eax, 0C0000428h
.text:00000001400EE3E3 MiResolveProtoPteFault             mov   eax, 0C0000428h
PAGE:00000001402E89E4SeValidateImageHeader            mov   eax, 0C0000428h
PAGE:00000001403A5168SeValidateImageData                mov   eax, 0C0000428h
PAGE:00000001404F6F37PipCallDriverAddDeviceQueryRoutine cmp   eax, 0C0000428h
PAGE:00000001404F6F8DPipCallDriverAddDeviceQueryRoutine cmp   ebx, 0C0000428h
PAGE:00000001404F716FPipCallDriverAddDeviceQueryRoutine cmp   ebx, 0C0000428h

去看看SeValidateImageHeader

int __fastcall SeValidateImageHeader(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5)
{
PVOID v5; // rax@2
int result; // eax@2


if ( g_CiEnabled )//第一个可以patch点
{
    if ( g_CiCallbacks )
      result = g_CiCallbacks(a1, a2, a3, a4);这里调用了CiValidateImageHeader
    else
      result = 0xC0000428;
}
else
{
    v5 = ExAllocatePoolWithTag(PagedPool, 1ui64, 0x68506553u);
    *(_QWORD *)a5 = v5;
    result = v5 == 0i64 ? 0xC0000017 : 0;
}
return result;
}


去看看CiValidateImageHeader 这个应该不是这么执行的 我会在研究研究的

__int64 __fastcall CiValidateImageHeader(__int64 a1, __int64 a2, unsigned int a3, unsigned int a4, PVOID *a5)
{
signed int v5; // ebp@1
unsigned int v6; // er12@1
__int64 v7; // r14@1
int v8; // ebx@1
__int64 v9; // r13@1
bool v10; // zf@1
int v11; // er15@1
unsigned int v12; // edi@1
int v13; // eax@2
int v14; // eax@4
unsigned int v16; // eax@30
signed int v17; // eax@43
__int64 v18; // rdx@46
int v19; // er11@55
__int64 v20; // rdx@65
__int64 v21; // rdx@76
PVOID v22; // rax@82
__int16 v23; // @1
__int16 v24; // @1
PVOID P; // @1
int v26; // @1
unsigned int v27; // @2
int v28; // @1
char Dst; // @1
char v30; // @30


v5 = 0;
v6 = a3;
v7 = a1;
LOBYTE(v8) = a4;
v9 = a2;
v26 = a4;
v28 = 0;
memset(&Dst, 0, 0x14ui64);
v10 = *a5 == 0i64;
v23 = 0;
v24 = 0;
P = 0i64;
v11 = v10;
v12 = CiInitializePhase2();
if ( (v12 & 0x80000000) != 0 )
    goto LABEL_52;
v13 = CipFixImageType(v9, &v27, &v26);
v8 = v26;
v12 = v13;
if ( v13 < 0 )
    goto LABEL_52;
if ( !(v26 & 2) )
{
    if ( *a5 && v26 & 5 )
    {
      v14 = 0;//这里为什么?
      goto LABEL_12;
    }
    if ( !(v26 & 4) && (!(g_CiOptions & 4) || !_bittest((const unsigned int *)&v8, 0x1Fu)) )
    {
      v14 = v26 & 1;                            // //默认 为 4 | 2 = 6 成立 我们这里要不成立 才执行到这个地方
      goto LABEL_12;
    }
}
v14 = 1;
LABEL_12:
v12 = 0;
if ( !v14 )
    goto LABEL_81;                              // //直接加载驱动
    .....
}


后面的再说
参考资料:
6330510 windows x64 vista以上系统代码完整性校验分析
//
__int64 CiInitializePhase2()
{
int v5; // esi@6
signed int v6; // ebx@9
__int64 v7; // rcx@22
__int64 v8; // rax@22
PVOID v9; // rdi@23
struct _KTIMER *v10; // rax@30
struct _KTIMER *v11; // rbp@30
char v12; // al@34
signed __int64 v13; // rbx@39
__int16 v14; // @11
__int16 v15; // @11
__int64 v16; // @11


if ( g_EtwEventHandle )
    return 0i64;
__asm { lock bts cs:g_CiInitLock, 0 }
if ( _CF )
    ExfAcquirePushLockExclusive(&g_CiInitLock);
if ( !g_EtwEventHandle )
{
    v5 = CipCheckConfigOptions();
    if ( v5 >= 0 )
    {
      v5 = EtwRegister(CodeIntegrityEventProviderId, 0i64, 0i64, &g_EtwEventHandle);
      if ( v5 >= 0 )
      {
      v6 = 2;
      if ( g_CiOptions & 8 )
          v6 = 6;
      v14 = 90;
      v15 = 92;
      v16 = (__int64)L"\\SystemRoot\\System32\\CodeIntegrity\\driver.stl";
      if ( MinCrypKCallbacks && CipMinCrypK_CloseFile )
      {
          g_MincrypkCallbacks = (const struct _MINCRYPTK_CALLBACKS *const )&MinCrypKCallbacks;
          ExInitializeResourceLite(&g_CatalogListLock);
          v5 = I_LoadRevocationList(&v14, (unsigned int)v6, &g_RevocationList);
      }
      else
      {
          v5 = 0xC000000D;
      }
      if ( v5 >= 0 )
      {
          PESetInitialState();
          while ( 1 )
          {
            v9 = g_BootDriverList;            // //在初始化的时候赋值发现初始化函数第一个参数为为SepInitializeCodeIntegrity(内核初始化函数)对g_ciEn判断 后面就是一个调用ci 初始化函数的sub函数 sub函数跳到这个函数来
                                                // 初始化函数的第一个参数决定了是否可以关闭DSE 默认为6 (如果是双机调试的话是不走条路的)我们现在说的是正常系统 如果为0则关闭DSE
                                                // 如果为8 则为测试模式
            if ( g_BootDriverList == &g_BootDriverList )
            break;
            if ( *((_DWORD *)g_BootDriverList + 8) == 0xC0000428 )
            {
            CiLogFileEvent((__int64)((char *)g_BootDriverList + 16), (__int64)CiImageFileHashNotFound);// 没有找到签名 或无效的签名
            CiAudit((__int64)((char *)v9 + 16), 0x13AE);
            }
            else if ( *((_DWORD *)g_BootDriverList + 8) >= 0 && *((_BYTE *)g_BootDriverList + 36) & 1 )
            {
            CiLogFileEvent((__int64)((char *)g_BootDriverList + 16), (__int64)CiNoEmbeddedSignatureDriverLoaded);// 这个地方出错说明内核调试器的问题 资料:https://technet.microsoft.com/en-us/library/dd363944(WS.10).aspx
            }
            v7 = *(_QWORD *)v9;
            v8 = *((_QWORD *)v9 + 1);
            *(_QWORD *)v8 = *(_QWORD *)v9;
            *(_QWORD *)(v7 + 8) = v8;
            ExFreePoolWithTag(v9, 0);
          }
          if ( (_DWORD)InitSafeBootMode
            || !g_BootCacheDelay
            || !(g_CiOptions & 0x10) && (_BYTE)KdDebuggerEnabled == 1 && !(_BYTE)KdDebuggerNotPresent
            || g_CiOptions & 8 )
            goto LABEL_34;
          v10 = (struct _KTIMER *)ExAllocatePoolWithTag(0, 0xA0ui64, 0x63734943u);
          v11 = v10;
          if ( v10 )
          {
            v13 = -600000000i64 * (unsigned int)g_BootCacheDelay;
            KeInitializeTimer(v10);
            KeInitializeDpc((PRKDPC)&v11, CipPostBootTimerRoutine, v11);
            *(_QWORD *)&v11.Header.Type = 0i64;
            v11.Header.WaitListHead.Blink = (struct _LIST_ENTRY *)CipPostBootWorker;
            v11.DueTime.QuadPart = (ULONGLONG)v11;
            KeSetTimer(v11, (LARGE_INTEGER)v13, (PKDPC)&v11);
            goto LABEL_34;
          }
          v5 = 0xC0000017;
      }
      }
    }
    MinCrypK_Cleanup();
    if ( g_EtwEventHandle )
    {
      EtwUnregister();
      g_EtwEventHandle = 0i64;
    }
    goto LABEL_34;
}
v5 = 0;
LABEL_34:
v12 = _InterlockedExchangeAdd8(&g_CiInitLock, 0xFFFFFFFFFFFFFFFFui64);
if ( v12 & 2 )
{
    if ( !(v12 & 4) )
      ExfTryToWakePushLock(&g_CiInitLock);
}
return (unsigned int)v5;
}
页: [1]
查看完整版本: Win7 x64动态开启DSE