Apache中大量使用了Hook机制,使得第三方开发Module可以扩展Apache服务器的默认处理。
Apache Hook功能可以简述如下:
1. 程序主框架根据名称声明和定义Hook
2. 第三方Module通过实现和挂载Hook来扩展主框架的行为。
3. 程序主框架在某些操作发生时显示触发Hook
例如,Apache的事务日志(也即访问日志)就是用Hook机制实现的,对应上面的3个环节如下:
1. 在Apache核心代码protocol.c中定义了名为log_transaction的Hook:
APR_HOOK_STRUCT(
…
APR_HOOK_LINK(log_transaction)
…
)
…
AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction,
(request_rec *r), (r), OK, DECLINED)
2. 可选模块mod_log_config通过挂载Hook来扩展主程序的行为:
static void register_hooks(apr_pool_t *p)
{
…
ap_hook_log_transaction(multi_log_transaction,NULL,
NULL,APR_HOOK_MIDDLE);
…
}
3. 在Apache的核心流程ap_process_request函数中显式触发了该Hook:
void ap_process_request(request_rec *r)
{
…
ap_run_log_transaction(r)
…
}
上述机制是如何实现的呢,在此先做一个简单的描述:
1. 首先,Hook的基础实现是在apr库中,由apr_hooks.h和apr_hooks.c两个源文件来实现,这两个文件定义了大量的宏,并实现了一系列查找,排序相关的函数。
2. 其次,Hook是根据名字定义出来的,本例可以看作一个名为log_transaction的Hook。
3. 再其次,Hook通过apr_hooks.h中提供的宏被定义,这些宏扩展开来以后,将产生多个函数和结构——本例中看到的ap_run_log_transaction函数和ap_hook_log_transaction函数就是这些宏定义出来的。
我们就以log_transaction为例,来看一下Apache对此Hook的实现。
(一)声明和定义
本小结暂时不对各个函数的流程进行解释,只是先说明Apache如何通过宏来产生Hook所需函数和结构的声明和定义。
声明位于http_protocol.h文件中:
AP_DECLARE_HOOK(int,log_transaction,(request_rec *r))
这个宏展开以后如下:
typedef int ap_HOOK_log_transaction_t (request_rec *r);
AP_DECLARE(void) ap_hook_log_transaction(ap_HOOK_log_transaction_t *pf,
const char *const *aszPre,
const char * const *aszSucc, int nOrder);
AP_DECLARE(int) ap_run_log_transaction (request_rec *r);
AP_DECLARE(apr_array_header_t *) ap_hook_get_log_transaction(void);
typedef struct ap_AP_log_transaction_t {
ap_HOOK_log_transaction_t *pFunc;
const char *szName;
const char * const *aszPredecessors;
const char * const *aszSuccessors;
int nOrder;
} ap_AP_log_transaction_t;
也即声明了三个函数,并定义了一个函数指针类型和一个结构。上述三个函数的定义位于protocol.c文件的代码中,也是由一个宏来定义:
AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction,
(request_rec *r), (r), OK, DECLINED)
此宏展开以后如下:
AP_DECLARE(void) ap_hook_log_transaction(ap_HOOK_log_transaction_t *pf,
const char *const *aszPre,
const char * const *aszSucc, int nOrder)
{
ap_AP_log_transaction_t *pHook;
if(!_hooks.link_log_transaction)
{
_hooks.link_log_transaction=apr_array_make(apr_hook_global_pool,
1,
sizeof(ap_AP_log_transaction_t));
apr_hook_sort_register(log_transaction,&_hooks.link_log_transaction);
}
pHook=apr_array_push(_hooks.link_log_transaction);
pHook->pFunc=pf;
pHook->aszPredecessors=aszPre;
pHook->aszSuccessors=aszSucc;
pHook->nOrder=nOrder;
pHook->szName=apr_hook_debug_current;
if(apr_hook_debug_enabled)
apr_hook_debug_show(log_transaction,aszPre,aszSucc);
}
AP_DECLARE(apr_array_header_t *) ap_hook_get_log_transaction(void);
{
return _hooks.link_log_transaction;
}
AP_DECALRE(int) ap_run_log_transaction (request_rec *r)
{
ap_AP_log_transaction_t *pHook;
int n;
ret rv;
if(!_hooks.link_log_transaction)
return ok;
pHook=(ap_AP_log_transaction_t *)_hooks.link_log_transaction->elts;
for(n=0 ; n < _hooks.link_log_transaction->nelts ; ++n)
{
rv=pHook[n].pFunc (r);
if(rv != ok && rv != decline)
return rv;
}
return ok;
}
这里用到了一个静态变量_hooks,这个变量也是由宏定义出来的,在protocol.c文件的最开始:
APR_HOOK_STRUCT(
APR_HOOK_LINK(post_read_request)
APR_HOOK_LINK(log_transaction)
APR_HOOK_LINK(http_scheme)
APR_HOOK_LINK(default_port)
)
此宏展开以后如下:
static struct {
apr_array_header_t* link_post_read_request;
apr_array_header_t* link_log_transaction;
apr_array_header_t* link_http_scheme;
apr_array_header_t* link_default_port;
} _hooks;
也即声明了一个拥有4个成员(每个成员都是一个数组)的匿名结构,并用此结构定义了一个名为_hooks的静态变量。
(二)触发
触发是由ap_run_log_transaction函数实现的:
AP_DECALRE(int) ap_run_log_transaction (request_rec *r)
{
ap_AP_log_transaction_t *pHook;
int n;
ret rv;
if(!_hooks.link_log_transaction)
return ok;
pHook=(ap_AP_log_transaction_t *)_hooks.link_log_transaction->elts;
for(n=0 ; n < _hooks.link_log_transaction->nelts ; ++n)
{
rv=pHook[n].pFunc (r);
if(rv != ok && rv != decline)
return rv;
}
return ok;
}
此函数遍历静态变量_hooks的成员link_log_transaction(类型为apr_array_header_t*,是Apache内部使用的数组),并根据数组每个元素中的函数指针进行函数调用——此函数指针指向各个模块挂载到此Hook上的函数。
值得注意的是for循环中的条件语句——如果钩子函数的返回值既不是ok也不是decline,则终止循环,直接退出。
(三)挂载
挂载由函数ap_hook_log_transaction函数实现:
AP_DECLARE(void) ap_hook_log_transaction(ap_HOOK_log_transaction_t *pf,
const char *const *aszPre,
const char * const *aszSucc, int nOrder)
{
ap_AP_log_transaction_t *pHook;
if(!_hooks.link_log_transaction)
{
_hooks.link_log_transaction=apr_array_make(apr_hook_global_pool,
1,
sizeof(ap_AP_log_transaction_t));
apr_hook_sort_register(“log_transaction”, &_hooks.link_log_transaction);
}
pHook=apr_array_push(_hooks.link_log_transaction);
pHook->pFunc=pf;
pHook->aszPredecessors=aszPre;
pHook->aszSuccessors=aszSucc;
pHook->nOrder=nOrder;
pHook->szName=apr_hook_debug_current;
if(apr_hook_debug_enabled)
apr_hook_debug_show(log_transaction,aszPre,aszSucc);
}
此函数先检查静态变量_hooks中的成员link_log_transaction是否为空,如果为空则创建一个初始大小为1的数组。然后往此数组中添加一个元素。
(四)综述
综上所述,对log_transaction这个Hook的具体实现和使用如下:
1. 框架定义静态结构变量_hooks,其成员link_log_transaction用于存放log_transaction相关的Hook。
2. 框架声明和定义Hook所需的函数:
a) ap_hook_log_transaction,此函数的功能是将一个函数指针(注册)添加到对应的Hook数组中。
b) ap_run_log_transaction,此函数的功能是执行一个Hook数组中的所有已注册函数。
3. 模块mod_log_config通过ap_hook_log_transaction注册(添加)自己的日志扩展函数multi_log_transaction
4. 框架调用ap_run_log_transaction,此时multi_log_transaction将会被执行。
分享到:
相关推荐
c++ hook 全局钩子 全局键盘钩子
键盘钩子 hook 键盘钩子 hook 键盘钩子 hook 键盘钩子 hook 键盘钩子 hook 键盘钩子 hook 键盘钩子 hook 键盘钩子 hook
Hook钩子Hook钩子Hook钩子Hook钩子,取得当前消息钩子处理
VB Hook 钩子 键盘钩子 源代码VB Hook 钩子 键盘钩子 源代码
DELPHI编写的HOOK API实现DLL全局钩子启动记事本的程序-.rar DELPHI编写的HOOK API实现DLL全局钩子启动记事本的程序-.rar
PB串口通讯数据监控,使用钩子HOOK API
apihook完整源代码 钩子(HOOK) > apihook完整源代码 钩子(HOOK) >
API Hook基本原理和实现,钩子的特性
本资源使用VS2015开发,QT版本5.10,截取处理Windows消息,HOOK鼠标键盘,获取所有按键信息,可区分鼠标侧键及滚轮上下滚动消息。
hook钩子简单实例 hook钩子简单实例 hook钩子简单实例 hook钩子简单实例
通过执行远程线程,实现向系统内的进程注入远程代码,来完成hook功能,具有很强的稳定性
钩子函数,顾名思义,就是把我们自己实现的hook函数在某一时刻挂接到目标挂载点上。 1. hook函数,就是我们自己实现的函数,函数类型与挂载点匹配(返回值,参数列表) 2. 挂接,也就是hook或者叫注册(register...
DELPHI编写的HOOK API实现DLL全局钩子启动记事本的程序-DELPHI prepared HOOK API to achieve the overall hook DLL procedures start Notepad
Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子Hook 钩子 例子
Hook(钩子)的简单实现例子
利用API Hook截获CreateFile和CloseHandle达到加解密DOC文件和防拷贝的目的 visual c++调用hook API钩子截获CreateFile和CloseHandle来加密WORD文件+实现文件防拷贝
c++钩子函数:copy hook c++调用钩子函数监视复制文件操作
Hook经典分析 关于QQ Hook的应用 钩子
hook 钩子 技术 hook 钩子 技术 hook 钩子 技术hook 钩子 技术hook 钩子 技术
老外写的sockethook代码 实现socket钩子,提供hook代码和测试例程序-Written by foreigners sockethook hook socket code to provide hook procedure code and test cases