当前位置:科普知识站>综合知识>

hook怎么写

综合知识 阅读(2.16W)
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中执行的。