MySpy開發手記 (轉)

worldblog發表於2008-01-11
MySpy開發手記 (轉)[@more@]

:namespace prefix = o ns = "urn:schemas--com::office" /> 

撰文-Aweay

最近作者用20天寫了一個小,在csdn的Bcb論壇和chinabcb發表,得到了大家的支援,並有很多朋友詢問是否可以公程式碼,作者其實也不是一個保守的人,以前就公開了自己的遊戲,但後來這個遊戲被別人,還那他當共享軟體收費,我非常生氣,也算有了教訓,這次作者在短期之內是不會公開原始碼了,但面對那麼多網友的支援,作者認為有責任寫一些東西來幫助廣大bcber愛好者共同進步,所以就寫了這篇開發手記,希望對初學者有一定幫助,如果你是高手,就當我班門弄斧好了。

如果你還沒有見過MySpy,你可以從?t=6445"> ,這個地址需要你註冊登入才能看到下載地址,否則只有介紹。

作者不打算介紹整個開發過程,就拿出問的最多的問題來介紹一下吧:

1.  如何將圖示儲存為真彩色圖示的?

其實,這本來不改算是個問題,但在Bcb和裡這可真是一個非常難解決的問題,不知大家是否知道,Bcb和Delphi的TIcon類儲存的圖示僅支援16色,這樣不管是256色還是真彩色的圖示,都只能用16色來顯示,這樣的儲存結果不要也罷,作者曾一度想放棄儲存圖示的功能,但最後還是沒有這樣做,那麼作者是怎麼解決的呢?

首先作者想到了Inte,既然我有這樣的問題,那麼世界上肯定還有其他人遇到了這樣的問題,去上應該可以找到其他人解決問題的方法,作者花了一個下午的時間,在各大Delphi站點、faq、區都沒有找到合適的解決方法,最後在一個日本網戰上找到了一個TIconEx,從幾個認識的中文裡,我猜出了這個東西正好是我要的,我立刻開著快車把他下了下來,很可惜沒有原始碼,日本人真tmd的討厭,懷著對日本人無限的憤怒之情,我把那個TIconEx扔進了垃圾箱。

看來他山之石是借不出來了,那麼作者只好從底層出發尋找解決方案了,從這個地址http://www.csdn.net/dev/format/ ,作者找到了Icon的格式和一段工程師寫的例子程式碼,作者用了一個晚上來研究這個Icon格式和工程師的程式碼,明白後,作者決定把他用Bcb封裝起來,因為原來的程式碼是用c語言編寫的,而作者是個 oo 愛好者,所以作者決定把他類化然後加入了從HICON儲存檔案的程式碼(原來的只能從模組中抽取出來儲存)。

程式碼是寫完了,但是把他用到Bcb還真是不容易,不過這已經不是技術問題了,大家如果有興趣就自己試一試吧,對了,上面介紹Icon格式的文章是英文的,如果作者有時間了,會把他翻譯成為中文的,那篇文章寫的相當好。

2.  如何HOOK

HOOK在MySpy裡是用的最多的技術,從獲取密碼到截獲的訊息都是HOOK技術,可以說這個技術已經不是什麼技術了,網上隨便一個站點都可以找到相關介紹資料,但截獲系統訊息的還是比較麻煩的,作者就介紹一下它吧。

截獲系統訊息無非是系統鉤子WH_CALLWNDPROC、WH_CALLWNDPROCRET和WH_GETMESSAGE,為什麼要安裝這麼多,因為系統訊息有很多不同的型別,有Send,Post還有處理訊息返回也是需要截獲的,當然如果你對系統選單也感興趣,還需要安裝WH_SYSMSGFILTER鉤子,因為這是一個系統範圍的鉤子,所以必須編寫成為DLL,而核心程式碼也不過就是:

LRESULT CALLBACK MsgHookProc1(int nCode, WPARAM wParam,LPARAM lParam)

{

  if (nCode>=0)

  {

  CTRUCT* mm=(CWPSTRUCT*)lParam;

  MsgData data;

  data.msg=mm->message;

  data.wparam=(int)mm->wParam;

  data.lparam=(int)mm->lParam;

  data.type=1;

  data.result=0;

  COPYDATASTRUCT copydata;

  copydata.dwData=0;

  copydata.cbData=sizeof(MsgData);

  copydata.lpData=&data;

  if(mm->hwnd==HookStruct->HookedWnd)

  {

  SendMessage(HookStruct->ParentWnd,WM_COPYDATA,0,(LPARAM)&copydata);

  }

  }

  return(CallNextHookEx(HookStruct->MsgHook1,nCode,wParam,lParam));

}

可以看到作者是使用WM_COPYDATA向MySpy傳送通知訊息的,上面是其中一個HOOK的回撥,其他類似。MySpy收到WM_COPYDATA訊息後,會將lParam引數轉換成為MsgData,而這個結構體封裝了關於該訊息全部有用的資訊,就等著MySpy處理了。HOOK其實真的很簡單,就是麻煩,作者在除錯過程中,至少當機10多次,如果使用系統,可能你就光當機了。

到此你可能認為寫個截獲訊息的功能就算完成了,如果你注意MySpy的話,並對有一定了解,你會發現,我們得到的訊息是個整數的id,而我們不可能只給顯示個id,我們需要WM_XXX這個的友好表示,但API裡並沒有提供把整數id轉換成為友好字串的函式,這該如何解決呢?作者最後使用了一個記錄檔案,檔案格式如下:

0x0000 WM_NULL

0x0001 WM_CREATE

0x0002 WM_DESTROY

0x0003 WM_MOVE

0x0005 WM_SIZE

0x0006 WM_ACTIVATE

……

有了這個檔案,查詢對應的友好字串就簡單了,而且擴充套件這個記錄檔案非常容易,你可以加入你已知id的對應字串。關鍵在於查詢,這個也不難,排序後查詢再合適不過了。到現在,作者也不知道我的解決方法是不是最好的,還請各位賜教?

3.  如何得到網頁上的元素,並取得他的相關資訊?

這個問題還是有一點難度的,特別對於不懂COM的人,這個問題就更難了。

想要操作HTML首先要得到IHtmlDocument2介面,這個介面是IE4.0以上提供用來專門與Html互動的COM表露的,如果我們用或script來操作Html,非常簡單,當然得到網頁裡的元素也非常簡單,而使用Bcb這樣的開發工具來操作Html,沒有微軟的幫助恐怕是不行(至少作者不知道),還好微軟確實提供了這方面的支援。這個支援就是OLEACC.DLL。

這個DLL的功能很多,其中之一就是從HWND得到關聯的COM物件的介面,那麼程式碼到底是什麼樣的呢?

CComPtr spAccess;

hr=AccessibleFromWindow(hwnd,0,IID_IAccessible,(void**) &spAccess);

if ( SUCCEEDED(hr) )

{

CComPtr spServiceProv;

hr=spAccess->QueryInterface(IID_IServiceProvider,(void**)&spServiceProv);

if(hr==S_OK)

{

CComPtr spWin;

hr=spServiceProv->QueryService(IID_IHTMLWindow2,IID_IHTMLWindow2,(void**)&spWin);

if(hr==S_OK)

spWin->get_document(&pDoc2);

}

}

上面就是從HWND取得IHTMLDocument2介面的核心程式碼了,當然你需要加入Oleacc.h和Oleacc.lib檔案,得到IHTMLDocument2介面後我們就用了同ASP同樣強大的能力去造作HTML了,關於如何操作HTML這裡就不談了,有ASP知識的朋友一看到這裡我想都明白了吧。

這裡的關鍵函式就是Oleacc.dll匯出的AccessibleObjectFromWindow,這個函式的作用看一下名字就知道了,MSDN裡給的說明如下:

Retrieves the address of the specified interface to the object associated with the given window.

所以這個函式不光可以得到IHTMLDocument2介面還可以得到Office等介面,有興趣的可以試一試.

4.  如何編寫?

MySpy支援外掛,而且為MySpy開發外掛很容易,當然這主要靠作者的合理設計和完整的開發文件(大家不要砸我:)),編寫外掛本來不應該算MySpy的特色功能,或者說絕對不是什麼核心技術,不過既然MySpy寫了,又有人問,我就順便介紹一下如何開發外掛吧。

作者在開始設計外掛結構的時候,徘徊在使用COM插還是普通DLL插的交叉路口,使用COM會容易編寫程式碼,對於開發人員容易理解,而且現在的大多數軟體都是使用COM作為外掛的,但使用COM的最大問題是,將大大增加MySpy的身體臃腫度和增加MySpy的開發時間,因為作者需要單獨編寫一個DLL來封裝整個MySpy,然後表露介面,這樣就額外帶來了將近1倍額外脂肪,這是作者不能接受的,還有就是編寫COM外掛對於開發人員要求太高了;使用DLL來做外掛又有很多方法,是匯出若干函式來負責若干功能還是匯出1-2個函式來泛化設計呢?還有就是要不要外掛同MySpy有互動呢(存在雙向資料訪問嗎?)

最後作者選擇了現在的解決方法,就是僅匯出一個函式的泛化設計,這個設計類似於的訊息機制,就是MySpy傳送若干訊息給外掛來通知外掛做什麼事情,外掛也可以傳送訊息給MySpy來控制MySpy,而開發人員僅需要處理相應訊息並返回必要的值,剩下的事情由MySpy完成,這樣的解決方法不需要額外的DLL,在MySpy程式碼內部的適當位置傳送適當的訊息給外掛,然後處理返回值就可以了。我們來看一下匯出函式的格式:

extern "C" __declspec(dllexport)

int MMPlugin(MMSG msg,MPARAM wParam,MPARAM lParam)

{

  switch(msg)

  {

  case MM_INIT:

  //place your init code here

  break;

  case MM_DESTROY:

  //place your destroy code here

  break;

  …

  }

}

可以看到這個匯出函式,很像WndProc函式,作者這樣設計的靈感完全來源於Windows訊息機制的巧妙,一個整型的MPARAM引數可以傳遞任何型別,任何大小的資料,作者真的很佩服Windows的訊息機制,不知各位朋友有什麼好的方法,不妨大家一起討論一下。

至此MySpy的關鍵技術已經全部介紹完了,大家可能也看到了,作者對所有的技術介紹都是點到為止,並沒有討論的很詳細,這並不是作者不願意給出原始碼,而是沒有必要,在作者看來解決問題的方法是思想,如果大家有興趣,自己試一試,像作者一樣花個10-20天,肯定大有收穫。

作者非常歡迎大家來信討論 to:siney@yeah.net">siney@yeah.net 。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-997081/,如需轉載,請註明出處,否則將追究法律責任。

相關文章