SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

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

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

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

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード 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;
}

次のページ
関数呼び出し2:直接関数が呼ばれる場合

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
「SEXYHOOK」 とある関数の接合部連載記事一覧
この記事の著者

rti(あーるてぃーあい)

働いたら負けだと思っていた元ニートのプログラマ歌って踊れてさくらたんにもハァハァできます。love:C++,アセンブラ,PHP,javascript好きのOO厨房低レイヤープログラムやネットワークサーバからサーバサイドプログラム、ソフトウェア設計、インフラ設計運用までと幅広くやってます。多分設計信者。 あんまり得意ではないけど 人工知能(学習エンジン)とかシステム...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/4883 2010/03/03 17:59

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング