IE的FREAK对策(a)

对IE来说,FREAK的就是在握手交换密钥的时候,服务器把高强度的密钥丢弃,转而使用512位RSA密钥和浏览器(客户端)协商的过程。针对这个问题,Firefox和Chrome都能正常处理,可惜IE、Safari和Opera(Linux)都是一贯的死相,该出问题的还是出问题。另外,Mozilla的这个问题很久前就修复了。要说为啥有这个问题,还是怪老美年轻的时候想着监控全球搞出来的一堆恶心玩意儿。

IE自己用的是Schannel库,从Wireshark抓包上看,明显出现了(服务器)server hello - server key exchange 的过程,在firefox下这个过程被直接拒掉了server hello - alert - connection fail,IE倒是来者不拒完成了协商,同时将密钥降级成RSA(512位交换)。

以下是在CVE Test上IE最终的结果:TLS 1.1, AES (128 位加密 (高)); RSA(512 位交换)

现在512位的估计一台机器跑几天就出来了,所以这个东西明显是不安全的。但是怎么修啊?微软给出来了Security Advisor,但是明显不靠谱,他也不标明是客户端用的还是服务器端用的,浪费了我两个小时的测试,明显它这招不能用在客户端上,而且受限于微软的gpedit.msc输入框最多只能输入1023字节,它每个算法的名字还特别长,所以微软干脆就把……把他的支持加密方式给删了一部分。

然后现在首要的就是获得这么一个信息: 我怎么能方便快捷的知道现在IE连接是什么情况?明显ie的属性-连接可以告诉我们这一切,但是这个怎么获取呢?开始我天真的以为可以用bp user32!SetWindowTextA/W的方式来获取,可是出人意料的是,属性窗口里面居然也是一个Internet Explorer_Server。(这一点你从IE11的属性就可以发现,因为它的“证书”按钮明显和“确定”按钮的样式不一样)

好吧,现在我们有一个很脏的方式:先弹出属性,然后找到窗口句柄,获取到里面Internet Explorer_Server的句柄,然后获取它的IHTMLDocument2对象,然后获取它的innerHTML。 看起来就很复杂,先实现一下。

这时,还是得用上bp user32!SetWindowTextA/W的方法,首先获取到设置连接的位置:

Breakpoint 1 hit
eax=00000002 ebx=02683ae0 ecx=00000000 edx=00000007 esi=0012b9b0 edi=000500be
eip=77d2960e esp=0012b894 ebp=0012bb7c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040246
USER32!SetWindowTextW:
77d2960e 8bff            mov     edi,edi
0:000> du poi(esp+0x8)
0012b9b0  "属性"
0:000> kvn
 # ChildEBP RetAddr  Args to Child              
00 0012b890 7718ac1b 000500be 0012b9b0 00000000 USER32!SetWindowTextW (FPO: [Non-Fpo])
01 0012bb7c 7718afcd 000500be 02683ae0 000600bc comctl32!_SetTitle+0xf9 (FPO: [Non-Fpo])
02 0012bf3c 7718c695 000500be 02683ae0 02683ae0 comctl32!InitPropSheetDlg+0x80 (FPO: [Non-Fpo])
03 0012bfac 77d18734 000500be 00000110 000600bc comctl32!PropSheetDlgProc+0x4cb (FPO: [Non-Fpo])
04 0012bfd8 77d2413c 7718c1ca 000500be 00000110 USER32!InternalCallWinProc+0x28
05 0012c044 77d23b30 0014bab8 7718c1ca 000500be USER32!UserCallDlgProcCheckWow+0xf0 (FPO: [Non-Fpo])
06 0012c08c 77d23d5c 00000000 00000110 000600bc USER32!DefDlgProcWorker+0xa8 (FPO: [Non-Fpo])
07 0012c0a8 77d18734 000500be 00000110 000600bc USER32!DefDlgProcW+0x22 (FPO: [Non-Fpo])
08 0012c0d4 77d18816 77d23d3a 000500be 00000110 USER32!InternalCallWinProc+0x28
09 0012c13c 77d2927b 0014bab8 77d23d3a 000500be USER32!UserCallWinProcCheckWow+0x150 (FPO: [Non-Fpo])
0a 0012c178 77d2651a 00619fd8 00603980 000600bc USER32!SendMessageWorker+0x4a5 (FPO: [Non-Fpo])
0b 0012c230 77d2683e 00000000 00619fd8 000000e0 USER32!InternalCreateDialog+0x9df (FPO: [Non-Fpo])
0c 0012c254 77d3f03a 77180000 001f4760 00030126 USER32!CreateDialogIndirectParamAorW+0x33 (FPO: [Non-Fpo])
0d 0012c274 7720b9a1 77180000 001f4760 00030126 USER32!CreateDialogIndirectParamW+0x1b (FPO: [Non-Fpo])
0e 0012c2bc 7718ccc7 77180000 001f4760 00030126 comctl32!SHFusionCreateDialogIndirectParam+0x36 (FPO: [Non-Fpo])
0f 0012c320 7718cf39 00030126 77d290b4 0012c398 comctl32!_RealPropertySheet+0x242 (FPO: [Non-Fpo])
10 0012c338 7718cf54 0012c398 00000000 0012c38c comctl32!_PropertySheet+0x146 (FPO: [Non-Fpo])
11 0012c348 77157047 0012c398 77d290b4 00000000 comctl32!PropertySheetW+0xf (FPO: [Non-Fpo])
12 0012c38c 77157d50 00000000 00000034 00000501 OLEAUT32!COlePropertySheet::DoModal+0x2a (FPO: [Non-Fpo])
13 0012c3ec 7e5a6806 0012c414 7e25689c 7e558bc0 OLEAUT32!OleCreatePropertyFrameIndirect+0x28 (FPO: [Non-Fpo])
14 0012c494 7e5a6adc 002dc857 00000000 00000000 SHDOCVW!CDocHostUIHandler::ShowPropertysheetDialog+0x1f9 (FPO: [Non-Fpo])
15 0012c4a8 7e58bf11 00151808 7e25688c 0000000a SHDOCVW!CDocHostUIHandler::Exec+0xab (FPO: [Non-Fpo])
16 0012d74c 7e57ff44 0017782c 7e25688c 0000000a SHDOCVW!CDocObjectHost::OnExec+0xae2 (FPO: [Non-Fpo])
17 0012d77c 7e355e07 00000000 7e25688c 0000000a SHDOCVW!CDocObjectHost::Exec+0x101 (FPO: [Non-Fpo])
18 0012d8b4 7e315ec5 01f407f0 0004010a 00000000 mshtml!CDoc::ShowPropertyDialog+0x10b (FPO: [Non-Fpo])
19 0012dc4c 7e29bba5 00000000 7e55890c 0000001c mshtml!CDoc::ExecHelper+0x252 (FPO: [Non-Fpo])
1a 0012dc6c 7e5a4960 001c4af8 7e55890c 0000001c mshtml!CDoc::Exec+0x1e (FPO: [Non-Fpo])
1b 0012dd58 7e5aa6b7 00151800 0000001c 0012ddb4 SHDOCVW!CDocHostUIHandler::ShowContextMenu+0x436 (FPO: [Non-Fpo])
1c 0012dd84 7e395765 00177810 00000000 0012ddb4 SHDOCVW!CDocObjectHost::ShowContextMenu+0x88 (FPO: [Non-Fpo])
1d 0012ddc8 7e36cf18 0000017b 0000013a 00000000 mshtml!CDoc::ShowContextMenu+0xee (FPO: [Non-Fpo])
1e 0012dde0 7e36cee2 0000017b 0000013a 00000000 mshtml!CElement::ShowContextMenu+0x1b (FPO: [Non-Fpo])
1f 0012deec 7e330067 0000013a 0000013a 00000000 mshtml!CElement::OnContextMenu+0xb0 (FPO: [Non-Fpo])
20 0012dfa4 7e2f6e72 02061f00 0012e1c8 0205ddc0 mshtml!CLayout::HandleMessage+0x2b9 (FPO: [Non-Fpo])
21 0012e088 7e2f69c9 02061f00 0012e1c8 0205de40 mshtml!CFlowLayout::HandleMessage+0x64f (FPO: [Non-Fpo])
22 0012e0a4 7e2f6647 0205ddc0 0012e1c8 0205de40 mshtml!CElement::HandleMessage+0x90 (FPO: [Non-Fpo])
23 0012e120 7e2e8cfa 0205de40 0205de40 00000000 mshtml!CDoc::PumpMessage+0x93c (FPO: [Non-Fpo])
24 0012e26c 7e2e7c78 0000007b 00000000 013a017b mshtml!CDoc::OnMouseMessage+0x3b6 (FPO: [Non-Fpo])
25 0012e38c 7e278a1a 00000000 0000007b 0004010a mshtml!CDoc::OnWindowMessage+0xc43 (FPO: [Non-Fpo])
26 0012e4c4 77d18734 0004010a 0000007b 0004010a mshtml!CServer::WndProc+0x9f (FPO: [Non-Fpo])
27 0012e4f0 77d18816 7e2789a4 0004010a 0000007b USER32!InternalCallWinProc+0x28
28 0012e558 77d2bf15 00000000 7e2789a4 0004010a USER32!UserCallWinProcCheckWow+0x150 (FPO: [Non-Fpo])
29 0012e5ac 77d28dd9 0004010a 00000205 00000000 USER32!RealDefWindowProcWorker+0x107a (FPO: [Non-Fpo])
2a 0012e5c8 77d28d77 0004010a 00000205 00000000 USER32!RealDefWindowProcW+0x47 (FPO: [Non-Fpo])
2b 0012e610 7e2f7668 0004010a 00000205 00000000 USER32!DefWindowProcW+0x72 (FPO: [Non-Fpo])
2c 0012e634 7e2f66b1 00000205 00000000 00bf0145 mshtml!CServer::OnDefWindowMessage+0x68 (FPO: [Non-Fpo])
2d 0012e6b8 7e2e8cfa 0205de40 00000000 00000000 mshtml!CDoc::PumpMessage+0xa5c (FPO: [Non-Fpo])
2e 0012e804 7e2e7c78 00000205 00000000 00bf0145 mshtml!CDoc::OnMouseMessage+0x3b6 (FPO: [Non-Fpo])
2f 0012e924 7e278a1a 00000000 00000205 00000000 mshtml!CDoc::OnWindowMessage+0xc43 (FPO: [Non-Fpo])
30 0012ea5c 77d18734 0004010a 00000205 00000000 mshtml!CServer::WndProc+0x9f (FPO: [Non-Fpo])
31 0012ea88 77d18816 7e2789a4 0004010a 00000205 USER32!InternalCallWinProc+0x28
32 0012eaf0 77d189cd 00000000 7e2789a4 0004010a USER32!UserCallWinProcCheckWow+0x150 (FPO: [Non-Fpo])
33 0012eb50 77d18a10 0012eb90 00000000 0012eb78 USER32!DispatchMessageWorker+0x306 (FPO: [Non-Fpo])
34 0012eb60 75f0d875 0012eb90 00000000 00152178 USER32!DispatchMessageW+0xf (FPO: [Non-Fpo])
35 0012eb78 75f15218 0012eb90 0012ee98 00000000 BROWSEUI!TimedDispatchMessage+0x33 (FPO: [Non-Fpo])
36 0012edd8 75f15389 00151f10 0012ee98 00151f10 BROWSEUI!BrowserThreadProc+0x336 (FPO: [Non-Fpo])
37 0012ee6c 75f15655 00151f10 00151f10 00000000 BROWSEUI!BrowserProtectedThreadProc+0x50 (FPO: [Non-Fpo])
38 0012fef0 7e5d8d7a 00151f10 00000000 00000000 BROWSEUI!SHOpenFolderWindow+0x22c (FPO: [Non-Fpo])
39 0012ff10 00402372 001423ba 00000001 030f0d4e SHDOCVW!IEWinMain+0x129 (FPO: [Non-Fpo])
3a 0012ff60 00402444 00400000 00000000 001423ba iexplore!WinMainT+0x2de (FPO: [Non-Fpo])
3b 0012ffc0 7c817067 030f0d4e 0007d880 7ffd9000 iexplore!_ModuleEntry+0x99 (FPO: [Non-Fpo])
3c 0012fff0 00000000 00402451 00000000 78746341 kernel32!BaseProcessStart+0x23 (FPO: [Non-Fpo])

让咱先看看0x12-0x26这几层:

12 0012c38c 77157d50 00000000 00000034 00000501 OLEAUT32!COlePropertySheet::DoModal+0x2a (FPO: [Non-Fpo])
13 0012c3ec 7e5a6806 0012c414 7e25689c 7e558bc0 OLEAUT32!OleCreatePropertyFrameIndirect+0x28 (FPO: [Non-Fpo])
14 0012c494 7e5a6adc 002dc857 00000000 00000000 SHDOCVW!CDocHostUIHandler::ShowPropertysheetDialog+0x1f9 (FPO: [Non-Fpo])
15 0012c4a8 7e58bf11 00151808 7e25688c 0000000a SHDOCVW!CDocHostUIHandler::Exec+0xab (FPO: [Non-Fpo])
16 0012d74c 7e57ff44 0017782c 7e25688c 0000000a SHDOCVW!CDocObjectHost::OnExec+0xae2 (FPO: [Non-Fpo])
17 0012d77c 7e355e07 00000000 7e25688c 0000000a SHDOCVW!CDocObjectHost::Exec+0x101 (FPO: [Non-Fpo])
18 0012d8b4 7e315ec5 01f407f0 0004010a 00000000 mshtml!CDoc::ShowPropertyDialog+0x10b (FPO: [Non-Fpo])
19 0012dc4c 7e29bba5 00000000 7e55890c 0000001c mshtml!CDoc::ExecHelper+0x252 (FPO: [Non-Fpo])
1a 0012dc6c 7e5a4960 001c4af8 7e55890c 0000001c mshtml!CDoc::Exec+0x1e (FPO: [Non-Fpo])
1b 0012dd58 7e5aa6b7 00151800 0000001c 0012ddb4 SHDOCVW!CDocHostUIHandler::ShowContextMenu+0x436 (FPO: [Non-Fpo])
1c 0012dd84 7e395765 00177810 00000000 0012ddb4 SHDOCVW!CDocObjectHost::ShowContextMenu+0x88 (FPO: [Non-Fpo])
1d 0012ddc8 7e36cf18 0000017b 0000013a 00000000 mshtml!CDoc::ShowContextMenu+0xee (FPO: [Non-Fpo])
1e 0012dde0 7e36cee2 0000017b 0000013a 00000000 mshtml!CElement::ShowContextMenu+0x1b (FPO: [Non-Fpo])
1f 0012deec 7e330067 0000013a 0000013a 00000000 mshtml!CElement::OnContextMenu+0xb0 (FPO: [Non-Fpo])
20 0012dfa4 7e2f6e72 02061f00 0012e1c8 0205ddc0 mshtml!CLayout::HandleMessage+0x2b9 (FPO: [Non-Fpo])
21 0012e088 7e2f69c9 02061f00 0012e1c8 0205de40 mshtml!CFlowLayout::HandleMessage+0x64f (FPO: [Non-Fpo])
22 0012e0a4 7e2f6647 0205ddc0 0012e1c8 0205de40 mshtml!CElement::HandleMessage+0x90 (FPO: [Non-Fpo])
23 0012e120 7e2e8cfa 0205de40 0205de40 00000000 mshtml!CDoc::PumpMessage+0x93c (FPO: [Non-Fpo])
24 0012e26c 7e2e7c78 0000007b 00000000 013a017b mshtml!CDoc::OnMouseMessage+0x3b6 (FPO: [Non-Fpo])
25 0012e38c 7e278a1a 00000000 0000007b 0004010a mshtml!CDoc::OnWindowMessage+0xc43 (FPO: [Non-Fpo])
26 0012e4c4 77d18734 0004010a 0000007b 0004010a mshtml!CServer::WndProc+0x9f (FPO: [Non-Fpo])

0x26 - 0x1b是接收到用户点击右键,然后弹出右键菜单的过程。 0x1a - 0x14是弹出属性框的过程,0x13 - 0x12则是属性框的操作了。所以,我们需要的是什么大家也都知道了。

shdocvw,这个dll的作用是:
f1.png

只是为了加个水印。

好吧,差不多就是这样的结构(这个是IE5/6的,看图片就知道有年头了)
f2.png

shdocvw从虚拟机里面拖出来,IDA看一下这个函数的原型是什么:
CDocHostUIHandler::ShowPropertysheetDialog(tagVARIANT *,tagVARIANT *,ulong)

好吧,其实事实上就是:

HRESULT
CDocHostUIHandler::ShowPropertysheetDialog(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut, DWORD)
{

// must match order of PropertysheetEnum
static const SExpandoInfo s_aPropertysheetExpandos[] =
{
    {OLESTR("propertysheetPunks"),  VT_SAFEARRAY}
};

    HRESULT             hr;
    HWND                hwnd = NULL;
    HWND                hwndParent;
    IUnknown          * punk = NULL;
    OLECMD              olecmd = {0, 0};
    int                 cUnk = 0;
    IUnknown * HUGEP  * apUnk = NULL;
    OCPFIPARAMS         ocpfiparams;
    CAUUID              ca = { 0, 0 };
    RECT                rc = {0, 0, 0, 0};
    RECT                rcDesktop = {0, 0, 0, 0};
    SIZE                pixelOffset;
    SIZE                metricOffset = {0, 0};

    IHTMLEventObj     * pEventObj = NULL;
    const int           cExpandos = ARRAYSIZE(s_aPropertysheetExpandos);
    VARIANT             aVariant[cExpandos];
    DISPID              aDispid[cExpandos];
    SAFEARRAY         * psafearray = NULL;

    ASSERT(pvarargIn && V_VT(pvarargIn) == VT_UNKNOWN && V_UNKNOWN(pvarargIn));
    if (!pvarargIn || (V_VT(pvarargIn) != VT_UNKNOWN) || !V_UNKNOWN(pvarargIn))
    {
        hr = E_INVALIDARG;
        goto Cleanup;
    }

    // get the hwnd
    punk = V_UNKNOWN(pvarargIn);
    hr = GetHwndFromUnknown(punk, &hwnd);
    if (hr)
        goto Cleanup;

    // get the SafeArray expando from the event obj
    hr = GetEventFromUnknown(punk, &pEventObj);
    if (hr)
        goto Cleanup;

    hr = GetParamsFromEvent(
            pEventObj,
            cExpandos,
            aDispid,
            aVariant,
            s_aPropertysheetExpandos);
    if (hr)
        goto Cleanup;
    psafearray = V_ARRAY(&aVariant[PropertysheetPunks]);

    // verify array dimensions
    if (SafeArrayGetDim(psafearray) != 1)
    {
        hr = E_INVALIDARG;
        goto Cleanup;
    }

    // get array size, adding one to 0-based size
    hr = SafeArrayGetUBound(psafearray, 1, (long*)&cUnk);
    if (hr)
        goto Cleanup;
    cUnk++;

    if (cUnk)
    {
        // get pointer to vector
        hr = SafeArrayAccessData(psafearray, (void HUGEP* FAR*)&apUnk);
        if (hr)
            goto Cleanup;
    }
    else
    {
        cUnk = 1;
        apUnk = &punk;
    }

    // Compute pages to load
    hr = THR(GetCommonPages(cUnk, apUnk, &ca));
    if (hr)
        goto Cleanup;

    //  compute top-level parent
    while ( hwndParent = GetParent(hwnd) )
        hwnd = hwndParent;

    // BUGBUG dialog box is not centered on screen
    // the ocpfi seems to be ignoring the x, y values in ocpfiparams
    // Compute offset to center of screen
    GetWindowRect(GetDesktopWindow(), &rcDesktop);
    GetWindowRect(hwnd, &rc);
    pixelOffset.cx = (rcDesktop.right - rcDesktop.left)/2 - rc.left;
    pixelOffset.cy = (rcDesktop.bottom - rcDesktop.top)/2 - rc.top;
    AtlPixelToHiMetric(&pixelOffset, &metricOffset);

    memset(&ocpfiparams, 0, sizeof(ocpfiparams));

    ocpfiparams.cbStructSize = sizeof(ocpfiparams);
    ocpfiparams.hWndOwner = hwnd;
    ocpfiparams.x = metricOffset.cx;
    ocpfiparams.y = metricOffset.cy;
    ocpfiparams.lpszCaption = NULL;
    ocpfiparams.cObjects = cUnk;
    ocpfiparams.lplpUnk = apUnk;
    ocpfiparams.cPages = ca.cElems;
    ocpfiparams.lpPages = ca.pElems;
    ocpfiparams.lcid = GetUserDefaultLCID();
    ocpfiparams.dispidInitialProperty = DISPID_UNKNOWN;

    // OleCreatePropertyFrameIndirect throws its own dialog on error,
    // so we don't want to display that twice
    THR(OleCreatePropertyFrameIndirect(&ocpfiparams));
    hr = S_OK;

Cleanup:
    if (ca.cElems)
        CoTaskMemFree(ca.pElems);

    if (psafearray && apUnk)
        SafeArrayUnaccessData(psafearray);

    if (pvarargOut)
        VariantInit(pvarargOut);

    for (int i=0; i<cExpandos; i++)
        VariantClear(&aVariant[i]);

    ATOMICRELEASE(pEventObj);

    return hr;
}

读一下代码,看看它做了什么:
1、pvarargIn的作用仅仅是让它获取一个hwnd。

punk = V_UNKNOWN(pvarargIn);
hr = GetHwndFromUnknown(punk, &hwnd);

2、从pEventObj中获取属性页的各个参数

hr = GetParamsFromEvent(
        pEventObj,
        cExpandos,
        aDispid,
        aVariant,
        s_aPropertysheetExpandos);

3、从这些参数中获取Common Page,待会儿就能知道Common Pages是什么

 hr = THR(GetCommonPages(cUnk, apUnk, &ca));
if (hr)
    goto Cleanup;

4、计算窗口所需参数,弹出窗口

THR(OleCreatePropertyFrameIndirect(&ocpfiparams));

现在让我们看看重要的GetCommonPages,它的作用是获取页面的属性。

HRESULT CDocHostUIHandler::GetCommonPages(int cUnk, IUnknown **apUnk, CAUUID *pca)
{
    HRESULT                hr;
    int                    i;
    UINT                   iScan, iFill, iCompare;
    BOOL                   fFirst = TRUE;
    CAUUID                 caCurrent;
    IUnknown *             pUnk;
    ISpecifyPropertyPages *pSPP;

    pca->cElems = 0;
    pca->pElems = NULL;

    for (i = 0; i < cUnk; i++)
    {
        pUnk = apUnk[i];
        ASSERT(pUnk);

        hr = THR(pUnk->QueryInterface(
                IID_ISpecifyPropertyPages,
                (void **)&pSPP));
        if (hr)
            goto Cleanup;

         hr = THR(pSPP->GetPages(fFirst ? pca : &caCurrent));
         ATOMICRELEASE(pSPP);
         if (hr)
             goto Cleanup;

         if (fFirst)
             continue;

         // keep only the common pages
         else
         {
             for (iScan = 0, iFill = 0; iScan < pca->cElems; iScan++)
             {
                 for (iCompare = 0; iCompare < caCurrent.cElems; iCompare++)
                 {
                     if (caCurrent.pElems[iCompare] == pca->pElems[iScan])
                         break;
                 }
                 if (iCompare != caCurrent.cElems)
                 {
                     pca->pElems[iFill++] = pca->pElems[iScan];

                 }
             }
             pca->cElems = iFill;
             CoTaskMemFree(caCurrent.pElems);
         }
    }


Cleanup:
    return hr;
}

可见,apUnk很可能就是当前页面的IUnknown,所以,也就是说我们完全可能从当前页面获取到这些属性!让我们在MSDN上查询一下IID_ISpecifyPropertyPages,

ISpecifyPropertyPages interface

Indicates that an object supports property pages. OLE property pages enable an object to display its properties in a tabbed dialog box known as a property sheet. An end user can then view and change the object's properties. An object can display its property pages independent of its client, or the client can manage the display of property pages from a number of contained objects in a single property sheet. Property pages also provide a means for notifying a client of changes in an object's properties.

Minimum supported client
    Windows 2000 Professional [desktop apps only]

Minimum supported server
    Windows 2000 Server [desktop apps only]

Header
    OCIdl.h

IDL
    OCIdl.idl

IID
     IID_ISpecifyPropertyPages is defined as B196B28B-BAB4-101A-B69C-00AA00341D07

这样就好办得多了,至少我们知道了如下信息:

1、属性框确实是COM对象的属性,而且不是在IE中画的,是通过ISpecifyPropertyPages接口弹出来的东西。
2、我们从IUnknown中就可能能检索出所有的属性。

have a try,后续试验在(b)篇。

标签:none

添加新评论

captcha
请输入验证码