我有一个程序(NWShader)挂钩到第二个程序的OpenGL调用(NWN)来做后处理效果等等。
NWShader最初是为Windows构建的,通常是现代版本(win32),并使用DLL导出(让Windows加载它并获取一些OpenGL函数)和Detours(挂钩到其他函数)。我正在使用Win在查看sysdir之前在当前目录中查找任何DLL的技巧,因此它会加载我的。我在DLL上使用此方法重定向:
#pragma comment(linker, "/export:oldFunc=nwshader.newFunc)
将它们发送到我自己的DLL中的其他命名函数。然后我做任何处理并从系统DLL调用原始函数。
我需要将NWShader移植到Linux(NWN存在于两种版本中)。据我所知,我需要做的是一个共享库(.so文件)。如果这是在NWN可执行文件之前预加载的(我找到了一个shell脚本来处理它),我的函数将被调用。唯一的问题是我需要调用原始函数(我会使用各种DLL动态加载方法,我认为)并且需要能够像Detour一样进行内部函数挂钩。
目前我正在构建Ubuntu 9.10 x64(使用32位编译器标志)。我无法在Google上找到太多帮助,但我不确切地知道* nix社区所指的是什么。我可以编写C ++代码,但我更习惯于Windows。作为OpenGL,需要修改以与Linux兼容的唯一部分是挂钩代码和调用。有没有一种简单易用的方法,或者它是否涉及重新创建Detours并动态加载原始函数地址?
答案 0 :(得分:5)
库预加载可以通过LD_PRELOAD
完成。从那里,您需要查看dlopen
和dlsym
调用以获取原始库中的实际函数。如果您想手工做事,这就是全部。
您还可以通过某种方式修改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
答案 1 :(得分:3)
这听起来像你在找什么。您可能已经找到了解决方案,但我想我会通过这个解决方案。我使用linux并玩NWN,并希望能够使用nwshader。 OGC(在文章中提到)似乎是通过打断Opengl来实现的某种多人作弊,就像nwshader所做的那样,但是出于不同的目的。
http://aimbots.net/tutorials/14575-detours-linux-windows.html
适用于Linux的Detours&amp;视窗
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位可执行文件运行它。
答案 2 :(得分:2)
如您所述,将您自己的oldfunc
写在共享库中并预加载它。但是还要编写一些在原始库上调用dlopen()
的初始化,并dlsym()
来获取指向原始oldfunc
的函数指针。 (这些函数分别是LoadLibrary
和GetProcAddress
的Unix等价物。)
答案 3 :(得分:0)
您可以查看functions redirection in shared ELF libraries的方法。附有代码。它允许您从特定模块挂钩特定功能。