コード:
#include <stdio.h>
#include <winsock.h>
#include <wininet.h>
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <tlhelp32.h>
#include <Dbghelp.h> // ImageDirectoryEntryToData 関数用
#define PROCESSHOOK_EXPORT
#include "ProcessHook.h"
#pragma comment( lib, "Dbghelp.lib" ) // ImageDirectoryEntryToData 関数用
#pragma comment( lib, "wininet.lib" )
// DLL間共有変数の宣言
#pragma data_seg( "Shared" )
HHOOK gs_hhook = NULL;
HWND gs_hwndStart = NULL; // 開始したプロセスのメッセージ受信用ウィンドウのハンドル
#pragma data_seg()
#pragma comment( linker, "/Section:Shared,rws" )
// 構造体の宣言
// マッピングした DLL のデータ保存用構造体
typedef struct tagModuleData {
DWORD dwPID; // DLL を埋め込む対象のプロセスID
HMODULE hLibModule; // プロセスに埋め込んだ DLL のモジュールハンドル
DWORD dwTID; // DLL 内で作ったスレッドのスレッドID
struct tagModuleData *pNext; // 次のデータのアドレス
} ModuleData;
// フックする関数のデータ保存用構造体
typedef struct tagHookFunctionData {
LPCSTR lpszModuleName;
LPCSTR lpszHookFuncName;
PROC pfnHook;
PROC pfnOrig;
PROC *ppfnNow;
PROC *ppfnNew;
} HookFunctionData;
// 定数の定義
#define PH_EXIT ( WM_APP + 0x1000 )
#define PH_THREADID ( WM_APP + 0x1001 )
#define PH_MODULEHANDLE ( WM_APP + 0x1002 )
#define PH_MESSAGE ( WM_APP + 0x1003 )
#define PH_REMOVE ( WM_APP + 0x1004 )
#define PH_TEST ( WM_APP + 0x2000 )
#define CPID_MESSAGE 1
#define START_WINDOW_CLASS_NAME "ProcessHookStartWindow"
// グローバル変数の宣言
HINSTANCE g_hinstDll = NULL; // DLL のインスタンスハンドル
HANDLE g_hThread = NULL; // DLL で作成したスレッドのハンドル
ModuleData *g_mdTop = NULL; // フックしたプロセスの最初のデータ。 Start のみで使用
// プロトタイプ宣言
DWORD WINAPI StartThread( LPVOID );
LRESULT CALLBACK StartWindowProc( HWND, UINT, WPARAM, LPARAM );
BOOL MappingLibrary( DWORD );
DWORD WINAPI MappedThread( LPVOID );
BOOL HookFunction( HookFunctionData*, BOOL );
VOID ReplaceIATEntry( HookFunctionData*, HMODULE );
HWND CreateMessageWindow( LPCTSTR, HINSTANCE, WNDPROC );
// フックを開始する関数(外部にエクスポートする)
// lpszProcessName : フックする対象のプロセス名
// dwPID : フックする対象のプロセスID。指定しない場合は -1 にする
// 戻り値 : フックしたプロセスの数。エラーのときは -1
EXPORT( int ) StartProcessHook( LPCTSTR lpszProcessName, DWORD dwPID ) {
puts("\tInStart");
// 特殊なパターンの時。場合分けが面倒なのですべてエラーを返す
if( gs_hwndStart != NULL || g_hThread != NULL )
return -1;
// スレッドを作る。作るのに失敗したらエラーを返す
DWORD dwTID;
g_hThread = CreateThread( NULL, 0, StartThread, 0, 0, &dwTID );
if( g_hThread == NULL )
return -1;
// ウィンドウが作成されるのを待つ
while( gs_hwndStart == NULL ) {
DWORD dwExitCode;
GetExitCodeThread( g_hThread, &dwExitCode );
// スレッドが終了していたらウィンドウの作成に失敗したと判断。エラーを返す
if( dwExitCode != STILL_ACTIVE ) {
puts("CreateWindowError");
// 変数の後処理
CloseHandle( g_hThread );
g_hThread = NULL;
return -1;
}
Sleep( 1 );
}
int ret = 0; // 返り値
// dwPID が指定されている場合。その dwPID のみを対象にマッピングする
if( dwPID != -1 ) {
if( MappingLibrary( dwPID ) )
++ret;
// lpszProcessName のみが指定されている場合。同じ名前のすべてのプロセスにマッピングする
} else if( lpszProcessName != NULL ) {
// プロセスのスナップショットを取得。失敗したらエラーを返す
HANDLE hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hSnap == INVALID_HANDLE_VALUE ) {
puts("CreateToolhelp32SnapshotError");
ret = -1;
} else {
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
// すべてのプロセス名を列挙
if( Process32First( hSnap, &pe ) ) {
do{
// _tprintf( _T( "\t\t%s\t%d %d\n" ), pe.szExeFile, pe.th32ProcessID, pe.th32ParentProcessID );
// プロセス名が一致したらマッピングする
if( lstrcmp( pe.szExeFile, lpszProcessName ) == 0 ) {
_tprintf( _T("\t\tMapping %s\tPID : %d\tParentPID : %d\n"), pe.szExeFile, pe.th32ProcessID, pe.th32ParentProcessID );
if( MappingLibrary( pe.th32ProcessID ) )
++ret;
}
} while( Process32Next( hSnap, &pe ) );
// プロセスが一つも見つからなかった場合
} else {
puts("NotFoundProcess");
}
}
// 変数の後処理
CloseHandle( hSnap );
// dwPID == -1 && lpszProcessName == NULL の場合
// すべてのプロセスを対象にマッピングしても良かったが、自分には必要なかったので実装せず
} else {
ret = -1;
}
// 返り値が正常でない場合はスレッドの終了処理とかをやってもらう
if( ret == -1 || ret == 0 ) {
StopProcessHook();
}
puts("\tOutStart");
return ret;
}
// フックを終了する関数(外部にエクスポートする)
// 戻り値 : 成功したら TRUE、失敗したら FALSE
EXPORT( BOOL ) StopProcessHook( void ) {
puts("\tInStop");
// 特殊なパターンの時。エラーを返す
if( gs_hwndStart == NULL || g_hThread == NULL )
return FALSE;
// まず自分自身のスレッドに対して終了のメッセージを送っておく
PostMessage( gs_hwndStart, PH_EXIT, 0, 0 );
gs_hwndStart = NULL;
// マッピングしたすべてのプロセスに対してフックの解除をする
while( g_mdTop != NULL ) {
ModuleData *mdDel = g_mdTop;
g_mdTop = g_mdTop->pNext;
if( mdDel->dwTID != 0 ) {
// スレッドに対して終了のメッセージを送る
PostThreadMessage( mdDel->dwTID, PH_EXIT, 0, 0 );
printf("\t\tPostMessage\tPID : %d\tTID : %d\n", mdDel->dwPID, mdDel->dwTID );
HANDLE hThread = OpenThread( SYNCHRONIZE, FALSE, mdDel->dwTID );
if( hThread == NULL )
puts("OpenThreadError");
else {
// スレッドが終了するのを待つ
DWORD ret = WaitForSingleObject( hThread, 10000 );
printf("\t\tExitThread : %d\n", ret );
// 変数の後処理
CloseHandle( hThread );
}
}
if( mdDel->dwPID != 0 && mdDel->hLibModule != NULL ) {
// プロセスに FreeLibrary 関数を呼び出させてマッピングを解除する
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, mdDel->dwPID );
if( hProcess == NULL )
puts("OpenProcessError");
else {
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE )GetProcAddress(
GetModuleHandle( _T("Kernel32") ), "FreeLibrary" ), (LPVOID)mdDel->hLibModule, 0, NULL );
if( hThread == NULL )
puts("CreateRemoteThreadError");
else {
// FreeLibrary 関数が終了するのを待つ
DWORD ret = WaitForSingleObject( hThread, 10000 );
printf("\t\tExitProcess : %d\n", ret );
// 変数の後処理
CloseHandle( hThread );
}
// 変数の後処理
CloseHandle( hProcess );
}
}
// 変数の後処理
free( mdDel );
}
//自分自身のスレッドが終了するのを待つ
WaitForSingleObject( g_hThread, INFINITE );
// 変数の後処理
CloseHandle( g_hThread );
g_hThread = NULL;
puts("\tOutStop");
return TRUE;
}
//----------------------------------------------------------------------------------------------------
// これ以降の行にフックする関数を宣言して、メイン関数内にデータを記述する
//----------------------------------------------------------------------------------------------------
HINTERNET Hook_HttpOpenRequestW( HINTERNET hConnect, LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
LPCWSTR lpszReferrer, LPCWSTR FAR * lplpszAcceptTypes, DWORD dwFlags, DWORD_PTR dwContext )
{
HINTERNET ret = HttpOpenRequestW( hConnect, lpszVerb, lpszObjectName, lpszVersion,
lpszReferrer, lplpszAcceptTypes, dwFlags, dwContext );
// 文字列の長さを取得
int len = lstrlenW( lpszObjectName ) + 1;
LPWSTR data = (LPWSTR)calloc( len, sizeof(LPWSTR) );
wsprintfW( data, L"%s", lpszObjectName );
// スレッドに対してメッセージを送り、開始したプロセスにデータを送ってもらう
// 送るのに失敗したらメモリを解放する
if( PostThreadMessage( GetThreadId( g_hThread ), PH_MESSAGE, (WPARAM)data, len * sizeof(LPWSTR) ) == 0 )
free( data );
return ret;
}
HINTERNET Hook_HttpOpenRequestA( HINTERNET hConnect, LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
LPCSTR lpszReferrer, LPCSTR FAR * lplpszAcceptTypes, DWORD dwFlags, DWORD_PTR dwContext )
{
HINTERNET ret = HttpOpenRequestA( hConnect, lpszVerb, lpszObjectName, lpszVersion,
lpszReferrer, lplpszAcceptTypes, dwFlags, dwContext );
// 文字列の長さを取得
int len = lstrlenA( lpszObjectName ) + 1;
LPWSTR data = (LPWSTR)calloc( len, sizeof(LPWSTR) );
// Hook_HttpOpenRequestW と形式を合わせるためにワイド文字に簡易的に変換。
wsprintfW( data, L"%S", lpszObjectName );
// スレッドに対してメッセージを送り、開始したプロセスにデータを送ってもらう
// 送るのに失敗したらメモリを解放する
if( PostThreadMessage( GetThreadId( g_hThread ), PH_MESSAGE, (WPARAM)data, len * sizeof(LPWSTR) ) == 0 )
free( data );
return ret;
}
//----------------------------------------------------------------------------------------------------
// フックする関数をここまでに宣言する
//----------------------------------------------------------------------------------------------------
// メイン
BOOL WINAPI DllMain( HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved ) {
// フックする関数のまとめたデータを記述
#define FUNCTION_NUM 2
static HookFunctionData hfData[FUNCTION_NUM] = {
{ "wininet.dll", "HttpOpenRequestW", (PROC)Hook_HttpOpenRequestW, },
{ "wininet.dll", "HttpOpenRequestA", (PROC)Hook_HttpOpenRequestA, },
};
static BOOL isStartProcess = FALSE;
switch( fdwReason ) {
case DLL_PROCESS_ATTACH:
puts("DLL_PROCESS_ATTACH");
// 自分のモジュールハンドルをグローバル関数に保存
g_hinstDll = hinstDll;
// gs_hwndStart が初期値のままなら開始したプロセスと判断
if( gs_hwndStart == NULL ) {
isStartProcess = TRUE;
// 権限の違うプロセスからもメッセージを受信できるように設定
// この関数が定義されていない環境でも使えるようにこんな面倒な使い方をしている?
// Window7 以降なら ChangeWindowMessageFilterEx の方を使った方がいいらしい
HMODULE hModDll = LoadLibrary( _T("user32.dll") );
if( hModDll != NULL ) {
typedef BOOL (WINAPI *MESSAGEFILTER)( UINT, DWORD );
MESSAGEFILTER myChangeWindowMessageFilter =(MESSAGEFILTER)
GetProcAddress( hModDll, "ChangeWindowMessageFilter" );
if( myChangeWindowMessageFilter != NULL ) {
myChangeWindowMessageFilter( WM_COPYDATA, MSGFLT_ADD );
myChangeWindowMessageFilter( PH_THREADID, MSGFLT_ADD );
myChangeWindowMessageFilter( PH_REMOVE, MSGFLT_ADD );
myChangeWindowMessageFilter( PH_TEST, MSGFLT_ADD );
puts( "\tChangedFilter" );
} // 失敗した場合はその関数自体がない可能性がある
FreeLibrary( hModDll );
}
} else {
// スレッドを作る。失敗したら DLL は読み込まないことにする
DWORD dwTID;
g_hThread = CreateThread( NULL, 0, MappedThread, hfData, 0, &dwTID );
if( g_hThread == NULL )
return FALSE;
// フックする関数のオリジナル関数のアドレスを取得
for( int i = 0; i < FUNCTION_NUM; ++i )
hfData[i].pfnOrig = GetProcAddress( GetModuleHandleA( hfData[i].lpszModuleName ),
hfData[i].lpszHookFuncName );
// MessageBox(NULL, _T("DLL_PROCESS_ATTACH"), _T("DllMain"), MB_OK);
}
break;
case DLL_PROCESS_DETACH:
puts("DLL_PROCESS_DETACH");
if( isStartProcess ) {
// 念のためフックを解除
StopProcessHook();
} else {
if( gs_hwndStart != NULL )
PostMessage( gs_hwndStart, PH_REMOVE, (WPARAM)GetCurrentProcessId(), 0 );
// 念のためフックを解除
HookFunction( hfData, FALSE );
MessageBox(NULL, _T("DLL_PROCESS_DETACH"), _T("DllMain"), MB_OK);
}
break;
case DLL_THREAD_ATTACH:
puts("THREAD_ATTACH");
break;
case DLL_THREAD_DETACH:
puts("THREAD_DETACH");
break;
}
return TRUE;
}
// 開始したプロセス内で作成するスレッド
DWORD WINAPI StartThread( LPVOID lpParam ) {
puts("\tInThread");
MSG msg;
// メッセージ取得用のウィンドウの作成。失敗したら終了する
gs_hwndStart = CreateMessageWindow( _T( START_WINDOW_CLASS_NAME ), g_hinstDll, StartWindowProc );
if( gs_hwndStart == NULL )
ExitThread( 0 );
// メッセージループ
while ( GetMessage( &msg, NULL, 0, 0 ) > 0 ) {
DispatchMessage( &msg );
}
ExitThread( msg.wParam );
}
// 開始したプロセス内で作成するスレッドで作成するウィンドウのプロシージャ
LRESULT CALLBACK StartWindowProc( HWND hwnd , UINT msg , WPARAM wp , LPARAM lp ) {
switch( msg ) {
// テストメッセージ
case PH_TEST:
printf("\tPH_TEST : HWND = 0x%08x : WPARAM = %d : LPARAM = %d\n", hwnd, wp, lp );
return 0;
// PH_REMOVE ならそのプロセスは終了したとみなす
// このメッセージが来る時点で DLL_PROCESS_DETACH なのでメモリを解放するのみ
case PH_REMOVE: {
printf("\tPH_REMOVE\t%d\n", wp );
if( g_mdTop != NULL ) {
// 終了したプロセスが最初のデータだった場合
if( g_mdTop->dwPID == (DWORD)wp ) {
printf("\t\tTop\tPID : %d\n", g_mdTop->dwPID );
ModuleData *mdDel = g_mdTop;
g_mdTop = mdDel->pNext;
free( mdDel );
return 0;
}
for( ModuleData *mdNow = g_mdTop; mdNow->pNext != NULL; mdNow = mdNow->pNext ) {
// 終了したプロセスが最初以外のデータだった場合
if( mdNow->pNext->dwPID == (DWORD)wp ) {
printf("\t\tNotTop\tPID : %d\n", mdNow->pNext->dwPID );
ModuleData *mdDel = mdNow->pNext;
mdNow->pNext = mdDel->pNext;
free( mdDel );
return 0;
}
}
}
// ここに来たら終了したプロセスはフックしていないことになっている
printf("NotHook\tPID : %d\n", wp );
return 0;
}
// PH_THREADID か PH_MODULEHANDLE ならデータを記録
case PH_THREADID: case PH_MODULEHANDLE: {
printf("\t%s %d\tPID : %d\n", ( msg == PH_THREADID ) ? "PH_THREADID" : "PH_MODULEHANDLE", lp, wp );
ModuleData *mdNew = g_mdTop;
// PID がすでに記録されているかを確認する
for( ; mdNew != NULL; mdNew = mdNew->pNext ) {
if( mdNew->dwPID == (DWORD)wp )
break;
}
// newData == NULL ならまだ記録されていないのでデータを新しく先頭に作る
if( mdNew == NULL ) {
mdNew = (ModuleData*)calloc( 1, sizeof(ModuleData) );
mdNew->dwPID = (DWORD)wp;
mdNew->pNext = g_mdTop;
g_mdTop = mdNew;
printf("\t\tMakeNewData\tnew : %x\tnext : %x\n", g_mdTop, g_mdTop->pNext );
}
// 新しいデータを保存する
if( msg == PH_THREADID )
mdNew->dwTID = (DWORD)lp;
else
mdNew->hLibModule = (HMODULE)lp;
return 0;
}
// WM_COPYDATA ならデータを表示
case WM_COPYDATA: {
COPYDATASTRUCT *cpData = (COPYDATASTRUCT*)lp;
switch( cpData->dwData ) {
case CPID_MESSAGE:
wprintf( L"PID : %d\t%s\n", wp, (LPCWSTR)cpData->lpData );
break;
}
return 0;
}
// PH_EXIT なら終了
case PH_EXIT:
puts("\tPH_EXIT");
DestroyWindow( hwnd );
return 0;
case WM_DESTROY:
puts("\tWM_DESTROY");
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hwnd , msg , wp , lp );
}
// 対象のプロセスIDに自分をマッピングする関数
// dwPID : フックする対象のプロセスID
// 戻り値 : 成功したら TRUE 、失敗したら FALSE
BOOL MappingLibrary( DWORD dwPID ) {
// 開始したプロセスならマッピングしない
if( dwPID == GetCurrentProcessId() )
return FALSE;
// 対象のプロセスのハンドルを取得
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwPID );
if(hProcess == NULL){
puts("OpenProcessError");
return FALSE;
}
// 自分自身の名前をフルパスで取得(+長さも)
WCHAR szLibFilePath[_MAX_PATH];
int nLibFileLen;
GetModuleFileNameW( (HMODULE)g_hinstDll, szLibFilePath, _MAX_PATH );
nLibFileLen = ( lstrlenW( szLibFilePath ) + 1 ) * sizeof(WCHAR);
// 対象のプロセス内にパスを書き込める領域を確保する
LPWSTR RemoteProcessMemory = (LPWSTR)VirtualAllocEx( hProcess, NULL, nLibFileLen, MEM_COMMIT, PAGE_READWRITE);
if( RemoteProcessMemory == NULL ) {
puts("VirtualAllocExError");
return FALSE;
}
// 対象のプロセス内にパスを書き込む
if( WriteProcessMemory( hProcess, RemoteProcessMemory, (PVOID)szLibFilePath, nLibFileLen, NULL ) == 0 ) {
puts("WriteProcessMemoryError");
return FALSE;
}
// LoadLibrary関数のアドレスを取得
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)
GetProcAddress( GetModuleHandleW( L"Kernel32" ), "LoadLibraryW" );
if( pfnThreadRtn == NULL ) {
puts("GetProcAddressError");
return FALSE;
}
// 対象のプロセス内でLoadLibrary関数を呼び出させる
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, pfnThreadRtn, RemoteProcessMemory, 0, NULL );
if( hThread == NULL ) {
puts("CreateRemoteThreadError");
return FALSE;
}
// LoadLibrary 関数が終了するのを待つ
WaitForSingleObject( hThread, INFINITE );
// LoadLibrary 関数の戻り値を取得する(=対象のプロセス内にマッピングされたDLLのモジュールハンドル)
HMODULE hMod;
GetExitCodeThread( hThread, (LPDWORD)&hMod );
if( hMod == NULL ) {
puts("LoadLibraryError");
return FALSE;
}
// マッピングを解除する用に対象のプロセスの情報を保存する
if( PostMessage( gs_hwndStart, PH_MODULEHANDLE, (WPARAM)dwPID, (LPARAM)hMod ) == 0 ) {
puts("PostMessageError");
return FALSE;
}
// 変数の後処理
CloseHandle( hThread );
VirtualFreeEx( hProcess, RemoteProcessMemory, nLibFileLen, MEM_RELEASE );
CloseHandle( hProcess );
return TRUE;
}
// マッピングされたプロセス内で作成するスレッド
// lpParam : HookFunctionData 構造体へのポインタ
DWORD WINAPI MappedThread( LPVOID lpParam ) {
MSG msg;
HookFunctionData *hfData = (HookFunctionData*)lpParam;
// まず自分のスレッドIDを開始したプロセスに送る
PostMessage( gs_hwndStart, PH_THREADID, (WPARAM)GetCurrentProcessId(), (LPARAM)GetCurrentThreadId() );
// フック開始
HookFunction( hfData, TRUE );
// メッセージループ
while( GetMessage( &msg, NULL, 0, 0 ) > 0 ) {
switch( msg.message ) {
// テストメッセージ
case PH_TEST: {
TCHAR str[256];
wsprintf( str, _T("\tPH_TEST : HWND = 0x%08x : WPARAM = %d : LPARAM = %d\n"), msg.hwnd, msg.wParam, msg.lParam );
MessageBox( NULL, str, _T("PH_TEST"), MB_OK );
break;
}
// PH_MESSAGE が送られてきたらその内容を開始したプロセスに送る
case PH_MESSAGE: {
COPYDATASTRUCT cpData;
cpData.dwData = CPID_MESSAGE;
cpData.cbData = (DWORD)msg.lParam;
cpData.lpData = (LPVOID)msg.wParam;
SendMessage( gs_hwndStart, WM_COPYDATA, (WPARAM)GetCurrentProcessId(), (LPARAM)&cpData );
free( (LPVOID)msg.wParam );
break;
}
// PH_EXIT が送られてきたらスレッドを終了する
case PH_EXIT:
PostQuitMessage( 0 );
break;
}
// もしかしていらない?
DispatchMessage( &msg );
}
// フック解除
HookFunction( hfData, FALSE );
ExitThread( msg.wParam );
}
// 自分が読み込まれているプロセスにフックする or 解除する関数
// hfData : HookFunctionData 構造体へのポインタ
// hookFlag : フックするかどうか。フックするなら TRUE 、解除するなら FALSE を指定
// 戻り値 : 成功したら TRUE 、失敗したら FALSE
BOOL HookFunction( HookFunctionData *hfData, BOOL hookFlag ) {
static BOOL isHook = FALSE; // 現状フックされているかどうか
if( isHook == hookFlag )
return FALSE;
// フックするか解除するかによって変更する前と後のアドレスを変える
if( hookFlag ) {
for( int i = 0; i < FUNCTION_NUM; ++i ) {
hfData[i].ppfnNow = &( hfData[i].pfnOrig );
hfData[i].ppfnNew = &( hfData[i].pfnHook );
}
} else {
for( int i = 0; i < FUNCTION_NUM; ++i ) {
hfData[i].ppfnNow = &( hfData[i].pfnHook );
hfData[i].ppfnNew = &( hfData[i].pfnOrig );
}
}
// モジュールリストを取得
HANDLE hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, GetCurrentProcessId() );
if( hModuleSnap != INVALID_HANDLE_VALUE ) {
MODULEENTRY32 me;
me.dwSize = sizeof(me);
// それぞれのモジュールに対してReplaceIATEntryを実行
if( Module32First( hModuleSnap, &me ) ) {
do {
// 自分自身には行わない
if( me.hModule != g_hinstDll )
ReplaceIATEntry( hfData, me.hModule );
} while( Module32Next( hModuleSnap, &me ) );
}
// 変数の後処理
CloseHandle( hModuleSnap );
}
isHook = hookFlag;
return TRUE;
}
// ひとつのモジュールに対してAPIフックを行う関数
// hfData : HookFunctionData 構造体へのポインタ
// hmodCaller : 現在考えている一つのモジュールのハンドル
VOID ReplaceIATEntry( HookFunctionData *hfData, HMODULE hmodCaller ) {
// モジュールのインポートセクションのアドレスを取得
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData( hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize );
// インポートセクションを持っていないなら脱出
if( pImportDesc == NULL )
return;
// インポートディスクリプタを検索
while( pImportDesc->Name ) {
// モジュール名を取得
LPCSTR pszModName = (LPCSTR) ( (LPBYTE)hmodCaller + pImportDesc->Name );
// すべてのフックしたい関数を調べる
for( int i = 0; i < FUNCTION_NUM; ++i ) {
// モジュール名が一致するかを調べる
if( lstrcmpiA( pszModName, hfData[i].lpszModuleName ) == 0 ) {
// インポートアドレステーブルを取得
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)( (PBYTE)hmodCaller + pImportDesc->FirstThunk );
while( pThunk->u1.Function ) {
// 関数アドレスのアドレスを取得
PROC *ppfn = (PROC*)&pThunk->u1.Function;
// 該当関数であるならばインポートセクションのアドレスを書き換える
if( *ppfn == *( hfData[i].ppfnNow ) ) {
DWORD dwOldProtect;
VirtualProtect( ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwOldProtect );
WriteProcessMemory( GetCurrentProcess(), ppfn, hfData[i].ppfnNew , sizeof(PROC), NULL );
// MessageBoxA( NULL, hfData[i].lpszHookFuncName, pszModName, MB_OK );
break;
}
++pThunk;
}
}
}
++pImportDesc;
}
return;
}
// メッセージ取得用ウィンドウを作成する関数
// lpszClassName : ウィンドウのクラス名
// hInst : インスタンスハンドル
// WndProc : ウィンドウプロシージャへのポインタ
HWND CreateMessageWindow( LPCTSTR lpszClassName, HINSTANCE hInst, WNDPROC WndProc ) {
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = lpszClassName;
wc.hIconSm = NULL;
if( RegisterClassEx( &wc ) == 0 )
return NULL;
return CreateWindowEx( 0, lpszClassName, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, hInst, NULL );
}