當前位置:生活全書館 >

綜合知識

> hook怎麼寫

hook怎麼寫

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中執行的。

標籤: hook
  • 文章版權屬於文章作者所有,轉載請註明 https://shqsg.com/zonghezhishi/6yx0rz.html