網站首頁 學習教育 IT科技 金融知識 旅遊規劃 生活小知識 家鄉美食 養生小知識 健身運動 美容百科 遊戲知識 綜合知識
當前位置:趣知科普吧 > 綜合知識 > 

hook怎麼寫

欄目: 綜合知識 / 發佈於: / 人氣:2.04W
1. thinkphp hook 怎麼寫

ThinkPHP3.2 擴展--鉤子,HOOK之前寫到TP3.1的行爲擴展是tag();在TP3.2中引入了另一種說法—:鉤子。

hook怎麼寫

我們來看一下TP3.2中的鉤子這個東西: 一:檔案流程: 1:/index.php ->require './ThinkPHP/ThinkPHP.php'; 2:/ThinkPHP/ThinkPHP.php—->require CORE_PATH.'Think'.EXT; ThinkThink::start(); 3:/ThinkPHP/Library/Think/Think.class.php—–>App::run(); 4:/ThinkPHP/Library/Think/App.class.php 。到這裏基本流程就走完了,(這裏不說細節);二:代碼: 1:看一下 App::run()方法:// 應用初始化標籤 Hook::listen('app_init'); App::init(); // 應用開始標籤 Hook::listen('app_begin'); // Session初始化 if(!IS_CLI){ session(C('SESSION_OPTIONS')); } // 記錄應用初始化時間 G('initTime'); App::exec(); // 應用結束標籤 Hook::listen('app_end'); return ;其中的Hook::listen(”)就是用來執行鉤子的,我們可以在app_init這個安插的位置用來獲取應用中安裝的插件。

看一下Hook::listen();/** * 監聽標籤的插件 * @param string $tag 標籤名稱 * @param mixed $params 傳入參數 * @return void */ static public function listen($tag, &$params=NULL) { if(isset(self::$tags[$tag])) { if(APP_DEBUG) { G($tag.'Start'); trace('[ '.$tag.' ] --START--','','INFO'); } foreach (self::$tags[$tag] as $name) { APP_DEBUG && G($name.'_start'); $result = self::exec($name, $tag,$params); if(APP_DEBUG){ G($name.'_end'); trace('Run '.$name.' [ RunTime:'.G($name.'_start',$name.'_end',6).'s ]','','INFO'); } if(false === $result) { // 如果返回false 則中斷插件執行 return ; } } if(APP_DEBUG) { // 記錄行爲的執行日誌 trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO'); } } return; }其中關鍵是:self::exec($name, $tag,$params); 看一下exec的代碼:/** * 執行某個插件 * @param string $name 插件名稱 * @param string $tag 方法名(標籤名) * @param Mixed $params 傳入的參數 * @return void */ static public function exec($name, $tag,&$params=NULL) { if(false === strpos($name,'')) { // 插件(多個入口) $class = "Addons{$name}{$name}Addon"; }else{ // 行爲擴展(只有一個run入口方法) $class = $name.'Behavior'; $tag = 'run'; } $addon = new $class(); return $addon->$tag($params); }最後還不是 new $class();進而return $addon->$tag($params); 又轉到了具體鉤子的代碼方法。其實就是我們原本的調用class的方法,只不過經過別人的高度封裝了。

三:那麼問題來了,這個鉤子有什麼用呢? 怎麼用? 這裏以OneThink 的{:hook('AdminIndex')}爲例,看一些別人是怎麼用的。 在系統初始化到 Hook::listen('app_init'); 時, 把app_init的標籤位擴展了,在tags.php的配置檔案中有這麼個東西:用於初始化插件(或者說是獲取系統中安裝的插件) 'app_init'=>array('CommonBehaviorInitHook'));一看就明白,無非就是讀取持久化的資訊,放到快取或是其他的方式// 行爲擴展的執行入口必須是run public function run(&$content){ if(isset($_GET['m']) && $_GET['m'] === 'Install') return; $data = S('hooks'); if(!$data){ $hooks = M('Hooks')->getField('name,addons'); foreach ($hooks as $key => $value) { if($value){ $map['status'] = 1; $names = explode(',',$value); $map['name'] = array('IN',$names); $data = M('Addons')->where($map)->getField('id,name'); if($data){ $addons = array_intersect($names, $data); Hook::add($key,$addons); } } } S('hooks',Hook::get()); }else{ Hook::import($data,false); } }當在程序執行到{:hook('AdminIndex')}時—>調用的是Hook::listen('AdminIndex'); AdminIndex這個掛載點包含了三個插件:分別是:SiteStat, SystemInfo,DevTeam。

用一個循環來分別按順序執行.總結:鉤子其實就是起到一個掛載點的作用,這個鉤子掛在哪裏,就可以在哪裏執行,內容或功能就是掛載插件或類庫的具體實現。這樣實現的代碼就有很大的靈活性,掛載點不變,掛的東西變量,功能也就相應的變化,是不是很靈活強大呀。

2. netfilter框架中的hook函數怎麼寫

通俗的說,netfilter的架構就是在整個網絡流程的若干位置放置了一些檢測點(HOOK),而在每個檢測點上登記了一些處理函數進行處理(如包過濾,NAT等,甚至可以是 用戶自訂的功能)。

netfilter[1]

IP層的五個HOOK點的位置如下圖所示

[1]:NF_IP_PRE_ROUTING:剛剛進入網絡層的數據包透過此點(剛剛進行完版本號,校驗

和等檢測), 目的地址轉換在此點進行;

[2]:NF_IP_LOCAL_IN:經路由查找後,送往本機的透過此檢查點,INPUT包過濾在此點進行;

[3]:NF_IP_FORWARD:要轉發的包透過此檢測點,FORWARD包過濾在此點進行;

[4]:NF_IP_POST_ROUTING:所有馬上便要透過網絡設備出去的包透過此檢測點,內置的源地址轉換功能(包括地址僞裝)在此點進行;

[5]:NF_IP_LOCAL_OUT:本機進程發出的包透過此檢測點,OUTPUT包過濾在此點進行。

在IP層代碼中,有一些帶有NF_HOOK宏的語句,如IP的轉發函數中有:

如果在編譯內核時沒有配置netfilter時,就相當於調用最後一個參數,此例中即執行

ip_forward_finish函數;否則進入HOOK點,執行透過nf_register_hook()登記的功能

(這句話表達的可能比較含糊,實際是進入nf_hook_slow()函數,再由它執行登記的

函數)。

3. 什麼是HOOK功能

HOOK API是一個永恆的話題,如果沒有HOOK,許多技術將很難實現,也許根本不能實現。

這裏所說的API,是廣義上的API,它包括DOS下的中斷,WINDOWS裏的API、中斷服務、IFS和NDIS過濾等。比如大家熟悉的即時翻譯軟件,就是靠HOOK TextOut()或ExtTextOut()這兩個函數實現的,在操作系統用這兩個函數輸出文字之前,就把相應的英文替換成中文而達到即時翻譯;IFS和NDIS過濾也是如此,在讀寫磁盤和收發數據之前,系統會調用第三方提供的回調函數來判斷操作是否可以放行,它與普通HOOK不同,它是操作系統允許的,由操作系統提供接口來安裝回調函數。

甚至如果沒有HOOK,就沒有病毒,因爲不管是DOS下的病毒或WINDOWS裏的病毒,都是靠HOOK系統服務來實現自己的功能的:DOS下的病毒靠HOOK INT 21來感染檔案(檔案型病毒),靠HOOK INT 13來感染引導扇區(引導型病毒);WINDOWS下的病毒靠HOOK系統API(包括RING0層的和RING3層的),或者安裝IFS(CIH病毒所用的方法)來感染檔案。因此可以說“沒有HOOK,就沒有今天多姿多彩的軟件世界”。

由於涉及到專利和知識產權,或者是商業機密,微軟一直不提倡大家HOOK它的系統API,提供IFS和NDIS等其他過濾接口,也是爲了適應殺毒軟件和防火牆的需要纔開放的。所以在大多數時候,HOOK API要靠自己的力量來完成。

HOOK API有一個原則,這個原則就是:被HOOK的API的原有功能不能受到任何影響。就象醫生救人,如果把病人身體裏的病毒殺死了,病人也死了,那麼這個“救人”就沒有任何意義了。

如果你HOOK API之後,你的目的達到了,但API的原有功能失效了,這樣不是HOOK,而是REPLACE,操作系統的正常功能就會受到影響,甚至會崩潰。 HOOK API的技術,說起來也不復雜,就是改變程序流程的技術。

在CPU的指令裏,有幾條指令可以改變程序的流程:JMP,CALL,INT,RET,RETF,IRET等指令。理論上只要改變API入口和出口的任何機器碼,都可以HOOK,但是實際實現起來要複雜很多,因爲要處理好以下問題: 1,CPU指令長度問題,在32位系統裏,一條JMP/CALL指令的長度是5個字節,因此你只有替換API裏超過5個字節長度的機器碼(或者替換幾條指令長度加起來是5字節的指令),否則會影響被更改的小於5個字節的機器碼後面的數條指令,甚至程序流程會被打亂,產生不可預料的後果; 2,參數問題,爲了訪問原API的參數,你要透過EBP或ESP來引用參數,因此你要非常清楚你的HOOK代碼裏此時的EBP/ESP的值是多少; 3,時機的問題,有些HOOK必須在API的開頭,有些必須在API的尾部,比如HOOK CreateFilaA(),如果你在API尾部HOOK API,那麼此時你就不能寫檔案,甚至不能訪問檔案;HOOK RECV(),如果你在API頭HOOK,此時還沒有收到數據,你就去檢視RECV()的接收緩衝區,裏面當然沒有你想要的數據,必須等RECV()正常執行後,在RECV()的尾部HOOK,此時去檢視RECV()的緩衝區,裏面纔有想要的數據; 4,上下文的問題,有些HOOK代碼不能執行某些操作,否則會破壞原API的上下文,原API就失效了; 5,同步問題,在HOOK代碼裏儘量不使用全局變量,而使用局部變量,這樣也是模組化程序的需要; 6,最後要注意的是,被替換的CPU指令的原有功能一定要在HOOK代碼的某個地方模擬實現。

下面以ws2_32.dll裏的send()爲例子來說明如何HOOK這個函數: Exported fn(): send - Ord:0013h 地址 機器碼 彙編代碼 :71A21AF4 55 push ebp //將被HOOK的機器碼(第1種方法) :71A21AF5 8BEC mov ebp, esp //將被HOOK的機器碼(第2種方法) :71A21AF7 83EC10 sub esp, 00000010 :71A21AFA 56 push esi :71A21AFB 57 push edi :71A21AFC 33FF xor edi, edi :71A21AFE 813D1C20A371931CA271 cmp dword ptr [71A3201C], 71A21C93 //將被HOOK的機器碼(第4種方法) :71A21B08 0F84853D0000 je 71A25893 :71A21B0E 8D45F8 lea eax, dword ptr [ebp-08] :71A21B11 50 push eax :71A21B12 E869F7FFFF call 71A21280 :71A21B17 3BC7 cmp eax, edi :71A21B19 8945FC mov dword ptr [ebp-04], eax :71A21B1C 0F85C4940000 jne 71A2AFE6 :71A21B22 FF7508 push [ebp+08] :71A21B25 E826F7FFFF call 71A21250 :71A21B2A 8BF0 mov esi, eax :71A21B2C 3BF7 cmp esi, edi :71A21B2E 0F84AB940000 je 71A2AFDF :71A21B34 8B4510 mov eax, dword ptr [ebp+10] :71A21B37 53 push ebx :71A21B38 8D4DFC lea ecx, dword ptr [ebp-04] :71A21B3B 51 push ecx :71A21B3C FF75F8 push [ebp-08] :71A21B3F 8D4D08 lea ecx, dword ptr [ebp+08] :71A21B42 57 push edi :71A21B43 57 push edi :71A21B44 FF7514 push [ebp+14] :71A21B47 8945F0 mov dword ptr [ebp-10], eax :71A21B4A 8B450C mov eax, dword ptr [ebp+0C] :71A21B4D 51 push ecx :71A21B4E 6A01 push 00000001 :71A21B50 8D4DF0 lea ecx, dword ptr [ebp-10] :71A21B53 51 push ecx :71A21B54 FF7508 。

4. 如何HOOK任意函數

This HOWTO deals with pre-hooks. For details on post-hooks, see 如何安全的Post-Hook一個函數.

For more information on the actual hooking of functions, see 如何Hook一個函數.

你通常這樣使用麼

Meet Joe Average Hook:

local orig_foo = foo

function foo(a1, a2)

-- some code that looks at a1

return orig_foo(a1, a2)

end

問題在於這個方法只能處理固定數目的參數, 如果方法的API改變了, 將導致無法使用. 幸運的是我們有辦法使他繼續工作.

Blizzard's APIs do change from time to time!

使用安全的方式

local orig_foo = foo

function foo(a1, )

--do something with a1

return orig_foo(a1, )

end

這樣確保了所有的參數會傳遞到原始方法中, 即便你不知道具體有多少個參數. 同樣確保了所有返回值都能正確返回. 另一個好處是, 我們使用了局部變量來儲存原始方法並做了一個適當的尾調用可以帶來更好的性能, 從而爲我們的hook做了最小化的付出.

會帶來巨大的性能影響麼?

在WoW-2.0以前的設計中, 使用unpack(), 在每次hook被調用時創建一個垃圾回收表. 在新的設計中改進了, 使用''變量, 去掉了垃圾回收這部分源碼. 在Lua5.1中, 在每次hook調用時包括傳參和返回值都不會浪費表的內存.

5. 誰能比較詳細的介紹一下Hook的概念和使用方法

HOOK,我的懂得是,一個體系函數調用的用戶函數,一般情況下,都是有應用軟件調用體系函數來實現所需的功能,然則在某些情況下,比如體系須要嚮應用軟件發送的資訊量比較大年夜,或者是要交互的發送資訊,這個時或就須要應用軟件寫一個本身的函數,給體系調用,經由過程這個函數的參數體系向法度榜樣發送法度榜樣請求的資訊,經由過程參數法度榜樣也可以影響體系下一步發送的資訊。

在很多的情況下,HOOK函數都是在調用這個函數的過程中執行的,而不是在應用法度榜樣的過程中,所以HOOK函數的請求很高,不要破壞調用過程。在HOOK函數執行時,應用法度榜樣過程往往是濁宣的,也就是HOOK函數耗用的是應用法度榜樣的CPU時光,而不是調用過程的,即使調用過程此時也是濁宣的,但這不是絕對的,所以在某些情況下還要推敲和主過程的同步問題,最典範的是SetWindowsHookEx()函數設定的HOOK,HOOK函數必須在DLL中,全部DLL都被裝入IE的過程中,要大年夜HOOK函數返回資訊給應用法度榜樣必須要經由過程一些例如MappingFile,Pipe等過程間通信的方法,還要留意過程間拜訪同一數據的同步。

6. 如何hook某一個shell命令

方法一:切換到shell腳本所在的目錄(此時,稱爲工作目錄)執行shell腳本:

複製代碼代碼如下:

cd /data/shell

./hello.sh

./的意思是說在當前的工作目錄下執行hello.sh。如果不加上./,bash可能會響應找到不到hello.sh的錯誤資訊。因爲目前的工作目錄(/data/shell)可能不在執行程序默認的搜尋路徑之列,也就是說,不在環境變量PASH的內容之中。檢視PATH的內容可用 echo $PASH 命令。現在的/data/shell就不在環境變量PASH中的,所以必須加上./纔可執行。

方法二:以絕對路徑的方式去執行bash shell腳本:

複製代碼代碼如下:

/data/shell/hello.sh

方法三:直接使用bash 或sh 來執行bash shell腳本:

複製代碼代碼如下:

cd /data/shell

bash hello.sh

複製代碼代碼如下:

cd /data/shell

sh hello.sh

注意,若是以方法三的方式來執行,那麼,可以不必事先設定shell的執行權限,甚至都不用寫shell檔案中的第一行(指定bash路徑)。因爲方法三是將hello.sh作爲參數傳給sh(bash)命令來執行的。這時不是hello.sh自己來執行,而是被人家調用執行,所以不要執行權限。那麼不用指定bash路徑自然也好理解了啊,呵呵……。

方法四:在當前的shell環境中執行bash shell腳本:

複製代碼代碼如下:

cd /data/shell

. hello.sh

複製代碼代碼如下:

cd /data/shell

source hello.sh

前三種方法執行shell腳本時都是在當前shell(稱爲父shell)開啓一個子shell環境,此shell腳本就在這個子shell環境中執行。shell腳本執行完後子shell環境隨即關閉,然後又回到父shell中。而方法四則是在當前shell中執行的。

Tags:hook