質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.59%

APIを使用したプロセスを特定したい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 184

どのプロセスがユーザが指定したAPIを使用したのか確認を行う,APIの使用履歴を確認できるツールを探しています.

API Monitorが目的に近いようですが,API Monitorは指定したプロセスがどのAPIを使用しているかということしかわかりません.

普通にパソコンを使っているときの情報を取得したいため,特別な作業をしていない時のAPI使用履歴を知りたいです.

現在はツールが見つからないため,c++で自作していますがうまくいってないです.
自作のコードでは対象のAPIのIATを書き換えてグローバルにフックしようとしています.
以下にコードを記します.このコードの改善方法がわかる方がいたら訂正していただきたいです.

fp_MessageBoxW MessageBoxWPtr = NULL;
TCHAR fileNameBuf[MAX_PATH]=("not complete");

//書き換える関数(MessageBoxW)の定義
int
WINAPI
HookedMessageBoxW(
    HWND   hWnd,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT   uType
)
{
    OutputDebugString(TEXT("HookedMessageBoxW!\n")); //デバックビューに出力
    return MessageBoxWPtr(hWnd,lpText,lpCaption,uType); //元の関数を呼び出す
}




void APIHook() {
    if (GetModuleFileName(GetModuleHandle(NULL), fileNameBuf, MAX_PATH) > 0) {
            MessageBoxWPtr = (fp_MessageBoxW)RewriteFunction("User32.dll", "MessageBoxW", HookedMessageBoxW);
            }
    }
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  dwReason,
                       LPVOID lpReserved
                     )
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        DisableThreadLibraryCalls(hModule);
        APIHook();
    }
    return TRUE;
}
void* RewriteFunctionImp(const char* szRewriteModuleName, const char* szRewriteFunctionName, void* pRewriteFunctionPointer)
{
    for (int i = 0; i < 2; i++) {
        // ベースアドレス
        intptr_t pBase = 0;
        if (i == 0) {
            if (szRewriteModuleName) {
                pBase = (intptr_t)::GetModuleHandleA(szRewriteModuleName);
            }
        }
        else if (i == 1) {
            pBase = (intptr_t)GetModuleHandle(NULL);
        }
        if (!pBase)continue;

        // イメージ列挙
        ULONG ulSize;
        PIMAGE_IMPORT_DESCRIPTOR pImgDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData((HMODULE)pBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
        for (; pImgDesc->Name; pImgDesc++) {

            const char* szModuleName = (char*)(intptr_t)(pBase + pImgDesc->Name);

            PIMAGE_THUNK_DATA pFirstThunk = (PIMAGE_THUNK_DATA)(intptr_t)(pBase + pImgDesc->FirstThunk);
            PIMAGE_THUNK_DATA pOrgFirstThunk = (PIMAGE_THUNK_DATA)(intptr_t)(pBase + pImgDesc->OriginalFirstThunk);
            // 関数列挙

            for (; pFirstThunk->u1.Function; pFirstThunk++, pOrgFirstThunk++) {

                if (IMAGE_SNAP_BY_ORDINAL(pOrgFirstThunk->u1.Ordinal))continue;
                PIMAGE_IMPORT_BY_NAME pImportName = (PIMAGE_IMPORT_BY_NAME)(intptr_t)(pBase + (intptr_t)pOrgFirstThunk->u1.AddressOfData);
                if (!szRewriteFunctionName) {
                    // 表示のみ
                    printf("Module:%s Hint:%d, Name:%s\n", szModuleName, pImportName->Hint, pImportName->Name);
                }
                else {

                    // 書き換え判定
                    if (stricmp((const char*)pImportName->Name, szRewriteFunctionName) != 0)continue;

                    // 保護状態変更
                    DWORD dwOldProtect;
                    if (!VirtualProtect(&pFirstThunk->u1.Function, sizeof(pFirstThunk->u1.Function), PAGE_READWRITE, &dwOldProtect))
                        return NULL; // エラー
                    //OutputDebugString(pImportName->Name);
                    MessageBoxW(NULL, wc, wc, MB_OK);
                    // 書き換え
                    void* pOrgFunc = (void*)(intptr_t)pFirstThunk->u1.Function; // 元のアドレスを保存しておく
                    WriteProcessMemory(GetCurrentProcess(), &pFirstThunk->u1.Function, &pRewriteFunctionPointer, sizeof(pFirstThunk->u1.Function), NULL);
                    pFirstThunk->u1.Function = (intptr_t)pRewriteFunctionPointer;

                    // 保護状態戻し
                    VirtualProtect(&pFirstThunk->u1.Function, sizeof(pFirstThunk->u1.Function), dwOldProtect, &dwOldProtect);
                    return pOrgFunc; // 元のアドレスを返す
                }
            }
        }
    }
    return NULL;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

まず一点、

return pOrgFunc; // 元のアドレスを返す

この部分で return をしてしまっているので、一つのthunkを書き換えた時点で RewriteFunctionImp の処理が終了してしまうように見えます。実際は、各モジュールごとにIATが存在するため、例えばUser32.dllのMessageBoxWを書き換えようとしてこの関数を呼んだ場合、書き換えが行われるのはUser32.dllのIATだけであり、例えば実行ファイル本体のIATは書き換えが行われず、Hookを経由することもなくなってしまうのではないでしょうか。

次に、

for (int i = 0; i < 2; i++) {

このループでは szRewriteModuleName に渡された名前のモジュールと、実行ファイル本体だけを対象にしていますが、実際は実行ファイルの読み込んだ全てのモジュールから監視したいAPIが呼ばれている可能性があり、他のモジュール内部からのAPI呼び出しはそのモジュールのIATを経由するはずです。
そのため、全てのAPI呼び出しをフックするには、CreateToolhelp32Snapshotなどを利用して読み込まれた全モジュールを列挙し、それぞれのIATを書き換える必要があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/10/28 13:50

    IATの仕組みについて理解が足りてませんでした.
    もっと勉強しようと思います.
    回答ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る