windows_他のソフトのメッセージボックスを変更してみる

前回は同一プロセス内のメッセージボックスの内容を変更したので、今回は別プロセスのメッセージボックスの内容を変更したいと思います。ただし、今回の方法は対策を取るのが可能なようで再現できるかどうかはソフトによるような感じです。

まず、setWindowsHookExの公式のドキュメントを確認してみると、lpfnのパラメータの説明としてdwThreadIDパラメータで0(すべてのスレッド)を対象にする場合ダイナミックリンクライブラリ(DLL)内に存在するフックプロシージャへのポインタを指定しなければなりませんとあります。

なので、dllのプロジェクトを作成し前回作成したプロシージャを含めて上げる必要があるようです。

dllプロジェクトの作成

dllプロジェクトとして、まず以下のヘッダファイルを作成します。今回はプロジェクトの文字セットを設定なしとしています。

dll_export.h

#pragma once
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

EXPORT LRESULT CALLBACK MsgBoxHookProc(int nCode, WPARAM wp, LPARAM lp);

それから、MsgBoxHookProcを実装します。

dll_export.cpp

#include "stdafx.h"
#include "dll_export.h"
#include<Windows.h>

HHOOK hMsgBoxHook;

LRESULT CALLBACK MsgBoxHookProc(int nCode, WPARAM wp, LPARAM lp)
{
    if (nCode >= 0)
    {
        if (nCode == HCBT_ACTIVATE)
        {
            // テキストラベルの内容を書き換える
            HWND label = ::GetDlgItem((HWND)wp, 0xFFFF);
            SetWindowText(label, "Hook");
            // OK(IDOK)の内容を書き換える
            SetDlgItemText((HWND)wp, IDOK, "OK(HOOK)");
            // キャンセルボタン(IDCANCEL)の内容を書き換える
            SetDlgItemText((HWND)wp, IDCANCEL, "CANCEL(HOOK)");
        }
    }
    return CallNextHookEx(hMsgBoxHook, nCode, wp, lp);
}

あと、dllのこの関数を含めるように以下のdefファイルを作成します。

Source.def

LIBRARY dll_export.dll
EXPORTS
MsgBoxHookProc

あとはソリューションのビルドでdllを作成します。

次にdllをimportしてsetWindowsHookExを呼び出す側のプロジェクトを作成します。今回の例ではプロジェクトの文字セットを設定なしとしています。

hookを呼び出すプロジェクトの作成

setWindowsHookExを呼び出すファイルは以下のようになりました。

DllMsBoxHook.cpp

#include "stdafx.h"
#include "DllMsgBoxHook.h"

HHOOK hDllMsgBoxHook;

bool DllMsgBoxHookStart(HWND hWnd)
{
    HINSTANCE hInst;
    hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
    DWORD allThread = 0;

    HMODULE hModule = LoadLibrary("C:\\Users\\*****\\source\\repos\\dll_export\\Release\\dll_export.dll");
    if (!hModule) {
        MessageBox(hWnd, "dll not found", "Error", MB_OK);
        return false;
    }
    else {
        LRESULT(CALLBACK *func) (int nCode, WPARAM wp, LPARAM lp);
        func = (LRESULT(CALLBACK *)(int nCode, WPARAM wp, LPARAM lp))GetProcAddress(hModule, "MsgBoxHookProc");

        DWORD currentThread = GetCurrentThreadId();

        hDllMsgBoxHook = SetWindowsHookEx(WH_CBT, //フック関数のタイプ
            (HOOKPROC)func, //フックプロシージャのアドレス
            hModule, //フックプロシージャが入っているインスタンスハンドル
            0); //フックされるスレッド 0ならすべてのスレッド

        if (hDllMsgBoxHook == NULL) {
            MessageBox(hWnd, "フック開始に失敗", "Error", MB_OK);
            return false;
        }
        else {
            return true;
        }
    }


}

bool DllMsgBoxHookEnd(HWND hWnd)
{
    if (UnhookWindowsHookEx(hDllMsgBoxHook) != 0) {
        return true;
    }
    else {
        MessageBox(hWnd, "フック解除に失敗", "Error", MB_OK);
        return false;
    }
}

LoadLibraryでモジュールを読み込み、その後GetProcAddressでプロシージャを取得しており、それぞれSetWindowsHookExに渡しています。今回はすべてのスレッドを対象としているのでスレッドに0を指定しています。

これのヘッダーファイルは以下のようになります。

DllMsBoxHook.h

#pragma once
#include<Windows.h>

bool DllMsgBoxHookStart(HWND hWnd);
bool DllMsgBoxHookEnd(HWND hWnd);

最後に、フックの開始、終了ボタンがある以下のようなフォームを作成し、デバック実行すると動作が確認できるかと思います。

Form1.h

#pragma once
#include "DllMsgBoxHook.h"

namespace CppCLR_WinformsProjekt {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;

    /// <summary>
    /// Zusammenfassung f・ Form1
    /// </summary>
    public ref class Form1 : public System::Windows::Forms::Form
    {
    public:
        Form1(void)
        {
            InitializeComponent();
            //
            //TODO: Konstruktorcode hier hinzuf・en.
            //
        }

    protected:
        /// <summary>
        /// Verwendete Ressourcen bereinigen.
        /// </summary>
        ~Form1()
        {
            if (components)
            {
                delete components;
            }
        }
    private: System::Windows::Forms::Button^  button1;
    private: System::Windows::Forms::Button^  button2;
    private: System::Windows::Forms::Label^  label1;
    private: System::Windows::Forms::Button^  button3;


    protected:

    private:
        /// <summary>
        /// Erforderliche Designervariable.
        /// </summary>
        System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
        /// <summary>
        /// Erforderliche Methode f・ die Designerunterst・zung.
        /// Der Inhalt der Methode darf nicht mit dem Code-Editor ge舅dert werden.
        /// </summary>
        void InitializeComponent(void)
        {
            this->button1 = (gcnew System::Windows::Forms::Button());
            this->button2 = (gcnew System::Windows::Forms::Button());
            this->label1 = (gcnew System::Windows::Forms::Label());
            this->button3 = (gcnew System::Windows::Forms::Button());
            this->SuspendLayout();
            //
            // button1
            //
            this->button1->Location = System::Drawing::Point(33, 53);
            this->button1->Name = L"button1";
            this->button1->Size = System::Drawing::Size(101, 40);
            this->button1->TabIndex = 0;
            this->button1->Text = L"start";
            this->button1->UseVisualStyleBackColor = true;
            this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
            //
            // button2
            //
            this->button2->Location = System::Drawing::Point(152, 53);
            this->button2->Name = L"button2";
            this->button2->Size = System::Drawing::Size(101, 40);
            this->button2->TabIndex = 1;
            this->button2->Text = L"stop";
            this->button2->UseVisualStyleBackColor = true;
            this->button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);
            //
            // label1
            //
            this->label1->AutoSize = true;
            this->label1->Font = (gcnew System::Drawing::Font(L"MS UI Gothic", 22));
            this->label1->Location = System::Drawing::Point(37, 9);
            this->label1->Name = L"label1";
            this->label1->Size = System::Drawing::Size(156, 30);
            this->label1->TabIndex = 2;
            this->label1->Text = L"HOOK OFF";
            this->label1->Click += gcnew System::EventHandler(this, &Form1::label1_Click);
            //
            // button3
            //
            this->button3->Location = System::Drawing::Point(33, 100);
            this->button3->Name = L"button3";
            this->button3->Size = System::Drawing::Size(220, 48);
            this->button3->TabIndex = 3;
            this->button3->Text = L"click";
            this->button3->UseVisualStyleBackColor = true;
            this->button3->Click += gcnew System::EventHandler(this, &Form1::button3_Click_1);
            //
            // Form1
            //
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(283, 160);
            this->Controls->Add(this->button3);
            this->Controls->Add(this->label1);
            this->Controls->Add(this->button2);
            this->Controls->Add(this->button1);
            this->Name = L"Form1";
            this->Text = L"Form1";
            this->ResumeLayout(false);
            this->PerformLayout();

        }
#pragma endregion
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
        HWND hWnd = static_cast<HWND>(this->Handle.ToPointer());
        if( DllMsgBoxHookStart(hWnd)) {
            this->label1->Text = L"HOOK ON";
        }
    }
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
        HWND hWnd = static_cast<HWND>(this->Handle.ToPointer());
        if (DllMsgBoxHookEnd(hWnd)) {
            this->label1->Text = L"HOOK OFF";
        }
    }
    private: System::Void richTextBox1_TextChanged(System::Object^  sender, System::EventArgs^  e) {
    }
private: System::Void label1_Click(System::Object^  sender, System::EventArgs^  e) {
}
private: System::Void button3_Click_1(System::Object^  sender, System::EventArgs^  e) {
    MessageBox::Show("not hook",
        "not hook", MessageBoxButtons::OKCancel,
        MessageBoxIcon::Asterisk);
}
};
}

試してみたら以下のようになりました。
f:id:steavevaivai:20180724222236g:plain