This sounds like what you are looking for. You may have found a solution already, but I thought I would pass this on. I use linux and play NWN and would love to be able to use nwshader. OGC (referred to in the article) seems like it is some kind of multiplayer cheat that works by interrupting Opengl, much like what nwshader does but for a different purpose.
http://aimbots.net/tutorials/14575-detours-linux-windows.html
Detours for Linux & Windows
This is a basic "Hello world" detour example in C++.
It does not make use of the Microsoft detour library.
Therefore it works on Windows, Linux and Mac.
I used the detour and undetour functions from OGC, but corrected it for IA64, and I also corrected the bug that made it crash on Fedora.
Also, it works with C++. If you want to use it with pure C, you need to remove the C++ style typecasts, as well as the template.
You don't need the template in C anyway, since C lets you convert any pointer to void* without any error or even warning.
Works with IA-32 & IA-64 & AMD64 x86 processors.
To be fully working, you would need to include a disassembler and adjust relative jumps in the 5+ bytes detourlength. You would also need to take care if you are writing over to the next memory page. (It almost never happens, but it could happen.)
On IA-64, you can maximally jump 4 Gigabytes. That should be sufficient for any normal program, however.
if ( defined (_WIN32) || defined (_WIN64) )
#define WIN32_LEAN_AND_MEAN
#define WIN64_LEAN_AND_MEAN
#include <windows.h>
#define unprotect(addr,len) (VirtualProtect(addr,len,PAGE_EXECUTE_READWRITE,&oldprot))
#define GETPAGESIZE() getpagesize()
DWORD oldprot ;
unsigned long getpagesize (void)
{
static long g_pagesize = 0 ;
if (! g_pagesize)
{
SYSTEM_INFO system_info ;
GetSystemInfo(&system_info) ;
g_pagesize = system_info.dwPageSize ;
}
return (unsigned long) g_pagesize ;
}
#define CLEAR_SCREEN "cls"
else // LINUX / UNIX / OS X
#include <unistd.h>
#include <sys/mman.h>
#define unprotect(addr,len) (mprotect(addr,len,PROT_READ|PROT_WRITE|PROT_EXEC))
#define GETPAGESIZE() sysconf (_SC_PAGE_SIZE)
#define CLEAR_SCREEN "reset"
endif
include
include
include
unsigned long uslngPageSize = 0 ;
unsigned long uslngPageMask = 0 ;
#define JMP_OPCODE 0xE9
#define OPCODE_LENGTH 1
#define DATATYPE_ADDRESS int
#define ADDRESS_LENGTH (sizeof(DATATYPE_ADDRESS))
#define MIN_REQUIRED_FOR_DETOUR (OPCODE_LENGTH + ADDRESS_LENGTH)
#define INT_DETOUR_FACTOR 1
#define OPCODE_NOT_DEFINED 0
// offset[ENGINE][FUNCTION_NAME] ;
// detourlength[ENGINE][FUNCTION_NAME]
define HOTPATCH(FUNCTION_NAME) \
original_##FUNCTION_NAME = TemplateFuncInterceptFunction( \
original_##FUNCTION_NAME, \
reinterpret_cast<unsigned long> (&FUNCTION_NAME), \
reinterpret_cast<unsigned long> (&modified_##FUNCTION_NAME), \
static_cast<unsigned long> (FUNCTION_NAME##_COPY) \
)
define UNPATCH(FUNCTION_NAME) \
unpatchfunc( reinterpret_cast<void*>(reinterpret_cast<unsigned long>(&FUNCTION_NAME)), reinterpret_cast<unsigned char*> (reinterpret_cast<unsigned long>( original_##FUNCTION_NAME)), static_cast<unsigned long> (FUNCTION_NAME##_COPY))
define NATURALIZE(FUNCTION_NAME) \
Naturalized_##FUNCTION_NAME = FuncConvertAddress(Naturalized_##FUNCTION_NAME, &FUNCTION_NAME)
template
DataType FuncConvertAddress(const DataType dt_FunctionPointer, unsigned long uslng_FunctionAddress)
{
return reinterpret_cast (uslng_FunctionAddress) ;
}
void* FuncGetPage(const unsigned long &uslngVirtualMemoryAddress)
{
return reinterpret_cast (uslngVirtualMemoryAddress & uslngPageMask) ;
}
void* InterceptFunction (void* voidptr_AddressOfDetouredFunction, unsigned long uslng_CopyLength, void* voidptr_AddressOfDetourFunction)
{
DATATYPE_ADDRESS Relocation ;
//printf("copy length: %ld\n", uslng_CopyLength);
//printf("MIN_REQUIRED_FOR_DETOUR : %d\n", MIN_REQUIRED_FOR_DETOUR );
void* voidptr_BackupForOriginalFunction = malloc( uslng_CopyLength + MIN_REQUIRED_FOR_DETOUR ) ;
//printf("Sizeof Backuppointer %ld\n", sizeof(voidptr_BackupForOriginalFunction));
//printf("Sizeof AddrDetouredFunction %d\n", sizeof(voidptr_AddressOfDetouredFunction));
memcpy( voidptr_BackupForOriginalFunction, voidptr_AddressOfDetouredFunction, uslng_CopyLength) ;
if (OPCODE_NOT_DEFINED)
{
printf("Error: OP-Code not defined\n.") ;
exit(EXIT_FAILURE) ;
}
memset( reinterpret_cast<void*> (reinterpret_cast<unsigned long> (voidptr_BackupForOriginalFunction) + uslng_CopyLength),
JMP_OPCODE, OPCODE_LENGTH ) ;
Relocation = static_cast<DATATYPE_ADDRESS> (reinterpret_cast<unsigned long> (voidptr_AddressOfDetouredFunction)
- (reinterpret_cast<unsigned long> (voidptr_BackupForOriginalFunction)
+ MIN_REQUIRED_FOR_DETOUR)) ;
memcpy( reinterpret_cast<void*> ( reinterpret_cast<unsigned long> (voidptr_BackupForOriginalFunction)
+ uslng_CopyLength + OPCODE_LENGTH), &Relocation, ADDRESS_LENGTH) ;
unprotect(FuncGetPage(reinterpret_cast <unsigned long> (voidptr_AddressOfDetouredFunction)),uslngPageSize) ;
memset(voidptr_AddressOfDetouredFunction, JMP_OPCODE, OPCODE_LENGTH) ;
Relocation = static_cast<DATATYPE_ADDRESS> ( reinterpret_cast<unsigned long> (voidptr_AddressOfDetourFunction)
- (reinterpret_cast<unsigned long> (voidptr_AddressOfDetouredFunction)
+ MIN_REQUIRED_FOR_DETOUR)) ;
memcpy( reinterpret_cast<void*> (reinterpret_cast<unsigned long> (voidptr_AddressOfDetouredFunction)
+ OPCODE_LENGTH), &Relocation, ADDRESS_LENGTH) ;
unprotect(FuncGetPage(reinterpret_cast <unsigned long> (voidptr_BackupForOriginalFunction)),uslngPageSize) ;
return voidptr_BackupForOriginalFunction ;
}
// C++ is typesafe, they said...
// I say: Yes, but at which price ?
template
DataType TemplateFuncInterceptFunction( DataType dt_Original_Function, unsigned long uslng_FunctionAddress,
unsigned long uslng_modified_FunctionName, unsigned long uslng_DetourLength)
{
return reinterpret_cast
( reinterpret_cast
( InterceptFunction( reinterpret_cast (uslng_FunctionAddress),
uslng_DetourLength,
reinterpret_cast (uslng_modified_FunctionName)
)
)
);
}
void SayHello()
{
printf("Hello World\n");
}
void modified_SayHello()
{
printf("** World\n");
}
void (*original_SayHello)();
//#define SayHello_COPY 9
define SayHello_COPY 6
void unpatchfunc(void* patched_function, unsigned char* original_function, unsigned long uslng_DetourLength)
{
//DWORD dw_OldProtect;
//VirtualProtect(patched_function, uslng_DetourLength, PAGE_EXECUTE_READWRITE, &dw_OldProtect);
unprotect(FuncGetPage(reinterpret_cast(patched_function) ), uslngPageSize) ;
unsigned int intIndex;
for( intIndex = 0; intIndex < uslng_DetourLength; ++intIndex)
( (unsigned char) patched_function + intIndex) = *(original_function + intIndex) ;
//VirtualProtect(patched_function, uslng_DetourLength, dw_OldProtect, &dw_OldProtect);
unprotect(FuncGetPage(reinterpret_cast<unsigned long>(patched_function) ), uslngPageSize) ;
if(original_function!=NULL)
free( (void*) original_function) ;
}
int main()
{
system( CLEAR_SCREEN ) ;
uslngPageSize = GETPAGESIZE() ;
uslngPageMask = ( ~(uslngPageSize - 1) ) ;
printf("PageSize: %ld\n", uslngPageSize) ;
printf("PageMask: 0x%08lX\n", uslngPageMask) ;
SayHello() ;
printf("Hotpatching now!!!\n") ;
HOTPATCH(SayHello) ;
printf("Hotpatched:\n") ;
SayHello() ;
printf("Backup:\n") ;
original_SayHello() ;
printf("Unpatching now\n") ;
UNPATCH(SayHello);
// expands to: unpatchfunc( (void*) SayHello, (unsigned char*) original_SayHello, (int) SayHello_COPY) ;
printf("Unpatched:\n") ;
SayHello() ;
printf("EXIT_SUCCESS\n") ;
return EXIT_SUCCESS ;
}
Edit: Note that if you include this function in a 64 bit shared library/dll on Linux, you will get a segmentation fault. This is because 64-Bit shared libraries can only be compiled with -fPIC, which makes detouring more difficult, because you have to read the PLT before each jump. You need to compile the shared library as 32 bit Shared Object (-m32) and run it with a 32-Bit executable.