2. どう取り組んで(作ったプログラムはどれで:下のプログラムがdllになりSENDを変更します
3. どのようなエラーやトラブルで困っていて;メッセージボックスは挙動を変えられるのに同じ方法でSENDは変えられない
4. 自分は何が解らないのか、知りたいのか;SENDの挙動を変えるプログラムがほしい
5. 今のCの知識はどの程度なのか:3ヶ月くらい
OS名・windows7
コンパイラ名・visualstudio2010
ライブラリ名:
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef STRICT
#define STRICT
#endif
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <tlhelp32.h>
#include <Dbghelp.h>
// API_Hook_Lib.hに自分がDLLであることを通知
#define I_AM_HOOK_DLL
#include "API_Hook_Lib.h"
/////////////////////////////////////////////////////////////////////
// 制御関数
/////////////////////////////////////////////////////////////////////
// ImageDirectoryEntryToDataを使用するために
#pragma comment(lib, "Dbghelp.lib")
// g_hhookはSetWindowsHookExで使用するフックハンドル
// g_dwCurrentProcessIdは最初にDLLをマッピングしたプロセスのID
// つまりSetWindowsHookExを実行するプロセスのIDとなる
#pragma data_seg("Shared")
HHOOK g_hhook = NULL;
DWORD g_dwCurrentProcessId = 0;
#pragma data_seg()
#pragma comment(linker, "/Section:Shared,rws")
// SetWindowsHookExに渡すプロシージャ関数だが、事実上飾りみたいなもの
static LRESULT WINAPI GetMsgProc(int code, WPARAM wParam, LPARAM lParam)
{
// CallNextHookExの第1引数は2000/XP以降ならばNULLでもよい
return(CallNextHookEx(g_hhook, code, wParam, lParam));
}
// SetWindowsHookExで全プロセスにフックを実行
API_HOOK_EXPORT int WINAPI API_Hook_AllApps_Start(DWORD dwThreadId)
{
// フックハンドルを確認
if(g_hhook != NULL)
return -1;
// このDLLのハンドルを取得
MEMORY_BASIC_INFORMATION mbi;
if(VirtualQuery(API_Hook_AllApps_Start, &mbi, sizeof(mbi)) == 0)
return -1;
HMODULE hModule = (HMODULE) mbi.AllocationBase;
// 全プロセスへフックを実行
g_hhook = SetWindowsHookEx(
WH_GETMESSAGE, GetMsgProc, hModule, dwThreadId);
if(g_hhook == NULL)
return -1;
return 0;
}
// 全プロセスのフックを解除
API_HOOK_EXPORT int WINAPI API_Hook_AllApps_Stop()
{
// フックハンドルを確認
if(g_hhook == NULL)
return -1;
// UnhookWindowsHookExにてフックを解除
UnhookWindowsHookEx(g_hhook);
g_hhook = NULL;
return 0;
}
/////////////////////////////////////////////////////////////////////
// APIフックを実行するメインルーチン
/////////////////////////////////////////////////////////////////////
class CAPIHook
{
public:
// コンストラクタ
CAPIHook(PSTR, PSTR, PROC);
// デストラクタ
~CAPIHook();
// オリジナルアドレス取得用
operator PROC() { return(m_pfnOrig); }
private:
static CAPIHook *sm_pHead; // ノードのトップのデータ
CAPIHook *m_pNext; // 次のノードのデータ
// 保存領域
PCSTR m_pszModuleName; // 関数を持つモジュール名(ANSI)
PCSTR m_pszFuncName; // 関数名(ANSI)
PROC m_pfnOrig; // オリジナル関数のアドレス
PROC m_pfnHook; // 置き換わる関数のアドレス
// APIフックを適応させるメイン関数
static void WINAPI ReplaceIATEntryInAllMods(PCSTR, PROC, PROC);
static void WINAPI ReplaceIATEntryInOneMod(PCSTR, PROC, PROC, HMODULE);
// 新たにロードされたモジュールにAPIフックを対応させる関数
static void WINAPI FixupNewlyLoadedModule(HMODULE, DWORD);
// それぞれのAPIに置き換わるフック関数
static HMODULE WINAPI Hook_LoadLibraryA(PCSTR);
static HMODULE WINAPI Hook_LoadLibraryW(PCWSTR);
static HMODULE WINAPI Hook_LoadLibraryExA(PCSTR, HANDLE, DWORD);
static HMODULE WINAPI Hook_LoadLibraryExW(PCWSTR, HANDLE, DWORD);
static FARPROC WINAPI Hook_GetProcAddress(HMODULE, PCSTR);
// それぞれのAPIをフックすることを宣言
static CAPIHook sm_LoadLibraryA;
static CAPIHook sm_LoadLibraryW;
static CAPIHook sm_LoadLibraryExA;
static CAPIHook sm_LoadLibraryExW;
static CAPIHook sm_GetProcAddress;
};
// ノードのトップを初期化
CAPIHook *CAPIHook::sm_pHead = NULL;
// コンストラクタ
CAPIHook::CAPIHook(
PSTR pszModuleName,
PSTR pszFuncName,
PROC pfnHook)
{
m_pNext = sm_pHead; // 次のノードのアドレスを代入
sm_pHead = this; // このノードのアドレスを代入
// オリジナル関数のアドレスを取得
PROC pfnOrig = ::GetProcAddress(
GetModuleHandleA(pszModuleName), pszFuncName);
// フックに関するデータを保存
m_pszModuleName = pszModuleName;
m_pszFuncName = pszFuncName;
m_pfnOrig = pfnOrig;
m_pfnHook = pfnHook;
// プロセスIDが0ならDLLをマッピングする最初のプロセスと判断
// そのプロセスIDを共有メモリに保存
if(g_dwCurrentProcessId == 0)
g_dwCurrentProcessId = GetCurrentProcessId();
// 起動元と同じプロセスならフックを行わない
if(g_dwCurrentProcessId != GetCurrentProcessId())
ReplaceIATEntryInAllMods(m_pszModuleName, m_pfnOrig, m_pfnHook);
}
// デストラクタ
CAPIHook::~CAPIHook()
{
// 起動元と同じプロセスなら解除の必要なし
if(g_dwCurrentProcessId != GetCurrentProcessId())
ReplaceIATEntryInAllMods(m_pszModuleName, m_pfnHook, m_pfnOrig);
// ノードのトップを取得
CAPIHook *p = sm_pHead;
// ノードのトップが自分ならば、次のノードをトップに据えて終了
if(p == this) {
sm_pHead = p->m_pNext;
return;
}
// もし自分ではないならば、ノードの中から検索して
// 自分を連結から外す
while(p->m_pNext != NULL) {
if (p->m_pNext == this) {
p->m_pNext = p->m_pNext->m_pNext;
break;
}
p = p->m_pNext;
}
}
// すべてのモジュールに対してAPIフックを行う関数
void CAPIHook::ReplaceIATEntryInAllMods(
PCSTR pszModuleName,
PROC pfnCurrent,
PROC pfnNew)
{
// 自分自身(API_Hook_Lib.dll)のモジュールハンドルを取得
MEMORY_BASIC_INFORMATION mbi;
if(VirtualQuery(ReplaceIATEntryInAllMods, &mbi, sizeof(mbi)) == 0)
return;
HMODULE hModThisMod = (HMODULE) mbi.AllocationBase;
// モジュールリストを取得
HANDLE hModuleSnap = CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE, GetCurrentProcessId());
if(hModuleSnap == INVALID_HANDLE_VALUE)
return;
MODULEENTRY32 me;
me.dwSize = sizeof(me);
BOOL bModuleResult = Module32First(hModuleSnap, &me);
// それぞれのモジュールに対してReplaceIATEntryInOneModを実行
// ただし自分自身(API_Hook_Lib.dll)には行わない
while(bModuleResult) {
if(me.hModule != hModThisMod)
ReplaceIATEntryInOneMod(pszModuleName, pfnCurrent, pfnNew, me.hModule);
bModuleResult = Module32Next(hModuleSnap, &me);
}
CloseHandle(hModuleSnap);
}
// ひとつのモジュールに対してAPIフックを行う関数
void CAPIHook::ReplaceIATEntryInOneMod(
PCSTR pszModuleName,
PROC pfnCurrent,
PROC pfnNew,
HMODULE hmodCaller)
{
// モジュールのインポートセクションのアドレスを取得
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
// インポートセクションを持っていない
if (pImportDesc == NULL)
return;
// インポートディスクリプタを検索
while(pImportDesc->Name) {
PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
if (lstrcmpiA(pszModName, pszModuleName) == 0)
break;
pImportDesc++;
}
// このモジュールは呼び出し先から関数をインポートしていない
if (pImportDesc->Name == 0)
return;
// インポートアドレステーブルを取得
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
((PBYTE) hmodCaller + pImportDesc->FirstThunk);
// 新しい関数アドレスに置き換える
while(pThunk->u1.Function) {
// 関数アドレスのアドレスを取得
PROC *ppfn = (PROC*) &pThunk->u1.Function;
// 該当関数であるならば発見!
BOOL fFound = (*ppfn == pfnCurrent);
if (fFound) {
// アドレスが一致したので、インポートセクションのアドレスを書き換える
DWORD dwDummy;
VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy);
WriteProcessMemory(
GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), NULL);
return;
}
pThunk++;
}
// ここに処理が移った場合、インポートセクションに該当関数がなかったことになる
return;
}
/////////////////////////////////////////////////////////////////////
// デフォルトでフックするAPIの処理(CAPIHookクラス内部で管理する)
/////////////////////////////////////////////////////////////////////
// デフォルトでフックする関数のプロトタイプを定義
typedef HMODULE (WINAPI *PLOADLIBRARYA)(PCSTR);
typedef HMODULE (WINAPI *PLOADLIBRARYW)(PCWSTR);
typedef HMODULE (WINAPI *PLOADLIBRARYEXA)(PCSTR, HANDLE, DWORD);
typedef HMODULE (WINAPI *PLOADLIBRARYEXW)(PCWSTR, HANDLE, DWORD);
typedef FARPROC (WINAPI *PGETPROCADDRESS)(HMODULE, PCSTR);
// モジュールを扱うAPIをあらかじめフックしておく
CAPIHook CAPIHook::sm_LoadLibraryA (
"Kernel32.dll", "LoadLibraryA", (PROC) CAPIHook::Hook_LoadLibraryA);
CAPIHook CAPIHook::sm_LoadLibraryW (
"Kernel32.dll", "LoadLibraryW", (PROC) CAPIHook::Hook_LoadLibraryW);
CAPIHook CAPIHook::sm_LoadLibraryExA(
"Kernel32.dll", "LoadLibraryExA", (PROC) CAPIHook::Hook_LoadLibraryExA);
CAPIHook CAPIHook::sm_LoadLibraryExW(
"Kernel32.dll", "LoadLibraryExW", (PROC) CAPIHook::Hook_LoadLibraryExW);
CAPIHook CAPIHook::sm_GetProcAddress(
"Kernel32.dll", "GetProcAddress", (PROC) CAPIHook::Hook_GetProcAddress);
// 新たにロードされた関数をフックする関数
void CAPIHook::FixupNewlyLoadedModule(HMODULE hMod, DWORD dwFlags)
{
if ((hMod != NULL) && ((dwFlags & LOAD_LIBRARY_AS_DATAFILE) == 0)) {
for (CAPIHook *p = sm_pHead; p != NULL; p = p->m_pNext) {
ReplaceIATEntryInOneMod(
p->m_pszModuleName, p->m_pfnOrig, p->m_pfnHook, hMod);
}
}
}
// 置き換わったLoadLibraryA関数
HMODULE WINAPI CAPIHook::Hook_LoadLibraryA(PCSTR pszModulePath)
{
HMODULE hMod = (
(PLOADLIBRARYA)(PROC) CAPIHook::sm_LoadLibraryA)(pszModulePath);
FixupNewlyLoadedModule(hMod, 0);
return hMod;
}
// 置き換わったLoadLibraryW関数
HMODULE WINAPI CAPIHook::Hook_LoadLibraryW(PCWSTR pszModulePath)
{
HMODULE hMod = (
(PLOADLIBRARYW)(PROC) CAPIHook::sm_LoadLibraryW)(pszModulePath);
FixupNewlyLoadedModule(hMod, 0);
return hMod;
}
// 置き換わったLoadLibraryExA関数
HMODULE WINAPI CAPIHook::Hook_LoadLibraryExA(
PCSTR pszModulePath,
HANDLE hFile,
DWORD dwFlags)
{
HMODULE hMod = (
(PLOADLIBRARYEXA)(PROC) CAPIHook::sm_LoadLibraryExA)
(pszModulePath, hFile, dwFlags);
FixupNewlyLoadedModule(hMod, dwFlags);
return hMod;
}
// 置き換わったLoadLibraryExW関数
HMODULE WINAPI CAPIHook::Hook_LoadLibraryExW(
PCWSTR pszModulePath,
HANDLE hFile,
DWORD dwFlags)
{
HMODULE hMod = (
(PLOADLIBRARYEXW)(PROC) CAPIHook::sm_LoadLibraryExW)
(pszModulePath, hFile, dwFlags);
FixupNewlyLoadedModule(hMod, dwFlags);
return hMod;
}
// 置き換わったGetProcAddress関数
FARPROC WINAPI CAPIHook::Hook_GetProcAddress(HMODULE hMod, PCSTR pszProcName)
{
// 本当の関数アドレスを取得
FARPROC pfn = (
(PGETPROCADDRESS)(PROC) CAPIHook::sm_GetProcAddress)
(hMod, pszProcName);
// もしフックすべき関数であったならば、置き換わった関数のアドレスを渡す
for (CAPIHook *p = sm_pHead; (pfn != NULL) && (p != NULL); p = p->m_pNext) {
if (pfn == p->m_pfnOrig)
return (p->m_pfnHook);
}
return pfn;
}
/////////////////////////////////////////////////////////////////////
// この行以降に新たにフックしたいAPIを宣言し、置き換える関数を加える
/////////////////////////////////////////////////////////////////////
// 変数定義
extern CAPIHook g_MessageBoxA;
extern CAPIHook g_MessageBoxW;
extern CAPIHook g_send;
// フックする関数のプロトタイプを定義
typedef int (WINAPI *PFNMESSAGEBOXA)(HWND, PCSTR, PCSTR, UINT);
typedef int (WINAPI *PFNMESSAGEBOXW)(HWND, PCSTR, PCSTR, UINT);
typedef int (WINAPI *PFNSEND)(int, int, PCSTR,int);
// 置き換わる関数定義
void Main_MessageBox(void)
{
// プロセスのファイル名を取得
static TCHAR szProcessPath[1024];
GetModuleFileNameA(NULL, (LPSTR)szProcessPath, sizeof(szProcessPath));
// メインWindowへ通知するデータを作成
COPYDATASTRUCT cds;
cds.lpData = szProcessPath;
cds.cbData = lstrlen(szProcessPath) + 1;
cds.dwData = 0;
// メインWindowを検索
HWND hWnd = FindWindow(NULL, _T("API Hook Sample"));
if(hWnd)
SendMessage(hWnd, WM_COPYDATA, NULL, (LPARAM)&cds);
}
int WINAPI Hook_MessageBoxA(HWND hWnd,PCSTR pszText, PCSTR pszCaption,UINT uType)
{
// オリジナルMessageBoxAを呼び出す
int nResult = ((PFNMESSAGEBOXA)(PROC) g_MessageBoxA)
(hWnd, pszText, pszCaption, uType);
Main_MessageBox();
return nResult;
}
int WINAPI Hook_MessageBoxW(HWND hWnd,PCSTR pszText,PCSTR pszCaption,UINT uType)
{
// オリジナルMessageBoxWを呼び出す
int nResult = ((PFNMESSAGEBOXW)(PROC) g_MessageBoxW)
(hWnd, pszText, pszCaption, uType);
Main_MessageBox();
return nResult;
}
int WINAPI Hook_SEND(int sock,PCSTR buf, int size,int flag)
{
Main_MessageBox();
return 0;
}
// フックを実行
CAPIHook g_MessageBoxA( "User32.dll", "MessageBoxA", (PROC) Hook_MessageBoxA);
CAPIHook g_MessageBoxW("user32.dll", "MessageBoxW", (PROC) Hook_MessageBoxW);
CAPIHook g_send("wsock32.dll", "send", (PROC) Hook_SEND);