Hook関数
フック(Hook)関数とやらについて。
バイトで使う機会があったので、メモがてら。
- フック(Hook)
- プログラム中の特定の箇所に、利用者が独自の処理を追加できるようにする仕組みである
サンプルコード(C言語)
以下Intel x86系アーキテクチャについてのコード、コンパイラはgccとする。
#include#define HOOK __asm__ volatile ("movl %%ebp, %0":"=r"(ebp_buf):); \ ret_addr = (unsigned int *)ebp_buf[1]; \ ebp_buf[1] = (unsigned int)hook; unsigned int *ebp_buf; unsigned int *ret_addr; void hook(){ int z; __asm__ volatile ("movl %%eax, %0":"=r"(z):); z=z*2; printf("hook!\n"); __asm__ volatile ("movl %0 ,%%eax"::"r"(z)); __asm__ volatile ("movl %0 ,%%ebx"::"m"(ret_addr)); __asm__ volatile ("movl %%ebp, %%esp"::); __asm__ volatile ("popl %%ebp"::); __asm__ volatile ("jmp *%ebx"); } int func(){ int x,y,z; HOOK; x=2; y=3; z=x+y; return z; } int main(){ int z = func(); printf("z = %d\n",z); return 0; }
ややこしやーですね。
実行結果
[hat-tun@mimo]% ./a.out [~/algorithm] hook! z = 10
簡単に説明
main関数
まずmain関数はfunc関数を呼んで、その返り値を表示してるだけですね。
func関数
次にfunc関数ですが、これも一見ただ単に2+3の足し算をしてその答えを
returnしてるだけです。
が、しかし、func内でHOOKなるマクロが使われております。
HOOKマクロ
ここがミソですね。
インラインアセンブリ言語を使って、こねこねします。
大域変数ebp_bufにebpレジスタ(ベースポインタ)の情報をコピーし、
ret_addrに関数のリターンアドレス*1をコピーしたのち、
リターンアドレスをhook関数の存在するアドレス*2
に上書きしてます。
具体的に言うと、func関数実行中のベースポインタをとっておき、
func関数がreturnした後に戻るリターンアドレス、つまりここでは
main関数内でzに値を代入するところらへんのアドレスを退避させておき、
func内でreturnしたらhook関数へ飛ぶようにしてるわけです。
hook関数
フック関数本体です、ここに追加で行いたい処理なんかを書いちゃうわけです。
ここでは、return値を2倍するという操作をしています。
return値はeaxレジスタに入ってるので、それを変数zに取り出して、
計算してまたeaxに戻す。
そして、さっき退避しておいたベースポインタとリターンアドレスを戻し、
funcの帰るべきだったリターンアドレスへジャンプします。
HOOKの一言で、制御を奪えるので、これを引っ掛ける意味でフックというそうです。
だいぶテクニカルですね。
デバッグなんかに使えるらしいですが、
ただ実際こいつがどんだけすごい能力持ってるのかは、
わかりきってませんね。 精進します。
でも、何かの参考になれば。
インラインアセンブリについてはここを参考しました。
gccのx86インラインアセンブリに関して