端口Win32的DLL挂钩到Linux

我有一个程序(NWShader)挂到第二个程序的OpenGL调用(NWN)做后处理效果和什么。

NWShader最初是为Windows构build的,通常是现代版本(win32),同时使用DLL导出(以获取Windows加载它并获取一些OpenGL函数)和Detours(挂钩到其他函数)。 我使用的技巧,在检查sysdir之前,Win将在当前目录中查找任何DLL,因此会加载我的。 我有在这个方法redirect的DLL:

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

将它们发送到我自己的DLL中不同的命名函数。 然后我做任何处理,并从系统DLL调用原来的function。

我需要将NWShader移植到Linux(NWN存在于两种版本中)。 据我所知,我需要做的是共享库(.so文件)。 如果这是在NWN可执行文件(我发现一个shell脚本来处理这个)之前预加载,我的函数将被调用。 唯一的问题是我需要调用原始函数(我会使用各种DLLdynamic加载方法,我认为),需要能够执行类似Detour的内部函数挂钩。

目前,我正在构buildUbuntu 9.10 x64(带有32位编译器标志)。 我在Google上找不到太多帮助,但是我不知道这个* nix社区究竟是指什么的。 我可以编写C ++,但我更习惯于Windows。 作为OpenGL,需要修改与Linux兼容的唯一部分是钩子代码和调用。 有没有一个简单而简单的方法来做到这一点,或者它会涉及重新创buildDetours并dynamic加载原始函数地址?

Solutions Collecting From Web of "端口Win32的DLL挂钩到Linux"

库预加载可以通过LD_PRELOAD完成。 从那里你要看看dlopendlsym调用来获取原始库中的实际功能。 这是所有如果你想手工做的事情。

你也可以看一下修改ltrace的方式,使得你可以提供钩子函数(通过-e标志),让ltrace为你处理簿记。

[编辑]手工做的一个例子:

 #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); } 

和一个程序,如

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

你得到以下几点:

 $ ./a.out Hello World $ LD_PRELOAD=./libhook ./a.out I have hooked your puts Hello World 

这听起来像你在找什么。 你可能已经找到了解决办法,但我想我会通过这个。 我使用Linux和播放NWN,并希望能够使用nwshader。 OGC(在文章中提到)似乎是某种多人作弊,通过中断Opengl,很像nwshader做的,但为了一个不同的目的。

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

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 <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 ; } 

编辑:请注意,如果您将此函数包含在Linux上的64位共享库/ dll中,则会出现分段错误。 这是因为64位共享库只能使用-fPIC编译,这使得绕行变得更加困难,因为在每次跳转之前必须读取PLT。 您需要将共享库编译为32位共享对象(-m32)并使用32位可执行文件运行。

如您所述,将自己的oldfunc到共享库中并预加载它。 但是也可以编写一些在原始库上调用dlopen()初始化函数,并使用dlsym()来获取指向原始oldfunc函数的函数指针。 (这些函数分别是LoadLibraryGetProcAddress的Unix等价物。)

您可以查看共享ELF库中的函数重定向方法。 附有代码 它允许你钩住特定模块的特定功能。