分类 技术分享 下的文章

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)篇。

COM接口实现的随意的一点小记录

1、所有的COM接口的vtbl前三项都是一样的。
COM接口和C++编译器生成的抽象基类的内存接口是相同的。
vtbl的初始位置保存着IUnknown的御三家的地址,take an example:

在VS里面的例子,实例化IWebBrowser2之后,查看其地址的数据:

>dd 0x00821ae8
0x00821AE8  63362618(vtbl) 005d25a8 005d87fc abababab  
0x00821AF8  abababab       feeefeee 00000000 00000000  
0x00821B08  45b71a23       00001234 008237f8 008200c4  
0x00821B18  feeefeee       feeefeee feeefeee feeefeee  

f2.png

很容易就能找到御三家。

示例:

#include <ObjBase.h>
#include <iostream>

static IID IID_IA = {0x12345678, 0x1234, 0x1234, {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}};

interface IA : IUnknown
{
    virtual void __stdcall foo() = 0;
};

class CA : public IA
{
public:
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    virtual ULONG __stdcall AddRef(){std::cout<<"addref\n"<<std::endl; return 0;}
    virtual ULONG __stdcall Release(){std::cout<<"release\n"<<std::endl; return 0;}
    virtual void __stdcall foo()
    {
        std::cout << "a" << std::endl;
    }
};

HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
{
    if (iid == IID_IUnknown || iid == IID_IA)
    {
        *ppv = static_cast<IA*>(this);
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef();
    return S_OK;
}

IUnknown* CreateInstance()
{
    IUnknown* pI = static_cast<IA*>(new CA);
    pI->AddRef();
    return pI;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr;
    IUnknown* pIUnknown = CreateInstance();

    IA* pIA = NULL;
    hr = pIUnknown->QueryInterface(IID_IA, (void**)&pIA);
    if (SUCCEEDED(hr))
    {
        pIA->foo();

    printf("%08x %08x %08x",*(DWORD*)pIA, 
        *((DWORD*)pIA+1), 
        *((DWORD*)pIA+2));
    }   

    return 0;
}

输出:
00a07834 fdfdfdfd abababab

其实事实上pIA此时内存也就这一个东西了,拿出VS的dd证明一下代码没错:

>dd 0x007c8c38
0x007C8C38  00a07834(vtbl) fdfdfdfd abababab abababab  
0x007C8C48  00000000 00000000 18fb7b76 1c00dcbf  
0x007C8C58  007c8c18 007c4810 0f9a22b0 0000041d  
0x007C8C68  00000010 00000002 000000ba fdfdfdfd 

00a07834解引用后,前三项为QueryInterface、AddRef、Release的地址。

跟这关系不大的一个,在添加了私有成员之后:

class CA : public IA
{
public:
………………
private:
    ULONG m_SomeLong;
};

vtbl后面才会多出数据来,以前只是看书知道这事儿,这回算是实践了吧:

{,,testInterface.exe}(*(CA*){*}pIA).m_SomeLong  3452816845  unsigned long

>dd 0x00888c38
0x00888C38  00377834 *cdcdcdcd* fdfdfdfd abababab  
0x00888C48  abababab feeefeee 00000000 00000000  
0x00888C58  0d743d6b 1c0082e0 00888c18 00884810  
0x00888C68  0fbf22b0 0000041d 00000010 00000002  

(备注: 3452816845 (dec) == 0xcdcdcdcd (hex))

2、IDispatch接口中GetIDsOfNames根据提供的函数名称返回DISPID,Invoke则内部实现了一组按索引访问的函数,有点像是vtbl。

春节14天小长假,该补的还是全部补上吧

去年最后悔的就是把一堆没看完的书打着“放假我能看完”的名号带回家里,回北京以后想看书的时候一摸啥都没有,这14天好好的补完吧。我可能会尽量先补上ie的那几篇文章的坑,开坑的时候,坑挖的太大了,趁着过节给填上。

fswebcam 实时监控系统

f1.png

cubietruck搭出来的,不管有没有用。。每张图片~200k,每天监控下来的数据差不多有1.7GB,正好有个空闲的SSD,120G空间足以监控10天,其实监控三个月都不为过。。

然后给它开启samba和vnc,顺便backup还把图片传到网站的某个文件夹里面,网站空间很小,所以我只能15分钟传一张,每天产生20M数据,10天200M,看起来还可以的样子。

其实晚上拍的照片一片黑 每张也就17k左右

可执行程序的变量存储到底有什么规律呢?

测试一下:
Windows x86 (vs2010)、 x64(gcc)
Linux ARM (gcc)

code:

unsigned long g_A = 0x11223344;
unsigned long g_B;

unsigned long function()
{
    static unsigned long s_A = 0xAABBCCDD;
    static unsigned long s_B;
    unsigned long A = 0x55667788;
    s_A ++;
    s_B = s_A;
    return A;
}

int main(int argc, char** argv) 
{
    unsigned long B = 0x99999999;
    B = function();
    return 0;
}

1、编译选项:Windows, x86, 优化全关闭(vs2010)

Dump of file E:\users\blastts\documents\visual studio 2010\Projects\testSection\Release\testSection.exe

PE signature found

File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
             14C machine (x86)
               5 number of sections
        54D6CDF6 time date stamp Sun Feb 08 10:46:14 2015
               0 file pointer to symbol table
               0 number of symbols
              E0 size of optional header
             102 characteristics
                   Executable
                   32 bit word machine

SECTION HEADER #1
   .text name
     82A virtual size
    1000 virtual address (00401000 to 00401829)
     A00 size of raw data
     400 file pointer to raw data (00000400 to 00000DFF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         Execute Read

SECTION HEADER #2
  .rdata name
     5C6 virtual size
    2000 virtual address (00402000 to 004025C5)
     600 size of raw data
     E00 file pointer to raw data (00000E00 to 000013FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         Read Only

SECTION HEADER #3
   .data name
     394 virtual size
    3000 virtual address (00403000 to 00403393)
     200 size of raw data
    1400 file pointer to raw data (00001400 to 000015FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         Read Write

SECTION HEADER #4
   .rsrc name
     1B4 virtual size
    4000 virtual address (00404000 to 004041B3)
     200 size of raw data
    1600 file pointer to raw data (00001600 to 000017FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         Read Only

SECTION HEADER #5
  .reloc name
     18E virtual size
    5000 virtual address (00405000 to 0040518D)
     200 size of raw data
    1800 file pointer to raw data (00001800 to 000019FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
42000040 flags
         Initialized Data
         Discardable
         Read Only

  Summary

        1000 .data
        1000 .rdata
        1000 .reloc
        1000 .rsrc
        1000 .text

不出意外的话,全局变量unsigned long g_A = 0x11223344;,静态变量static unsigned long s_A = 0xAABBCCDD;应该都是存在一起的。

SECTION HEADER #3
   .data name
RAW DATA #3
  00403000: 44 33 22 11 DD CC BB AA 

而局部变量则又是在一起的

SECTION HEADER #1
   .text name
RAW DATA #1
  00401000: 55 8B EC 51 C7 45 FC **88 77 66 55** A1 04 30 40 00  U.имQ?Eи╣.wfU?.0@.
  00401010: 83 C0 01 A3 04 30 40 00 8B 0D 04 30 40 00 89 0D  .ид.бъ.0@....0@...
  00401020: 24 30 40 00 8B 45 FC 8B E5 5D C3 CC CC CC CC CC  $0@..Eи╣.?]?имимимимим
  00401030: 55 8B EC 51 C7 45 FC **99 99 99 99**

既然.text是Execute Read,那么必然有:

01021030          testSection!main (int, char **)

0:000> u testSection!main
testSection!main [e:\users\blastts\documents\visual studio 2010\projects\testsection\testsection\testsection.cpp @ 20]:
01021030 55              push    ebp
01021031 8bec            mov     ebp,esp
01021033 51              push    ecx
01021034 c745fc99999999  mov     dword ptr [ebp-4],99999999h
0102103b e8c0ffffff      call    testSection!function (01021000)
01021040 8945fc          mov     dword ptr [ebp-4],eax
01021043 33c0            xor     eax,eax
01021045 8be5            mov     esp,ebp

而没初值的s_B,(忘记关ASLR了,很容易就能算出RAW,所以先不管它)

0102101e 890d24300201    mov     dword ptr [testSection!s_B (01023024)],ecx


0:000> !dh 0x1020000
OPTIONAL HEADER VALUES
     10B magic #
   10.00 linker version
     A00 size of code
     C00 size of initialized data
       0 size of uninitialized data
    12D7 address of entry point
    1000 base of code
         ----- new -----
**01020000 image base**

SECTION HEADER #3
   .data name
     394 virtual size
    3000 virtual address
     200 size of raw data
    1400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

可见是位于.data中的。因为vs生成的这东西没有.bss,所以不完全像是他们所说,至少vs编译的c++程序,未初始化的全局变量不一定在.bss中。不过其实多个.bss也还不错,可能是没开优化的缘故?

其它的倒是很符合。全局变量在.data,局部变量跟着代码一起在.text中。

2、编译选项:Windows, x64, 优化全关闭(gcc 4.1)
跟vs的大同小异,只不过gcc生成的节是真的很多,挑一些重点发。

首先,全局变量,静态变量,跟之前一样。

SECTION HEADER #2
   .data name
     100 virtual size
    8000 virtual address (0000000000408000 to 00000000004080FF)
     200 size of raw data
    6E00 file pointer to raw data (00006E00 to 00006FFF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0500040 flags
         Initialized Data
         RESERVED - UNKNOWN
         RESERVED - UNKNOWN
         Read Write

RAW DATA #2
  0000000000408000: 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  0000000000408010: 44 33 22 11 DD CC BB AA

局部变量、函数也是一样

SECTION HEADER #1
   .text name
    67D0 virtual size
    1000 virtual address (0000000000401000 to 00000000004077CF)
    6800 size of raw data
     600 file pointer to raw data (00000600 to 00006DFF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60500020 flags
         Code
         RESERVED - UNKNOWN
         RESERVED - UNKNOWN
         Execute Read

RAW DATA #1
  0000000000401500: 55 48 89 E5 48 83 EC 10 C7 45 FC 88 77 66 55 

剩余的,我看到了bss的存在!

SECTION HEADER #6
    .bss name
    1400 virtual size
    D000 virtual address (000000000040C000 to 000000000040D3FF)
       0 size of raw data
       0 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0600080 flags
         Uninitialized Data
         RESERVED - UNKNOWN
         RESERVED - UNKNOWN
         Read Write

先看看使用这个之前没初始化过的变量的地方:

0:002> u image00000000_00400000+0x1533
image00000000_00400000+0x1533:
00000000`00401533 8b05db7a0000    mov     eax,dword ptr [image00000000_00400000+0x9014 (00000000`00409014)]
00000000`00401539 83c001          add     eax,1
00000000`0040153c 8905d27a0000    mov     dword ptr [image00000000_00400000+0x9014 (00000000`00409014)],eax
00000000`00401542 8b05cc7a0000    mov     eax,dword ptr [image00000000_00400000+0x9014 (00000000`00409014)]
00000000`00401548 8905f6ba0000    mov     dword ptr [image00000000_00400000+0xd044 (00000000`0040d044)],eax

这个倒是很符合:

static unsigned long s_B;
0:002> ?[poi[image00000000_00400000+0xd044]]
Evaluate expression: 0 = 00000000`00000000

static unsigned long s_A = 0xAABBCCDD;
0:002> ?[poi[image00000000_00400000+0x9014]]
Evaluate expression: 2864434397 = 00000000`aabbccdd

看吧,文件中预留的是0字节,只在启动后才从这里初始化一片0内存给它用,本意是减少(……节的描述都不止4字节了,浪费了更多,其实我觉得VS这里的做法反而是对的)文件大小,但是实际上如果没初始化的全局变量或者静态变量本身就不多的话,我觉得还不如并到.data节呢。

3、Linux (ARM) ,编译器GCC,无优化。

pi@BLASTN2 ~/projects/testSection/testSections/bin/Release :( $ objdump -h testSections 

testSections:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000019  00008134  00008134  00000134  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  00008150  00008150  00000150  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  00008170  00008170  00000170  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .hash         00000028  00008194  00008194  00000194  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .gnu.hash     00000024  000081bc  000081bc  000001bc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynsym       00000050  000081e0  000081e0  000001e0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .dynstr       00000077  00008230  00008230  00000230  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version  0000000a  000082a8  000082a8  000002a8  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .gnu.version_r 00000020  000082b4  000082b4  000002b4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.dyn      00000008  000082d4  000082d4  000002d4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .rel.plt      00000018  000082dc  000082dc  000002dc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 11 .init         0000000a  000082f4  000082f4  000002f4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt          0000003c  00008300  00008300  00000300  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         00000134  0000833c  0000833c  0000033c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         00000006  00008470  00008470  00000470  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       00000004  00008478  00008478  00000478  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .ARM.exidx    00000008  0000847c  0000847c  0000047c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .eh_frame     00000004  00008484  00008484  00000484  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 18 .init_array   00000004  00010488  00010488  00000488  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .fini_array   00000004  0001048c  0001048c  0000048c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .jcr          00000004  00010490  00010490  00000490  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .dynamic      00000108  00010494  00010494  00000494  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got          0000001c  0001059c  0001059c  0000059c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000010  000105b8  000105b8  000005b8  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          0000000c  000105c8  000105c8  000005c8  2**2
                  ALLOC
 25 .comment      0000001d  00000000  00000000  000005c8  2**0
                  CONTENTS, READONLY
 26 .ARM.attributes 00000033  00000000  00000000  000005e5  2**0
                  CONTENTS, READONLY

可以看到也是有.bss节的,而且大小为0,看FileOffset可知.bss的起始大小是0x5c8,.comment也是0x5c8,所以.bss是一个字都没有占到,

        0    2    4    6      8    a    c    e
00005b0 8300 0000 0000 0000 | 0000 0000 0000 0000
00005c0 3344 1122 ccdd aabb | 4347 3a43 2820 6544

可见,它也是满足这个规律,也即全局变量放.data,没赋值的全局变量放.bss(只是占虚拟内存而已),代码和局部变量放.text。

对这俩静态变量的操作也是类似:
f1.png
f2.png