/* * uMod_DetourEntry.h * * Created on: 13.01.2013 * Author: marts */ #ifndef UMOD_DETOURENTRY_H_ #define UMOD_DETOURENTRY_H_ #include "uMod_Main.h" #ifdef __CDT_PARSER__ #define NULL 0 #endif class uMod_Detour_Entry_Base { public: uMod_Detour_Entry_Base() {} virtual ~uMod_Detour_Entry_Base() {} virtual void TestLib(const char* lib_name, HMODULE plib) = 0; virtual void TestLib(const wchar_t* lib_name, HMODULE plib) = 0; virtual void FreeLib(HMODULE plib) = 0; virtual void Detour(void) = 0; virtual void Retour(void) = 0; }; template class uMod_Detour_Entry : public uMod_Detour_Entry_Base { public: uMod_Detour_Entry(const int num_bytes); virtual ~uMod_Detour_Entry(); virtual void TestLib(const char* lib_name, HMODULE plib); virtual void TestLib(const wchar_t* lib_name, HMODULE plib); virtual void FreeLib(HMODULE plib); virtual void Detour(void); virtual void Retour(void); bool CheckForDetour(); int SetFunctionName( const char* name) {return SetName( FunctionName, name);} int SetLibName( const char* name) {return SetName( LibName, name);} int SetFullLibName( const char* name) {return SetName( FullLibName, name);} int SetLibName( const wchar_t* name) {return SetName( LibNameW, name);} int SetFullLibName( const wchar_t* name) {return SetName( FullLibNameW, name);} void SetOrigFunction(T func) {OrigFunction = func;} void SetTargetFunction(T func) {TargetFunction = func;} T Function(void) const {return OrigFunction;} private: int SetName( char* &member_var, const char* name); int SetName( wchar_t* &member_var, const wchar_t* name); char* FunctionName; char* LibName; char* FullLibName; wchar_t* LibNameW; wchar_t* FullLibNameW; HMODULE PLibrary; int RefCounter; const int NumBytes; T OrigFunction; T TargetFunction; BYTE* DetourFunction; bool IsDetoured; bool IsFailed; }; template uMod_Detour_Entry::uMod_Detour_Entry(const int num_bytes) : FunctionName(NULL), LibName(NULL), FullLibName(NULL), LibNameW(NULL), FullLibNameW(NULL), PLibrary(NULL), NumBytes(num_bytes), OrigFunction(NULL), TargetFunction(NULL), DetourFunction(NULL), IsDetoured(false), IsFailed(false) { } template uMod_Detour_Entry::~uMod_Detour_Entry() { if (FunctionName!=NULL) delete [] FunctionName; if (LibName!=NULL) delete [] LibName; if (FullLibName!=NULL) delete [] FullLibName; if (LibNameW!=NULL) delete [] LibNameW; if (FullLibNameW!=NULL) delete [] FullLibNameW; if (DetourFunction!=NULL) delete [] DetourFunction; } template void uMod_Detour_Entry::TestLib(const char* lib_name, HMODULE plib) { if (lib_name==NULL) return; if (plib==NULL) return; if (FunctionName==NULL) return; if (LibName==NULL) return; if (PLibrary==plib) { RefCounter++; //return; } int len=0; while (lib_name[len]) len++; while (len>=0 && (lib_name[len]!='/' && lib_name[len]!='\\')) len--; len++; if (_stricmp( &lib_name[len], LibName)==0) { bool set_detour = true; if (FullLibName!=NULL) { set_detour = false; GlobalDetour.Detour_LoadLibraryA.Retour(); GlobalDetour.Detour_FreeLibrary.Retour(); HMODULE test_handle = LoadLibraryA( FullLibName); //get handle of original library if (test_handle==NULL || test_handle==plib) set_detour = true; // test if library (loaded by the game) is the original one or a fake one //if (test_handle!=NULL) FreeLibrary( test_handle); // free the library (we don't want top disturb our own RefCounter) GlobalDetour.Detour_LoadLibraryA.Detour(); GlobalDetour.Detour_FreeLibrary.Detour(); } if (!set_detour) return; // it is not the official library (or FullLibName is not set) if (CheckForDetour()) return; OrigFunction = (T) GetProcAddress(plib, FunctionName); if (OrigFunction==NULL) return; // this library does not contain the function we want to detour Message("uMod_Detour_Entry::TestLib( %s, %p ) set detour -> %s \n", lib_name, plib, FunctionName); RefCounter = 1; PLibrary = plib; IsDetoured = false; IsFailed = false; Detour(); } } template void uMod_Detour_Entry::TestLib(const wchar_t* lib_name, HMODULE plib) { if (lib_name==NULL) return; if (plib==NULL) return; if (FunctionName==NULL) return; if (LibNameW==NULL) return; if (PLibrary==plib) { RefCounter++; // return; } int len=0; while (lib_name[len]) len++; while (len>=0 && (lib_name[len]!='/' && lib_name[len]!='\\' )) len--; len++; if (_wcsicmp( &lib_name[len], LibNameW)==0) { bool set_detour = true; if (FullLibNameW!=NULL) { set_detour = false; GlobalDetour.Detour_LoadLibraryW.Retour(); GlobalDetour.Detour_FreeLibrary.Retour(); HMODULE test_handle = LoadLibraryW( FullLibNameW); //get handle of original library if (test_handle==NULL || test_handle==plib) set_detour = true; // test if library (loaded by the game) is the original one or a fake one if (test_handle!=NULL) FreeLibrary( test_handle); // free the library (we don't want top disturb our own RefCounter) GlobalDetour.Detour_LoadLibraryW.Detour(); GlobalDetour.Detour_FreeLibrary.Detour(); } if (!set_detour) return; // it is not the official library (or FullLibName is not set) if (CheckForDetour()) return; OrigFunction = (T) GetProcAddress(plib, FunctionName); if (OrigFunction==NULL) return; // this library does not contain the function we want to detour Message("uMod_Detour_Entry::TestLib( %ls, %p ) set detour -> %s \n", lib_name, plib, FunctionName); RefCounter = 1; PLibrary = plib; IsDetoured = false; IsFailed = false; Detour(); } } template void uMod_Detour_Entry::FreeLib(HMODULE plib) { if (plib==NULL) return; if (plib==PLibrary) RefCounter--; if (RefCounter<=0) PLibrary = NULL; } template void uMod_Detour_Entry::Detour(void) { if (IsDetoured || IsFailed) return; if (DetourFunction==NULL) { DetourFunction = new BYTE[NumBytes+5]; } BYTE *jmp = DetourFunction; BYTE *src = (BYTE*) OrigFunction; const BYTE *dst = (BYTE*) TargetFunction; const int len = NumBytes; DWORD dwback = 0; //(jmp, len+5, PAGE_EXECUTE_READWRITE, &dwback); //This is the addition needed for Windows 7 RC if(!VirtualProtect(src, NumBytes, PAGE_READWRITE, &dwback)) IsFailed = true; if(!memcpy(jmp, src, len)) IsFailed = true; jmp += len; jmp[0] = 0xE9; *(DWORD*)(jmp+1) = (DWORD)(src+len - jmp) - 5; //memset(src, 0x90, len); src[0] = 0xE9; *(DWORD*)(src+1) = (DWORD)(dst - src) - 5; if(!VirtualProtect(src, len, dwback, &dwback)) IsFailed = true; IsDetoured = true; } template void uMod_Detour_Entry::Retour(void) { if (!IsDetoured || IsFailed) return; BYTE *src = (BYTE*) OrigFunction; BYTE *restore = DetourFunction; const int len = NumBytes; DWORD dwback; if(!VirtualProtect(src, len, PAGE_READWRITE, &dwback)) IsFailed = true; if(!memcpy(src, restore, len)) IsFailed = true; restore[0] = 0xE9; *(DWORD*)(restore+1) = (DWORD)(src - restore) - 5; if(!VirtualProtect(src, len, dwback, &dwback)) IsFailed = true; IsDetoured = false; } template bool uMod_Detour_Entry::CheckForDetour() { if (DetourFunction==NULL) return false; //BYTE *jmp = DetourFunction; BYTE *src = (BYTE*) OrigFunction; const BYTE *dst = (BYTE*) TargetFunction; //const int len = NumBytes; if (src[0] != 0xE9) return false; if ( *(DWORD*)(src+1) != (DWORD)(dst - src) - 5) return false; return true; } template int uMod_Detour_Entry::SetName( char* &member_var, const char* name) { if (member_var!=NULL) delete [] member_var; member_var = NULL; int len=0; while (name[len]) len++; len++; member_var = new char[len]; len = 0; while (name[len]) {member_var[len] = name[len]; len++;} member_var[len] = 0; return 0; } template int uMod_Detour_Entry::SetName( wchar_t* &member_var, const wchar_t* name) { if (member_var!=NULL) delete [] member_var; member_var = NULL; int len=0; while (name[len]) len++; len++; member_var = new wchar_t[len]; len = 0; while (name[len]) {member_var[len] = name[len]; len++;} member_var[len] = 0; return 0; } #endif /* UMOD_DETOURENTRY_H_ */