Win32 DLL port for Linux

I have a program (NWShader) that intercepts a second OpenGL call program (NWN) to perform post-processing effects and something else.

NWShader was originally created for Windows, usually the modern version (win32), and uses both DLL export (to force Windows to load it and capture some OpenGL functions), and Detours (to connect to other functions). I use the trick when Win will look in the current directory for all DLLs before checking sysdir, so it loads mine. I have a DLL that redirects this method:

#pragma comment(linker, "/export:oldFunc=nwshader.newFunc) 

To send them to another named function in my own DLL. Then I do any processing and call the original function from the system DLL.

I need to connect NWShader to Linux (NWN exists in both versions). As far as I can tell, what I need to do is a shared library (.so file). If it is preloaded before NWN execution (I found a shell script to handle this), my functions will be called. The only problem is that I need to call the original function (I think I would use various dynamic methods of the DLL for this), and I need to be able to do hangs with internal functions.

I am currently creating Ubuntu 9.10 x64 (with 32-bit compiler flags). I could not find much on Google to help with this, but I do not know exactly what the * nix community refers to it as. I can encode C ++, but I'm more used to Windows. Being OpenGL, the only part that needs to be changed for compatibility with Linux is the connection code and calls. Is there a simple and easy way to do this, or will it include re-creating Detours and dynamically loading the source addresses of the functions?

+4
c ++ linux dll winapi hook
source share
4 answers

Library LD_PRELOAD can be done through LD_PRELOAD . From there, you want to look at dlopen and dlsym calls to get the actual functions in the source library. That’s all if you want to do something manually.

You can also look at modifying ltrace in such a way that you provide functions for hooking (using the -e flag), and let ltrace handle your account.

[Edit] An example of this manually:

 #include <dlfcn.h> #include <stdio.h> int (*orig_puts)(const char *); int puts (const char * str) { void * handle = dlopen("/lib/libc.so.6", RTLD_NOW | RTLD_GLOBAL); orig_puts = dlsym(handle,"puts"); fprintf (stderr,"I have hooked your puts\n"); return orig_puts(str); } 

And with a program like

 #include <stdio.h> int main () { puts ("Hello World"); return 0; } 

You get the following:

 $ ./a.out Hello World $ LD_PRELOAD=./libhook ./a.out I have hooked your puts Hello World 
+5
source share

This is similar to what you are looking for. You may have found a solution already, but I thought I would pass it on. I use linux and play NWN and would like to use nwshader. OGC (mentioned in the article) seems to be a kind of multi-user cheat that works by interrupting Opengl, just like what nwshader does, but for a different purpose.

http://aimbots.net/tutorials/14575-detours-linux-windows.html

Workaround for Linux and 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 <iostream> #include <cstdlib> #include <cstring> 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 <class DataType> DataType FuncConvertAddress(const DataType dt_FunctionPointer, unsigned long uslng_FunctionAddress) { return reinterpret_cast<DataType> (uslng_FunctionAddress) ; } void* FuncGetPage(const unsigned long &uslngVirtualMemoryAddress) { return reinterpret_cast<void*> (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 <class DataType> DataType TemplateFuncInterceptFunction( DataType dt_Original_Function, unsigned long uslng_FunctionAddress, unsigned long uslng_modified_FunctionName, unsigned long uslng_DetourLength) { return reinterpret_cast<DataType> ( reinterpret_cast<unsigned long> ( InterceptFunction( reinterpret_cast<void*> (uslng_FunctionAddress), uslng_DetourLength, reinterpret_cast<void*> (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<unsigned long>(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: please note that if you include this function in the 64-bit / dll shared library on Linux, you will get a segmentation error. This is because 64-bit shared libraries can only be compiled with -fPIC, which makes it harder to bypass because you have to read the PLT before each jump. You need to compile the shared library as a 32-bit shared object (-m32) and run it with a 32-bit executable.

+3
source share

Write your own oldfunc in the shared library and preload it, as you already mentioned. But also write the initialization that calls dlopen() in the source library, and dlsym() to get a pointer to the source oldfunc . (These functions are the Unix equivalents of LoadLibrary and GetProcAddress respectively.)

+2
source share

You can see the function redirection method in the ELF shared libraries . There the code is attached. This allows you to connect a specific function from a specific module.

0
source share

All Articles