Apache Hook 結構分析(三)
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搜索時刻相隨,卻提筆躊躇,不知所書。雖如此,我輩閱大牛之源碼,亦應有所得,有所得便應有所錄,有所錄方能河海不擇細流 故能就其深。
《解決方案》
好文 頂 清晰 清晰