全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:11141
推到 Plurk!
推到 Facebook!

與作業系統掛勾-Hook寫作

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-03-27 03:08:44 IP:61.64.xxx.xxx 未訂閱
http://www.bravos.com.tw/big5/tutor/Profession/Hook/  Hook簡介               MSDN的定義:    A hook is a point in the system message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure.                    Hook應用簡介:    Hook是用來與作業系統掛勾進而攔截並處理某些訊息之用。    例如說,我們想讓系統不管在什麼地方只要按個Ctl-N便執行NotePad,或許您會使用Form的KeyPreview,設定為True,但在其他Process中按Ctl-N呢?那就沒有用,這是就得設一個KeyboardProc來攔截所有Key in的鍵;          再如:線上翻譯軟體(如:易點通) 應用Hook功能中WH_MOUSE的來欄截Mouse的訊息。進而解析滑鼠所在位置的string token以便由資料庫中萃取對應的翻譯字句。    再如:UltraEditor中錄製巨集功能即使用Hook功能中的WH_JOURNALRECORD,執行巨集功能,即使用Hook功能中的WH_JOURNALPLAYBACK;    再如:ICQ會在User不輸入滑鼠或鍵盤idle一陣子時將User由Online的狀態變成Away的狀態。其內部即應用Hook功能中的WH_MOUSE, WH_KEYBOARD 以攔截所有Mouse及Keyboard動作。          Hook可以是整個系統為範圍(Remote Hook),即其他Process的動作您也可以攔截,也可以是LocalHook,它的攔截範圍只有Process本身。Remote Hook的Hook Function要在.Dll之中,Local Hook則可包含在專案模組中。    Remote Hook的應用實例,線上翻譯軟體(如:易點通)、鍵盤輸入法(如:自然輸入法),熱鍵攔截(如:TurboLaunch)。    由上數列舉可知Hook的應用幾乎是無所不在的,您能禁得起這般強悍的功能而不去學習它嗎?            轉載網路上一篇關於hook有趣的描述:    hook鉤子也,windows是訊息導向的,當有事情發生時windows會發出通知告訴你,像"失火了","房子倒了"之類的,於是你對這些訊息做出反應,windows程式大概就是這種架構。而hook的用處就是可以在windows送訊息給你的時候把訊息攔截下來。    你可以想像你的程式是皇帝,而windows是宰相,而hook是太監;如果話是從宰相口中親耳聽到的八成假不了,如果話是太監口中聽到的,說不定就變質了,hook的功用就是在這裡,所以你可以寫一個文字編輯器,然後掛上一個hook,並且用這個hook把鍵盤訊息攔截下來,然後把它丟掉,於是你的文字編輯器就沒有作用了,所以說宦官能搞亂朝政。    當然大部分人不會做這總傻事,大部分寫hook都是為了攔截整個系統的訊息或是假裝訊息給別人,這個時候你就必須把hook寫在dll裡了,然後用你的程式啟動dll裡的hook,由於dll會載入到所有的人的行程裡,所以你就可以利用她偷竊別人的東西或是假傳聖旨,例如你可以抓別人的視窗handle然後用你的程式對她丟訊息,比較值得注意的是,在dll裡你必須將要用來共享的資料設成shared,這樣才能去抓別的程式的資料,因為dll雖然存在於每個人的行程裡,但是資料都是獨立的,也就是每個人都有一分,如果你把用來共享的資料設成shared,那這筆記憶體區塊就只有一份,於是就可以拿來偷東西了             Hook程式必備的API       l   SetWindowsHookEx        The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for certain types of events. These events are associated either with a specific thread or with all threads in the system.       HHOOK SetWindowsHookEx(       int idHook,  hook型態,常用型態例如:WH_CALLWNDPROC        HOOKPROC lpfn,  自訂的hook procedure 之回呼函式,其prototype會依idHook(hook型態)而異        HINSTANCE hMod,  應用程式或DLL之instance     如果是Remote Hook,則可以使用GetModuleHandle(".dll名稱")來傳入。     如果是Local Hook,該值可以是NULL        DWORD dwThreadId);  指定要攔截訊息之thread ID,若為0則攔截系統中所有thread之訊息        回傳值:  如果SetWindowsHookEx()成功,它會傳回一個值,代表目前的Hook的Handle,這個值要記錄下來以提供UnHookWindowHookEx() (可用於 unhook時之參數)                                     l   UnhookWindowsHookEx        釋放移除先前經由SetWindowsHookEx()所註冊的hook handle resource.       BOOL UnhookWindowsHookEx(HHOOK hHook);       hHook,  便是SetWindowsHookEx()的傳回值                  l   CallNextHookEx        The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. A hook procedure can call this function either before or after processing the hook information.       LRESULT CallNextHookEx(       HHOOK hHook,  handle to current hook        int nCode,  hook code passed to hook procedure        WPARAM wParam,  value passed to hook procedure        LPARAM lParam);  value passed to hook procedure        CallNextHookEx 使用時機:        例如A程式可以有一個System Hook(Remote Hook),如KeyBoard Hook,而B程式也來設一個Remote的KeyBoard Hook,那麼到底KeyBoard的訊息誰所攔截?答案是,最後的那一個所攔截,也就是說A先做keyboard Hook,而後B才做,那訊息被B攔截,那A呢?就看B的Hook Function如何做。如果B想讓A的Hook Function也得這個訊息,那B就得呼叫CallNextHookEx()將這訊息Pass給A,於是產生Hook的一個連線。如果B中不想Pass這訊息給A,那就不要呼叫CallNextHookEx()。                   
Hook-C  範例
      本範例利用Hook技巧以攔截Microsoft Visual C   Dialog Box,因為此為Remote Hook故需以DLL包裝
 
//  HookVc.DLL     //  本模組開放兩個介面函式供外部程式呼叫     //  *   HookVcWndProc()     ==> 啟動攔截 VC 的視窗訊息     //  *   UnHookVcWndProc()   ==> 終止攔截 VC 的視窗訊息     HINSTANCE g_hInst = NULL;     static HWND s_hWndVc = NULL;    //  VC 的 Window Handle     static HHOOK s_hHook = NULL;    //  Hook Handle ID     int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)     {         g_hInst = hinst;         return 1;     }     BOOL HookVcWndProc()     {         //  找出VC主視窗 Window Handle         EnumWindows((WNDENUMPROC)EnumWindowsProc, NULL);        DWORD dwVcThreadId;         if (s_hWndVc && g_hInst) {            //  找出產生VC主視窗的ThreadID             dwVcThreadId = GetWindowThreadProcessId(s_hWndVc, NULL);             if (dwVcThreadId)                 //  於系統Send Message給VC處理後攔截     s_hHook=SetWindowsHookEx(WH_CALLWNDPROCRET,                                         (HOOKPROC)CallWndRetProcHook,  //  自訂的hook procedure之回呼函式                          g_hInst,                          //  this Dll's instance                          dwVcThreadId);                    //  thread you want to hook, here it's VC             if (s_hHook) return TRUE;   //  啟動攔截 VC 的視窗訊息成功         }         return FALSE;                   //  啟動攔截 VC 的視窗訊息失敗     } // HookVcWndProc     void UnHookVcWndProc()     {         if (s_hHook) {             UnhookWindowsHookEx(s_hHook); s_hHook = NULL ;         }     } // UnHookVcWndProc     //  自訂的hook procedure之回呼函式     //  nCode: 若 nCode<0 ==>不處理     //  lParam: Pointer to CWPRETSTRUCT, 訊息詳細資料     LRESULT CALLBACK CallWndRetProcHook(int nCode, WPARAM wParam, LPARAM lParam)     {         // Buffer for storing the window title.         TCHAR szBuff[ MAX_PATH ] ;         //  傳遞訊息給可能存在的下一個 Hook procedure         LRESULT lRet=CallNextHookEx(s_hHook, nCode, wParam, lParam);         //  若 nCode<0 ==>不繼續處理 (請參照 MSDN 'HOOKPROC', 'CallWndRetProc'文件說明)         if ( nCode < 0 ) return lRet;         //  取得訊息詳細資料 CWPRETSTRUCT *         PCWPRETSTRUCT pMsg = (PCWPRETSTRUCT)lParam;         //  以下利用 pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam繼續處理         //  ...         return lRet;     } // CallWndRetProcHook 
 
 
Hook-Delphi範例
      使用過ICQ嗎?ICQ會在User不輸入滑鼠或鍵盤idle一陣子時將User由Online的狀態變成Away的狀態。本範例利用Hook型態WH_MOUSE, WH_KEYBOARD 以攔截所有Mouse及Keyboard動作。當使用者於預定時限當中不輸入滑鼠或鍵盤時,本元件會觸發一個OnIdle notify event
 
l 
 TBvIdleCheck元件功能描述: 
 
  
 A user idle chekcing Component, apply the mouse/keyboard hook callback to check user idle time on application level.    當使用者於預定時限當中不輸入滑鼠或鍵盤時,本元件會觸發一個OnIdle notify event
 
l 
 Properties 
 
  
 Active:
 true èstart check, false èstop check
 
  
 Interval:
 Idle checking pooling time frequency (in second)
 
  
 IdleTime:
 Define the IdleTime criteria (in second)
 
l 
 Notify Event: 
 
  
 OnIdle:
 notify event happened when user mouse and keyboard idle time out
 
  
   
 
程式碼片段:
 
//  Mouse Hook 回呼函數內容     function MouseHookCallBack(Code: integer; Msg: WPARAM; MouseHook: LPARAM): LRESULT; stdcall;     begin         if  Code >= 0 then s_tIoEvent := Now;  //  紀錄 Mouse IO 時發生之時間         Result := CallNextHookEx(s_WhMouse, Code, Msg, MouseHook);     end;     //  Keyboard Hook 回呼函數內容     function KeyboardHookCallBack(Code: integer; Msg: WPARAM; KeyboardHook: LPARAM): LRESULT; stdcall;     begin         if  Code >= 0 then s_tIoEvent := Now;  //  紀錄 Keyboard IO 時發生之時間         Result := CallNextHookEx(s_WhKeyboard, Code, Msg, KeyboardHook);     end;     //  Construtor     constructor TBvIdleCheck.Create(AOwner: TComponent);     begin //[         inherited Create(AOwner);         ....         Inc(s_nInstances);         if  s_nInstances > 1 then exit;         //  註冊 Mouse Hook 回呼函數         s_WhMouse := SetWindowsHookEx(WH_MOUSE, MouseHookCallBack, GetModuleHandleFromInstance, GetCurrentThreadID);         //  註冊 Keyboard Hook 回呼函數         s_WhKeyboard := SetWindowsHookEx(WH_KEYBOARD, KeyboardHookCallBack, GetModuleHandleFromInstance, GetCurrentThreadID);     end; // ] TBvIdleCheck.Create     //  Destructor     destructor TBvIdleCheck.Destroy;     begin // [         Dec(s_nInstances);         Stop;         if  s_nInstances = 0 then begin                //  釋放 hook handle             UnhookWindowsHookEx(s_WhKeyboard); UnhookWindowsHookEx(s_WhMouse);         end;         inherited Destroy;     end; // ] TBvIdleCheck.Destroy     //  元件內部檢查 user 是否 idle,     //  if  yes ==> 觸發 Notify Event     procedure TBvIdleCheck._TimeHit(Sender: TObject);     var         tNow: TDateTime;         nSecElapsed: integer;     begin // [         tNow=Now;         nSecElapsed=TimeDiffSec(tNow, s_tIoEvent);         if  nSecElapsed
 
Hook-VB範例
      本範例展示在VB中利用Hook技巧以攔截應用程式中User按下Print Screen按鍵,因為此為Local Hook故可直接含於project中
 
'           ======================================================================     '          HookKb.BAS     '          KeyBoard Hook 的範例     '           ======================================================================     Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _             (ByVal idHook As Long, _             ByVal lpfn As Long,   _             ByVal hmod As Long,   _             ByVal dwThreadId As Long) As Long     Declare Function UnhookWindowsHookEx Lib "user32" Alias "UnhookWindowsHookEx"  _             (ByVal hHook As Long) As Long     Declare Function CallNextHookEx Lib "user32" Alias "CallNextHookEx" _             (ByVal hHook As Long, _             ByVal ncode As Long, _             ByVal wParam As Long, _             lParam As Any) As Long           Public g_hHook as Long           Public Function HookAppKb() As Boolean         HookAppKb = true         If g_hHook <> 0 Then             Exit Function         End If         '   攔截所有keystroke訊息         g_hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf MyKBHFunc, App.hInstance, App.ThreadId)     End Function           Public Sub UnHookAppKb()         If  g_hHook <> 0 Then             UnhookWindowsHookEx g_hHook             g_hHook = 0         End If     End Sub     '   MyKBHFunc: KeyStroke Hook Function的三個參數     '   Public Function MyKBHFunc(ByVal iCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long     '   iCode   HC_ACTION或HC_NOREMOVE     '   wParam  表按鍵Virtual Key     '   lParam  與WM_KEYDOWN同     '   傳回值  若訊息要被處理傳0反之傳1     Public Function MyKBHFunc(ByVal iCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long         MyKBHfunc = 0 '表示要處理這個訊息         If  wParam = vbKeySnapshot Then  '偵測-->若按到PrintScreen鍵             MyKBHFunc = 1 '在這個Hook便吃掉這個訊息             '   處理 User 按到PrintScreen鍵之動作             '   ....             Exit Function         End If         Call CallNextHookEx(g_hHook, iCode, wParam, lParam) '傳給下一個Hook     End Function 
 
      下載本範例: http:/dn/tutor/Delphi.Advance/HookKb.zip
 
 
附加檔案:47170_Hook.doc
pcboy
版主


發表:177
回覆:1838
積分:1463
註冊:2004-01-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-11-28 15:10:05 IP:61.220.xxx.xxx 訂閱
和下面這篇相同耶, 不過這篇比較早張貼
http://delphi.ktop.com.tw/board.php?cid=31&fid=77&tid=47170
------
能力不足,求助於人;有能力時,幫幫別人;如果您滿意答覆,請適時結案!

子曰:問有三種,不懂則問,雖懂有疑則問,雖懂而想知更多則問!
系統時間:2024-11-21 19:33:12
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!