LoginSignup
2
2

More than 1 year has passed since last update.

EasyHookで簡単にインラインフックする

Last updated at Posted at 2022-02-28

EasyHook とは

以下の2点を与えるだけでインラインフック(Detour)を行える関数を提供してくれるライブラリ。

  • フックする関数のアドレス
  • フックした後実行されるオリジナルの関数へのポインタ

手動でやる場合、トランポリンのコードをレジスタの整合性を考えながら書かないといけなかったり、アンフックする時に元のコードを覚えて置いたりしないといけなかったりするが、その手間を省ける。
Visual C# (マネージドコード)普通のC++ (アンマネージドコード) どちらでも使える。

EasyHook のダウンロード

EasyHookを導入するには二通りのやり方がある。

  1. Visual Studio の NuGetパッケージマネージャー を使ってインストールする方法
  2. 手動でバイナリをダウンロードし、includeパスを通したりして使う方法

自分 (visual Studio 2019 の DLLプロジェクト) は1の方法だと上手く行かなかったので、この記事では2の方法を使う

EasyHookのダウンロードリンクから、下記のように Binaries って書いてある最新版のをダウンロードする。ダウンロード場所は後でVisualStudioでincludeパスを追加する時にそこを指定するので、覚えていれば何でも良い。
image.png

Visual Studio で EasyHook を使うための設定

VisualStudioを立ち上げ、C++のDLLのプロジェクトを立ち上げる。
image.png
立ち上げた後、以下の用にしてソリューションのプロパティ画面を開き、インクルードディレクトリを編集する。
image.png
先ほどダウンロードしたEasyHookのフォルダの中に、NetFX3.5 というフォルダがあるはずなので、そこへのパスを追加する。
image.png
同様にして、ライブラリディレクトリも編集し、上記と同じパスを追加する。
image.png
終ったら、これはEasyHookとは関係ないが、構成プロパティ > 詳細 > 文字セット の所を「マルチバイト文字セットを使用する」に変えて置く。

サンプルプログラム

※ このサンプルは、本家のチュートリアルを参考にしています。
まず、上記の工程が上手く行ってるかどうかを確かめるために、以下のように include文を追加し、赤線が出ない事を確認しましょう。
image.png
ちなみに上図で分かる通り、今回は32bitのDLLでビルドします。
iostream は、EasyHookのフックが失敗した時のエラー文を表示するに、エラー文の文字列の型変換とかするのに使うので入れてます。

全体のサンプルプログラムは以下になります。

#include "pch.h"
#include <iostream>
#include <easyhook.h>
#pragma comment(lib, "EasyHook32.lib")

using namespace std;

BOOL WINAPI myBeepHook(DWORD dwFreq, DWORD dwDuration)
{
    MessageBox(NULL, "called from myBeepHook!", "success", MB_OK);
    return Beep(dwFreq + 800, dwDuration);
}

DWORD WINAPI ThreadMain(LPVOID params) {
    HOOK_TRACE_INFO hHook = { NULL };
    void* pBeep = GetProcAddress(GetModuleHandle("kernel32"), "Beep");

    Beep(500, 500); // フック前のBeep呼び出し

    // 1: フックの用意
    NTSTATUS res = LhInstallHook(pBeep, myBeepHook, NULL, &hHook);
    if (FAILED(res)) {
        wstring s(RtlGetLastErrorString());
        MessageBoxW(NULL, s.c_str(), L"error", MB_OK);
        return -1;
    }
    
    // 2: フックの有効化 (ここでフックされる)
    ULONG ACLEntries[1] = { 0 };
    LhSetInclusiveACL(ACLEntries, 1, &hHook);

    Beep(500, 500); // フック後のBeep呼び出し

    // 3: アンフック
    LhUninstallHook(&hHook);
    LhWaitForPendingRemovals(); // アンフックが完了するまで待つ
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        CreateThread(0, 0, ThreadMain, hModule, 0, 0);
    }
    return TRUE;
}

ビルドと実行

ビルド自体は Ctrl-b すればできますが、ビルド後にやるべき事があります。
ビルドした出力結果のDLLがあるディレクトリに、EasyHook32.dllを入れる必要があります。EasyHook32.dllは、インクルードディレクトリで指定したパス(NetFX3.5フォルダの中) にあります。
image.png
これを上図のように入れた後、以下のようにして実行してみましょう。以下のようにメッセージボックスが表示されればOKです。
image.png
※ rundll32.exeは任意のDLLを実行するためのアプリですが、カンマの後ろにエクスポート関数を指定する必要があり、今回はDLLMainしか要らないため、適当にhogeを入れてるのでエラーが出てますが、気にしなくて大丈夫です。

2
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2