- 论坛徽章:
- 0
|
Apache Hook 结构分析(三)
杨学刚
2009-3-18
xuegangyang@eyou.com
一、简介 1
二、Hook array结构分析 2
三、Hook 函数分析 3
3.1 hook函数实现 3
3.2 Run函数实现 4
3.2.1 FIRST处理流程对应的run函数定义 4
3.2.2 ALL处理流程对应的run函数定义 5
3.2.3 VOID处理流程对应的run函数定义 5
3.3 get_hook函数实现 6
四、HOOK宏分析 6
4.1 HOOK_STRUCT宏分析 6
4.2 EXTERNAL_HOOK宏分析 7
4.3 VOID宏分析 7
4.4 RUN_ALL宏分析 8
4.5 RUN_FIRST宏分析 9
4.6 使用宏定义HOOK 10
五、HOOK定义扩展 10
六、小结和思考 11
4.4 RUN_ALL宏分析
RUN_ALL宏用于实现处理流程为ALL时的run函数,其源码如下:
#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \
APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \
link##_DECLARE(ret) ns##_run_##name args_decl \
{ \
ns##_LINK_##name##_t *pHook; \
int n; \
ret rv; \
\
if(!_hooks.link_##name) \
return ok; \
\
pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \
for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \
{ \
rv=pHook[n].pFunc args_use; \
\
if(rv != ok && rv != decline) \
return rv; \
} \
return ok; \
}
|
以上用到的APR_IMPLEMENT_EXTERNAL_HOOK_BASE宏和在VOID中用到一样功能。
4.5 RUN_FIRST宏分析
RUN_ALL宏用于实现处理流程为FIRST时的run函数,其源码如下:
#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ns,link,ret,name,args_decl,args_use,decline) \
APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \
link##_DECLARE(ret) ns##_run_##name args_decl \
{ \
ns##_LINK_##name##_t *pHook; \
int n; \
ret rv; \
\
if(!_hooks.link_##name) \
return decline; \
\
pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \
for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \
{ \
rv=pHook[n].pFunc args_use; \
\
if(rv != decline) \
return rv; \
} \
return decline; \
}
|
以上用到的APR_IMPLEMENT_EXTERNAL_HOOK_BASE宏和在VOID中用到一样功能。
4.6 使用宏定义HOOK
经过以上分析的以后,如果要实现HOOK将会变得比较简单,只需按照顺序依次调用三个宏即可完成HOOK的定义,与上文相同,假设要实现example HOOK,其定义源码如下:
APR_HOOK_STRUCT(
APR_HOOK_LINK(example)
)
APR_DECLARE_EXTERNAL_HOOK(ap,AP,int,example,(apr_pool_t *pconf,apr_pool_t *plog,
apr_pool_t *ptemp,server_rec *s))
// 假设对应的处理方式为 ALL
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ap,AP,int, example,
(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s),
(pconf, plog, ptemp, s), OK, DECLINED) |
五、HOOK定义扩展
在以上分析中说过每一个HOOK都对应一个_hooks变量,如果在同一个编译单元里我们两次使用HOOK_STRUCT宏定义example1和example2 HOOK,岂不是会存在两个_hooks变量,这将导致编译错误,如果在同一编译单元中需要定义两个HOOK,就需要用到HOOK的扩展定义方式。假如要定义example1和example2 HOOK,可以按照以下方式进行定义:
APR_HOOK_STRUCT(
APR_HOOK_LINK(example1)
APR_HOOK_LINK(example2)
) |
以上宏定义展开后的源码如下:
static struct {
apr_array_header_t * link_example1;
apr_array_header_t * link_example2;
} _hooks; |
如此就在一个_hooks变量中定义了两个HOOK array,其中一个用于example1 HOOK,另外一个用于example2,之后需要使用两次
APR_DECLARE_EXTERNAL_HOOK宏来分别定义example1和example的hook函数和element类型,同样也需要使用两次APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL宏来定义run函数,其源码如下:
APR_DECLARE_EXTERNAL_HOOK(ap,AP,int,example1,(apr_pool_t *pconf,apr_pool_t *plog,
apr_pool_t *ptemp,server_rec *s))
// 假设对应的处理方式为 ALL
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ap,AP,int, example2,
(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s),
(pconf, plog, ptemp, s), OK, DECLINED)
APR_DECLARE_EXTERNAL_HOOK(ap,AP,int,example2,(apr_pool_t *pconf,apr_pool_t *plog,
apr_pool_t *ptemp,server_rec *s))
// 假设对应的处理方式为 ALL
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ap,AP,int, example2,
(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s),
(pconf, plog, ptemp, s), OK, DECLINED) |
至此便解决了同一编译单元定义多个HOOK的问题,笔者称此方法为HOOK扩展(也许不恰当,但没有想到更好方法)。虽然如此,疑惑也随之而来,这样定义的HOOK是一个HOOK还是两个HOOK?我想暂且称之为HOOK组吧,虽然他们由同一个HOOK_STRUCT定义,并且通过同一个_hooks 变量管理。
六、小结和思考
Apache HOOK目的是为了能让用户开发的模块注入到apache处理流程中,其核心在于函数指针的应用,笔者也接触过C++中的多态开发,通过使用多态可以避免函数指针的使用,而且可以使系统结构更加简单,但我想可能是C++多态开销太高,开发人员没有采用吧。
以前只学过C++,没有太多接触过C 语言,虽然二者相通,可在看源代码中发现,二者对程序的组织以及语言的应用完全不一样,apache中的HOOK 宏就耗去了我一个周的时间,而且在VC中宏是没有办法debug调试执行的,只好手工把宏进行替换,之后用自己替换后的函数进行debug才弄懂程序执行流程,不经感慨要是有一个宏替换的小软件该多好啊!
我研究生导师有一句诗:“才别夕阳又见朝阳”,感觉刚刚开了电脑写文档,倏忽已是日别西山,手中方才调整好本文格式,不经感慨古人写书之艰辛与执着,批阅十载,增删五次,方成红楼,而我辈电脑词霸一应俱全,google搜索时刻相随,却提笔踌躇,不知所书。虽如此,我辈阅大牛之源码,亦应有所得,有所得便应有所录,有所录方能河海不择细流 故能就其深。 |
|