Hook MSN Messenger之socket通訊的鳥事
如果要問我這幾天怎麼都沒寫blog,那除了正在搞DirectShow的心得分享外,卡在另一個API hooking上的問題,肯定是主因了。
這問題是怎樣的呢?話說我用API hooking的方式,試著掛上winsock API中的函式-recv()。其主要目的是要聽取MSN Messenger所傳送的所有訊息。程式寫好後,在自己的電腦上跑的也好好的,不過丟到另一台電腦上去,嘿,可怎麼都不會動。
接著開始漫長的診斷程序,我發現其餘的函式像send()、sendto()都可以成功的掛上去,但就是recv()和recvfrom()掛不上去。於是開始胡思亂想,猜想會不會是這台機器中毒了啊?請出了Birdman的Archon,也掃不出個所以然。
不過,就在快要絕望的時候,曙光竟然出現了-我發現,Messenger 7.5可以掛的上去,但Live Messenger不行啊。這是個好消息,經過反覆實驗後,發現的確如此。好,那問題就回到為什麼Live Messenger不行?難不成它用的不是recv()這個blocking的函式,而是non-blocking版本的WSARecv()嗎?
試著掛上WSARecv(),的確有反應,但截錄到的訊息並不是MSN用來傳遞訊息之用的。這…這真是令人絕望啊。
等等,在hook函式時,我指定的是ws2_32.dll,也就是Winsock 2中的函式,而不是wsock32.dll,也就是Winsock 1.1中的函式,這Live Messenger該不會用的是Winsock 1.1中的函式吧?這也不對,因為讓我們先來看一張圖:
基本上整個Winsock API的發展,如果從Winsock 1.1講的話,首先要提的是針對當時仍是16 bits作業系統(Windows 3.1)的Winsock 1.1應用程式。當時以winsock.dll提供16 bits的應用程式使用Winsock 1.1中的功能。到Windows 95問世後,得以出現32 bits的Winsock應用程式,為了與16 bits的winsock.dll區隔,另行提供了wsock32.dll。在wsock32.dll中,為32 bits的應用程式,提供了Winsock 1.1的實作。之後Winsock 2的API推出(ws2_32.dll),自然進行了許多的加強,但基於Winsock的遺產龐大,勢必處理相容Winsock 1.1的問題。而處理的最佳方式,自然是利用Winsock 2中的API來提供原先Winsock 1.1中API的功能。所以我們可以在上圖中看到倘若在提供Winsock 2的環境上,Winsock 1.1的函式是基於Winsock 2而達成的。
所以幾乎可以猜想,wsock32.dll中的函式,最終大概就是會轉遞至ws2_32.dll中的函式,因為提供重複的Winsock實作是很奇怪也不合邏輯的事。這是為什麼我即使有點懷疑Live Messenger用的是Winsock 1.1中的函式,但還是繼續認為即便如此,我只要hook到ws2_32.dll就可以。
嘿,debug這回事呀,就是要捐棄所有的成見,放掉所有的偏見。當事情無論如何都不在你想要的軌道上運行時,就只能把大腦清成空白,然後把自己變成白痴,不受某些既定的推論影響,才能夠有所收獲。
所以最後一條路,就掛掛看啊。
天啊,就是它。當我把自己的recv()掛到wsock32.dll時,發現Live Messenger傳的訊息都收到了。
這…這要怎麼解釋呀?東西既然會動了,那就來找答案吧。
看看這篇:
On WinXP, if you hook wsock32.dll, most of the API's are forwarded to either ws2_32.dll or to mswsock.dll. Only a couple API's are handled directly.
是的,Only a couple API's are handled directly
我要的recv()該不會就是吧?
在中整理了wsock32.dll中的每個函式究竟是自行實作,或是forward給mswsock.dll或ws2_32.dll。
很不幸或很幸運的(因為我終於找到解釋了)
哈!夠鳥吧。wsock32.dll中的send()和sentto()都是forward給ws2_32.dll中的send()及sendto()。但recv()和recvfrom()卻都有自己的實作。這就是之所以之前hook ws2_32.dll中的recv()對Live Messenger一直不能起作用的原因啊,因為它用的竟然是Winsock 1.1中的recv()而不是Winsock 2中的recv()。
這整件事,從頭到尾都很詭異。為什麼7.5版的MSN Messenger用的是Winsock 2,但到了MSN Live Messenger後,反而用回了Winsock 1.1中的recv()。然後,為什麼Winsock 1.1中的recv()和recvfrom()不像其他的函式一樣都forward給Winsock 2中的函式呢?這兩個謎團希望日後可以找到答案。
今天要開心的去睡覺了。