//Hook.cpp

//######################################################
//
//                 見せられないよ!
//                Ver.1.00 by x@rgs
//
//#####################################################

#define STRICT
#define UNICODE
#define _UNICODE

#include<tchar.h>
#include<windows.h>
#include<imagehlp.h>

void replaceAddress(PCSTR callee_mod_name,PROC current_pfn,PROC new_pfn,HMODULE mod_caller){
	//モジュールのインポートセクションのアドレスを取得する
	ULONG data_size;

	PIMAGE_IMPORT_DESCRIPTOR import_descriptor=NULL;
	import_descriptor=static_cast<PIMAGE_IMPORT_DESCRIPTOR>(::ImageDirectoryEntryToData(mod_caller,
																				   true,
																				   IMAGE_DIRECTORY_ENTRY_IMPORT,
																				   &data_size));

	if(import_descriptor==NULL){
		//このモジュールにはインポートセクションがない
		//もしくは現在ロードされていない
		return;
	}

	//呼び出し先の関数への参照が含まれているインポート記述子を検索する
	for(;import_descriptor->Name;import_descriptor++){
		PSTR mod_name=reinterpret_cast<PSTR>(reinterpret_cast<PBYTE>(mod_caller)+import_descriptor->Name);

		if(lstrcmpiA(mod_name,callee_mod_name)==0){
			//呼び出し元のIATで呼び出し先関数を取得する
			PIMAGE_THUNK_DATA thunk_data=reinterpret_cast<PIMAGE_THUNK_DATA>(reinterpret_cast<PBYTE>(mod_caller)+import_descriptor->FirstThunk);

			//現在の関数アドレスを新しい関数アドレスと置き換える
			for(;thunk_data->u1.Function;thunk_data++){
				//関数アドレスのアドレスを取得する
				PROC* ppfn=reinterpret_cast<PROC*>(&thunk_data->u1.Function);
				DWORD protect_bak=0;

				if(*ppfn!=current_pfn)continue;

				//保護状態変更
				if(!VirtualProtect(ppfn,sizeof(PROC),PAGE_READWRITE,&protect_bak)){
					return;
				}
				::WriteProcessMemory(::GetCurrentProcess(),ppfn,&new_pfn,sizeof(new_pfn),NULL);
				//保護状態を元に戻す
				::VirtualProtect(ppfn,sizeof(PROC),protect_bak,&protect_bak);
				return;
			}
		}
	}
}

namespace hook{
	typedef BOOL (WINAPI*pShowWindow)(HWND hWnd,int nCmdShow);
	pShowWindow org_pShowWindow;

	BOOL WINAPI showWindow(HWND hWnd,int nCmdShow){
		int state=nCmdShow;

		if(state==SW_SHOWNORMAL||
			state==SW_SHOW)state=SW_HIDE;

		return org_pShowWindow(hWnd,state);
	}

	void installHook(){
		org_pShowWindow=(pShowWindow)::GetProcAddress(::GetModuleHandleA("user32"),"ShowWindow");
		replaceAddress("user32.dll",
					   reinterpret_cast<PROC>(org_pShowWindow),
					   reinterpret_cast<PROC>(showWindow),
					   ::GetModuleHandle(NULL));
	}

	void uninstallHook(){
		replaceAddress("user32.dll",
					   reinterpret_cast<PROC>(showWindow),
					   reinterpret_cast<PROC>(org_pShowWindow),
					   ::GetModuleHandle(NULL));
	}
}

//extern "C"必須
extern "C" BOOL WINAPI DllMainCRTStartup(HINSTANCE instance_handle,DWORD reason,LPVOID reserved){
	switch(reason){
		case DLL_PROCESS_ATTACH:
			// attach to process
			// return FALSE to fail DLL load
			//DLL_THREAD_ATTACHとDLL_THREAD_DETACHを無効にする
			::DisableThreadLibraryCalls(instance_handle);

			hook::installHook();
			break;

		case DLL_PROCESS_DETACH:
			// detach from process
			hook::uninstallHook();
			break;

		case DLL_THREAD_ATTACH:
			// attach to thread
			break;

		case DLL_THREAD_DETACH:
			// detach from thread
			break;
	}
	return TRUE;// succesful
}
