CodeZine(コードジン)

特集ページ一覧

SEXYHOOKの実装部
とある関数の接合部(2)

関数、クラスメソッド、APIをフックする方法

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2010/03/02 14:00

ダウンロード sexyhook0.8 (80.0 KB)

目次

関数はどうやって呼び出されるか?

 フックの肝の部分はこれでおしまいなのですが、書き換えを行っているSEXYHOOKFuncBase::FunctionHookFunction関数の上の方はまだ説明していません。

 この上のほうで何をやっているのかですが、フックルーチンと書き換える関数の位置の特定を行っています。

 現在のアーキテクチャでは、実行されるプログラムはメモリのどこかにマッピングされるはずなので、どこかに関数の実態があり、それを呼び出しているはずです。この呼び出しには大きく3つのパターンがあるようです。

 以下の例をご覧ください。

//呼び出し側
95:       int a = add(1,2);
0040145D   push        2
0040145F   push        1
00401461   call        @ILT+70(add) (0040104b) ←
00401466   add         esp,8
00401469   mov         dword ptr [a],eax


//呼び出される関数
6:    int add(int a,int b)
7:    {
00401220   push        ebp
00401221   mov         ebp,esp
8:        return a + b;
00401223   mov         eax,dword ptr [a]
00401226   add         eax,dword ptr [b]
9:    }
00401229   pop         ebp
0040122A   ret

 教科書どおりにいうなら、引数をまずスタックに積んで、関数をcallし、結果はeaxレジスタで戻されるという感じでしょうか。しかし、よく見るとcallされたアドレスとadd関数が始まっているアドレスが違います。callされたのは、0040104bアドレスで、add関数が始まっているのは、00401220アドレスです。

関数呼び出し1:ILTを経由する場合

 一度ジャンプテーブル(ILT)を経由して関数が呼ばれるときがあります。先ほどのadd関数は、このようにILTが途中に入っています。

//呼び出し側
95:       int a = add(1,2);
0040145D   push        2
0040145F   push        1
00401461   call        @ILT+70(add) (0040104b)
00401466   add         esp,8
00401469   mov         dword ptr [a],eax

↓

@ILT+70(?add@@YAHHH@Z):
0040104B   jmp         add (00401220)

↓

//呼び出される関数
6:    int add(int a,int b)
7:    {
00401220   push        ebp
00401221   mov         ebp,esp
8:        return a + b;
00401223   mov         eax,dword ptr [a]
00401226   add         eax,dword ptr [b]
9:    }
00401229   pop         ebp
0040122A   ret

 関数のポインタvoid*p=&add;で取得されるアドレスは、ILTの方の0040104Bになります。

 SEXYHOOKでは、必ず関数本体を上書きしたいので、このような処理が行われていればアドレスを再計算し、関数本来の位置を見つけています。

 ILTを経由しているか否かの判定は結構いい加減で、(void*)&add等で取得した関数ポインタの先頭が0xe9(JMP命令)で始まっていれば、ILTを経由していると判断してアドレスを再計算しています。

uintptr_t overraideFunctionAddr = 0;
if (*((unsigned char*)inFunctionAddress+0) == 0xe9)
{
        //フック関数も ILT経由で飛んでくる場合
        //0xe9 call [4バイト相対アドレス]
        uintptr_t jmpaddress = *((uintptr_t*)((unsigned char*)inFunctionAddress+1));
        overraideFunctionAddr = (((uintptr_t)inFunctionAddress) + jmpaddress) + 5;      //+5は e9 00 00 00 00 (ILTのサイズ)

}
else
{
        //即、プログラム領域に飛んでくる場合
        overraideFunctionAddr = (uintptr_t)inFunctionAddress;
}

  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:「SEXYHOOK」 とある関数の接合部

著者プロフィール

  • rti(あーるてぃーあい)

    働いたら負けだと思っていた元ニートのプログラマ 歌って踊れてさくらたんにもハァハァできます。 love:C++,アセンブラ,PHP,javascript好きのOO厨房 低レイヤープログラムやネットワークサーバからサーバサイドプログラム、ソフトウェア設計、インフラ設計運用までと幅広くやってます。...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5