分享

阿里旺旺分析系列一:实时获取阿里旺旺聊天消息,实现旺旺客服机器人

 vcand3d 2012-12-26

  目前网络上有为数不多的几款客服机器人。比如某某旺旺机器人。实现的大概机制是获取淘宝旺旺收到的聊天消息。从本地数据库中搜索答案。然后再自动或者手动回复。

本文详细讲述如何分析阿里旺旺和某某旺旺机器人软件,以达到实时获取旺旺聊天消息的目的。并给出具体的实现代码。

关键字:阿里旺旺 阿里旺旺聊天消息 旺旺机器人 客服机器人

联系方式:crazydigua # gmail.com (#替换为@)

QQ:5738626(注明)

Blog: crazydigua.blog.51cto.com

分析步骤

1。 分析阿里旺旺

      1.1 打开旺旺的聊天窗口,使用Spy4Win查看,很容易就可以看出,旺旺的聊天历史是使用的内嵌IE(WebBrowser)实现的。

           image 

    1.2 使用Spy4Win的IE页面分析工具。分析页面内容。

image

        发现页面代码结构如下:

<DIV id=content style="OVERFLOW-Y: auto; HEIGHT: 192px" onscroll=OnContentScroll();><DIV id=History style="DISPLAY: none"> </DIV>
<DIV id=SeparationLine style="MARGIN-TOP: 5px; DISPLAY: none; MARGIN-BOTTOM: 10px; MARGIN-RIGHT: 20%; BORDER-BOTTOM: #cccccc 1px solid"></DIV>
<DIV id=Position1 style="DISPLAY: none"></DIV>
<DIV id=Position2 style="DISPLAY: none"></DIV>
<DIV id=Position3 style="DISPLAY: none"></DIV>
<DIV class=Msg id=MsgElement SendID="cntaobaochatplus">
<DIV class=MsgHead id=MsgHead><SPAN></SPAN><SPAN class=SenderName id=SenderName>chatplus</SPAN><SPAN> </SPAN><SPAN id=SenderSite></SPAN><SPAN id=MsgHeadRight><SPAN id=MsgTime>(15:44:18): </SPAN></SPAN></DIV>
<DIV class=InnerContent id=MsgContent>
<DIV class=MsgContent id=Msg_{02595DD4-47D3-46C1-8C11-E02491B83A3E} msgId="{02595DD4-47D3-46C1-8C11-E02491B83A3E}" sendId="cntaobaochatplus"><FONT style="FONT-SIZE: 10pt" face=宋体 color=#000000>test</FONT></DIV></DIV></DIV></DIV>

从代码中可以看出。最后的一个DIV中包含MSGID,发送用户的ID, 消息内容。

      因此只要在收到旺旺消息时,获取消息事件,并从聊天历史中读取出最后的消息即可。

2。 分析某旺旺机器人

      2.1 运行某旺旺机器人,发现实现方式是独立的程序,当收到任意旺旺消息时,程序都能截获。

      2.2 使用PEExplorer打开该主程序:

        检查导入的DLL:

image

           延迟导入的DLL:

image

         可以看出该程序使用OLEAcc.dll的

          AccessibleObjectFromWindow

          LresultFromObject

          来获取旺旺聊天窗口中的IE指针。

          从导入的DLL来看,使用的都是系统的DLL,未使用进程植入的方法。

       2.3 进一步分析改程序具体使用了那些函数。

           运行程序,使用SysInternals 的工具 Process Explorer打开进程,找出该程序进程中的字符串。

           image

           保存后搜索“Hook” 发现该程序使用了SetWindowsHookEx函数。因为该程序未进行进程植入,所以可以判断该程序使用了SetWindowsHookEx进行了挂钩。打开MSDN,查看该函数的说明:发现该函数支持HOOK以下类型:

WH_CALLWNDPROC ,WH_CALLWNDPROCRET, WH_CBT ,WH_DEBUG ,,WH_FOREGROUNDIDLE ,WH_GETMESSAGE ,WH_JOURNALPLAYBACK,WH_JOURNALRECORD,

WH_KEYBOARD,WH_KEYBOARD_LL,WH_MOUSE,WH_MOUSE_LL,WH_MSGFILTER,WH_SHELL,WH_SYSMSGFILTER

           简单分析可以看出,HOOK的应该是WH_SHELL类型。因为该HOOK类型支持类似窗口可见,窗口激活等消息。而每当收到旺旺聊天消息是,聊天窗口均会激活。

HSHELL_ACTIVATESHELLWINDOW

The shell should activate its main window.
HSHELL_WINDOWACTIVATEDThe activation has changed to a different top-level, unowned window. 其他参考MSDN。

                分析过程基本到此,可以看出程序启动时,创建系统的钩子,获取Shell的相关消息,再对消息进行判断。发现是旺旺收到的消息的话,就对旺旺的聊天窗口获取IE指针,再从IE里获取聊天的相关信息即可实现了。

3。 创建程序具体再进行分析。

     3.1 使用VS2005+MFC创建一个对话框程序(因为使用的都是标准的WindowsAPI,所以本方法和语言无关,Delphi,VB,C#,C++等均可轻松实现)

     3.2 在OnInitDialog中实现挂钩,RegisterShellHookWindow 和SetWindowsHookEx,WH_SHELL实现的目的是一样的.

          HWND Hwnd = GetSafeHwnd();

          msgShellHook = RegisterWindowMessage(L"SHELLHOOK");

          RegisterShellHookWindow( Hwnd );

          lpPrevWndProc = SetWindowLong( Hwnd , GWL_WNDPROC, long(MyWindowProc) );

         

          static LRESULT CALLBACK MyWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam,  LPARAM lParam  )
          {

               ATLTRACE("hwnd:%d,uMsg:%d,wParam:%ld,lParam:%ld\r\n",hwnd,uMsg,wParam,lParam); 
               return CallWindowProc((WNDPROC)lpPrevWndProc, hwnd, uMsg, wParam, lParam);

          }

          将Hook到的所有消息输出。

     3.3 分析Shell消息:

          聊天窗口未打开时收到聊天消息时的输出内容:

hwnd:855962,uMsg:49194,wParam:6,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:6,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:1,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:6,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:1125,wParam:4176056,lParam:0
hwnd:855962,uMsg:273,wParam:67109864,lParam:921390
hwnd:855962,uMsg:307,wParam:-268363765,lParam:921390
hwnd:855962,uMsg:273,wParam:50332648,lParam:921390
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:6,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0

          聊天窗口已打开,收到聊天消息时的输出内容:

hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:1125,wParam:4176344,lParam:0
hwnd:855962,uMsg:273,wParam:67109864,lParam:921390
hwnd:855962,uMsg:307,wParam:-2113853412,lParam:921390
hwnd:855962,uMsg:273,wParam:50332648,lParam:921390
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:6,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:6,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:49194,wParam:32774,lParam:921510
hwnd:855962,uMsg:874,wParam:0,lParam:0

使用Spy4Win查看聊天窗口:

image

可以看出hwnd:855962 是当前程序的窗口。lParam:921510即是旺旺的聊天消息的窗口。

可以发现每次收到消息时,不管聊天窗口是否已经打开。均有uMsg:49194,wParam:32774,lParam:921510的消息触发。

添加代码:

switch( wParam )
        {
        case 32774:
            {
                HWND hChat = (HWND)lParam;
                char name[255] ={0};
                GetClassNameA(hChat,name,255);

//判断聊天窗口是否为旺旺的窗口。

                if(strcmp(name,"StandardFrame") == 0)
                {
                    ProcessMsg(hwnd,hChat);
                }
            }
            break;
        default:
            break;
        }

3.4 获取聊天窗口句柄,以及历史记录的窗口句柄,历史记录IE的指针。

在ProcessMsg中,根据旺旺的聊天窗口,找到历史记录(WebBrowser)窗口的句柄:

    HWND hFind = ::FindWindowEx(hChat,NULL,L"SplitterBar",NULL);
    hFind = ::FindWindowEx(hFind,NULL,L"StandardWindow",NULL);
    hFind = ::FindWindowEx(hFind,NULL,L"SimpleBrowser",NULL);
    hFind = ::FindWindowEx(hFind,NULL,L"Shell Embedding",NULL);
    hFind = ::FindWindowEx(hFind,NULL,L"Shell DocObject View",NULL);
    hFind = ::FindWindowEx(hFind,NULL,L"Internet Explorer_Server",NULL);

    CComPtr<IHTMLDocument2> spDoc;  
    LRESULT lRes;   
    UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") );  
    ::SendMessageTimeout( hFind, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes );   

    HRESULT hr;  
    hr = ObjectFromLresult( lRes, IID_IHTMLDocument2, 0, (void**)&spDoc );  
    if ( SUCCEEDED(hr) )   
    {  
        CComPtr<IHTMLElement> spElement;
        spDoc->get_body(&spElement);

        //处理网页内容。

CComBSTR text;
        spElement->get_outerHTML(&text);

        wstring strText(text);
     }

        3.5 处理内容,获取聊天内容,发送者ID。

     当获取的IE指针后,后面的分析工作就很简单了,方法可以参考MSDN关于IHTMLDocument2部分。

     因为49194消息可能是旺旺自定义的消息,而且会多次触发,所以处理的时候,可以先处理处MsgID,如果已经处理过,就可以直接忽略。

3.6 实现效果:

image

    4。 发送消息回复。

当处理完收到的消息,可以在本地数据库中查找答案,或者进一步分析,得出合适的答案。再发送给相应的聊天窗口。

查看聊天窗口的输入框,发现该输入框是RichEdit的。所以只需要根据句柄找到输入框的句柄,直接SendMessage设置内容。再SendMessage模拟点击发送出去即可。

image

5。其他

这只是获取旺旺聊天消息的一种方式,还有其他方式:

1。根据旺旺的开发API,开发官方的旺旺插件中也能够获取到聊天消息的内容,但受到旺旺官方的限制。

2。远程植入Dll到旺旺的进程中,再对某些函数和消息进行挂钩,也能实现。但某些情况下受到杀毒软件或者安全软件的限制。

本文所述的方法实现起来比较简单,而且不受限制。使用简单的方法就能实现客服机器人。

但如果想要实现更智能的客服机器人,需要文本分析,人工智能方面的知识和开发。

此方法适用于旺旺2009,旺旺2010,旺旺卖家版,但不适用于旺旺5.7版本。5.7版本需要使用其他方式实现。

 

6。后记

笔者爱好开发,喜欢分析其他软件,找出实现的原理和技术,对破解,插件开发尤其感兴趣。这是第一篇分析的文章,以后我会写出更多的分析文章。

如果你有对某个软件是实现原理比较感兴趣或者比较困惑,可以发Email给我,或者我可以尝试来分析一下。

联系方式:crazydigua # gmail.com (#替换为@)

        QQ:5738626(注明)

        Blog: crazydigua.blog.51cto.com

转载请注明出处。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多