65.9K
CodeProject 正在变化。 阅读更多。
Home

密码破解器

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.95/5 (23投票s)

2006年8月26日

CPOL

2分钟阅读

viewsIcon

733221

downloadIcon

28825

一个简单的 BHO,用于检索用户 ID 和密码。

Screenshot - logininfo.jpg

背景

您是否使用过任何密码管理器和自动表单填充软件? AI RoboForm 是业内历史最悠久、最好的。最新版本的 Firefox 和 Netscape 也通过 Passcard 支持这一点。想象一下开发一个可以检索用户 ID 和密码的软件!为了实现上述目标,我需要开发一个 Internet Explorer 插件或 BHO。关于如何使用 ATL 开发 BHO 的文章有很多,因此我将跳过这一步,专注于如何处理事件和访问 DOM 以检索用户 ID 和密码。脑海中浮现的基本问题是我们如何检测给定的页面是否是登录页面。如果您能找到答案,您就可以完成剩下的工作。经过一些实验,我发现我们应该仅在页面至少有一个类型为 "password" 的输入字段时才尝试检索页面的密码。另一件重要的事情是,大多数登录页面只有一个类型为 <INPUT TYPE=TEXT> 的对象,并且只有一个类型为 <INPUT TYPE=PASWWORD> 的对象。

如何检索用户 ID 和密码

当浏览器完成页面下载后,它会发送一个事件 DISPID_DOCUMENTCOMPLETE。在这里,我们应该检查页面是否是登录页面。要检测这一点,您必须搜索文档对象中的所有元素,并找出是否存在任何类型为 "password" 的元素。如果找到一个,我们几乎可以肯定这是一个登录页面。

连接到 <FORM> 事件

//
CComPtr<IDISPATCH> spDisp; 
HRESULT hr = m_pWebBrowser2->get_Document(&spDisp);
if (SUCCEEDED(hr) && spDisp)
{ 
    // If this is not an HTML document (e.g., it's a Word doc or a PDF), don't sink.
    CComQIPtr<IHTMLDOCUMENT2 &IID_IHTMLDocument2> spHTML(spDisp);
     if (spHTML)
     { 
         /*there can be frames in HTML page enumerate each of frameset or iframe
              and find out if any of them contain a login page*/
           EnumFrames(spHTML);  
    }
}

void CIeLoginHelper::EnumFrames(CComPtr<IHTMLDocument2>& spDocument) 
{    
    
    CComPtr<IIHTMLDocument2> spDocument2;
    CComPtr<IIOleContainer> pContainer;
    // Get the container
    HRESULT hr = spDocument->QueryInterface(IID_IOleContainer,
                (void**)&pContainer);
    
    CComPtr<IIEnumUnknown>pEnumerator;
    // Get an enumerator for the frames
    hr = pContainer->EnumObjects(OLECONTF_EMBEDDINGS, &pEnumerator);
    IUnknown* pUnk;
    ULONG uFetched;

    // Enumerate and refresh all the frames
    BOOL bFrameFound = FALSE;
    for (UINT nIndex = 0; 
            S_OK == pEnumerator->Next(1, &pUnk, &uFetched);
                nIndex++)
    {
        CComPtr<IIWebBrowser2> pBrowser;
        hr = pUnk->QueryInterface(IID_IWebBrowser2, 
                (void**)&pBrowser);
        pUnk->Release();
        if (SUCCEEDED(hr))
        {
            CComPtr<IIDispatch> spDisp;
            pBrowser->get_Document(&spDisp);
            CComQIPtr<IHTMLDocument2, &
                         IID_IHTMLDocument2> spDocument2(spDisp);
            //Now recursivley browse through all of
                        //IHTMLWindow2 in a doc                    
            RecurseWindows(spDocument2);
            bFrameFound = TRUE;

        }
    }
    if(!bFrameFound || !m_bFoungLoginPage)
    {

        CComPtr<IIHTMLElementCollection> spFrmCol;
        CComPtr<IIHTMLElementCollection> spElmntCol;
        /*multipe <FORM> object can be in a page,
                 connect to each one them
        You never know which one contains uid and pwd fields
        */
        hr = spDocument->get_forms(&spFrmCol);
        // get element collection from page to check 
                if a page is a lgoin page
        hr = spDocument->get_all(&spElmntCol);
        if(IsLoginPage(spElmntCol))
                   EnableEvents(spFrmCol);    
    }        
}

如果页面有密码字段,那么您将对获取用户 ID 和密码感兴趣。

BOOL  CIeLoginHelper::IsLoginPage(CComPtr<IHTMLElementCollection>&spElemColl)
{
    if(spElemColl == NULL)
        return m_bFoungLoginPage;
    _variant_t varIdx(0L, VT_I4);
    long lCount = 0;
    HRESULT hr  = S_OK;
    hr = spElemColl->get_length (&lCount);
    if (SUCCEEDED(hr))
    {
        for(long lIndex = 0; lIndex <lCount; lIndex++ ) 
        { 
            varIdx=lIndex;
                    CComPtr<IDispatch>spElemDisp;
            hr = spElemColl->item(varIdx, varIdx, &spElemDisp);
            if (SUCCEEDED(hr))
            {
                CComPtr<IHTMLInputElement> spElem;
                hr = spElemDisp->QueryInterface(IID_IHTMLInputElement, (void**)&spElem);
                if (SUCCEEDED(hr))
                {
                    _bstr_t bsType;
                    hr = spElem->get_type(&bsType.GetBSTR());
                    if(SUCCEEDED(hr) && bsType.operator==(L"password"))
                    {
                        m_bFoungLoginPage = true;
                    }
                }
            }
            if(m_bFoungLoginPage)
                return m_bFoungLoginPage;
        }
    }
    return m_bFoungLoginPage;
}

一旦确定了目标页面,您所要做的就是遍历表单集合并连接到表单元素的事件,如下所示

_variant_t varIdx(0L, VT_I4);
long lCount = 0;
HRESULT hr  = S_OK;
hr = pElemColl->get_length (&lCount);
if (SUCCEEDED(hr))
{
    for(long lIndex = 0; lIndex <lCount; lIndex++ ) 
    { 
           varIdx=lIndex;
           hr=pElemColl->item(varIdx, varIdx, &pElemDisp);

        if (SUCCEEDED(hr))
        {
            hr = pElemDisp->QueryInterface(IID_IHTMLFormElement, (void**)&pElem);

            if (SUCCEEDED(hr))
            {
                // Obtained a form object.
                IConnectionPointContainer* pConPtContainer = NULL;
                IConnectionPoint* pConPt = NULL;    
                // Check that this is a connectable object.
                hr = pElem->QueryInterface(IID_IConnectionPointContainer,
                    (void**)&pConPtContainer);
                if (SUCCEEDED(hr))
                {
                    // Find the connection point.
                    hr = pConPtContainer->FindConnectionPoint(
                        DIID_HTMLFormElementEvents2, &pConPt);

                    if (SUCCEEDED(hr))
                    {
                        // Advise the connection point.
                        // pUnk is the IUnknown interface pointer for your event sink
                        hr = pConPt->Advise((IDispatch*)this, &m_dwBrowserCookie);
                        pConPt->Release();
                    }
                }
                pElem->Release();
            }
            pElemDisp->Release();
        }
    }
}

捕获用户 ID 和密码

数据捕获的时机很重要。最佳时机是在提交表单时。表单可以通过多种方式提交

以上任何对象都将触发事件 DISPID_HTMLFORMELEMENTEVENTS2_ONSUBMIT

在这种情况下,我们必须处理

  1. 当类型为 <INPUT TYPE=submit><INPUT TYPE=image><BUTTON TYPE=submit> 的对象被鼠标左键单击,或按下 Enter 键或空格键时。
  2. 通过在对象的鼠标或键盘事件处理程序中调用 form.submit
    1. DISPID_HTMLELEMENTEVENTS2_ONKEYPRESS
    2. DISPID_HTMLELEMENTEVENTS2_ONCLICK

一旦您知道何时捕获数据,剩下的就非常简单了。您所要做的就是遍历元素集合并检索用户 ID 和密码。

_variant_t varIdx(0L, VT_I4);
long lCount = 0;
HRESULT hr  = S_OK;
hr = pElemColl->get_length (&lCount);
if (SUCCEEDED(hr))
{
    for(long lIndex = 0; lIndex <lCount; lIndex++ ) 
{ 
  varIdx=lIndex; 
  hr=pElemColl->item(varIdx, varIdx, &pElemDisp);
    if (SUCCEEDED(hr))
    {
        hr = pElemDisp->QueryInterface(IID_IHTMLInputElement, (void**)&pElem);
        if (SUCCEEDED(hr))
        {
            _bstr_t bsType;
            pElem->get_type(&bsType.GetBSTR());
            if(bsType.operator ==(L"text"))
            {
                pElem->get_value(&bsUserId.GetBSTR());
            }
            else if(bsType.operator==(L"password"))
            {
                pElem->get_value(&bsPassword.GetBSTR());
            }
            pElem->Release();
        }

        pElemDisp->Release();
    }
    if(bsUserId.GetBSTR() && bsPassword.GetBSTR() && 
      ( bsUserId.operator!=(L"") && bsPassword.operator!=(L"") ) )
    {
        return;
    }            

    }
}

历史

  • V1.0.0.1 - 第一个版本。
  • V1.0.1.1 - 上传于 2006 年 8 月 29 日。此版本枚举页面中的框架以找出任何框架是否具有登录页面。
© . All rights reserved.