For people looking for a very easy way to hook OpenGL in linux: use dlsym().
It is very easy to use and also very powerful.
Use it with:
If you are hooking a game that uses wine:
You will also need to patch wine:
We basicly get a pointer to the glXSwapBuffers function by hooking glXGetProcAddressARB. We do this because wine uses glXGetProcAddressARB to do it, so thats the best way.
credits:
RoKFenris WINE patch
Sednogmah glswapbuffer hook
NOTE: the address to the libGL library may vary on different systems. "/usr/lib/i386-linux-gnu/libGL.so" for me (ubuntu 32bit).
C++:
#define _GNU_SOURCE
/* These libraries are necessary for the hook */
#include <dlfcn.h>
#include <stdlib.h>
#include <GL/gl.h>
/* "Injected" stuff */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static int framecnt = 0;
// our detour function
void HackFrame() {
// do our stuff
framecnt++;
printf("frame %d... \n", framecnt);
}
// hook glClear
void glClear(GLbitfield mask) {
static void (*lib_glClear)(GLbitfield mask) = NULL;
void* handle;
char* errorstr;
if(!lib_glClear) {
/* Load real libGL */
handle = dlopen("/usr/lib/i386-linux-gnu/libGL.so", RTLD_LAZY);
if(!handle) {
fputs(dlerror(), stderr);
exit(1);
}
/* Fetch pointer of real glClear() func */
lib_glClear = dlsym(handle, "glClear");
if( (errorstr = dlerror()) != NULL ) {
fprintf(stderr, "dlsym fail: %s\n", errorstr);
exit(1);
}
}
/* Woot */
HackFrame();
/* Call real glClear() */
lib_glClear(mask);
}
Use it with:
C++:
LD_PRELOAD=./our_library ./our_game
If you are hooking a game that uses wine:
C++:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <GL/gl.h>
#include <GL/glx.h>
void hookfunc();
/*
* Unfortunately WINE needs to be patched to allow hooking this via
* LD_PRELOAD.
*
* 1) Instead of using the default RTLD loader, WINE retrieves the address
* for glXGetProcAddressARB directly from the OpenGL library.
* This is done to enable binary compatibility to systems with or without
* OpenGL.
*
* Solution: patch WINE to use the default loader
*
* 2) WINE gets the pointers to glx functions via glXGetProcAddressARB
*
* => I'm hooking glXGetProcAddressARB and return my own
* pointer to glXSwapBuffers.
*
*/
typedef __GLXextFuncPtr (*fp_glXGetProcAddressARB) (const GLubyte*);
typedef __GLXextFuncPtr (*fp_glXSwapBuffers)(Display* dpy, GLXDrawable drawable);
// glXSwapBuffers
fp_glXSwapBuffers real_glXSwapBuffers;
void my_glXSwapBuffers(Display* dpy, GLXDrawable drawable) {
real_glXSwapBuffers(dpy, drawable);
hookfunc();
}
// glXGetProcAddressARB
__GLXextFuncPtr glXGetProcAddressARB (const GLubyte* procName)
{
__GLXextFuncPtr result;
printf("* hook-glx.c: glXGetProcAddressARB(\"%s\")\n", procName);
// Fetch pointer of actual glXGetProcAddressARB() function
static fp_glXGetProcAddressARB lib_getprocaddr = NULL;
if(!lib_getprocaddr)
{
char* errorstr;
lib_getprocaddr = (fp_glXGetProcAddressARB)
dlsym(RTLD_NEXT, "glXGetProcAddressARB");
if( (errorstr = dlerror()) != NULL )
{
fprintf(stderr, "dlsym fail: %s\n", errorstr);
exit(1);
}
}
result = lib_getprocaddr(procName);
// Return our own function pointers
if( strcmp( (const char*) procName, "glXSwapBuffers" ) == 0 )
{
real_glXSwapBuffers = (fp_glXSwapBuffers) result;
return (__GLXextFuncPtr) my_glXSwapBuffers;
}
// Return default function pointer
return lib_getprocaddr(procName);
}
C++:
diff -Nru wine-1.1.39.orig/dlls/winex11.drv/opengl.c wine-1.1.39/dlls/winex11.drv/opengl.c
--- wine-1.1.39.orig/dlls/winex11.drv/opengl.c 2010-02-27 02:21:02.973526893 +0100
+++ wine-1.1.39/dlls/winex11.drv/opengl.c 2010-02-27 02:27:11.231401387 +0100
@@ -412,7 +412,7 @@
return FALSE;
}
- pglXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
+ pglXGetProcAddressARB = wine_dlsym(RTLD_DEFAULT, "glXGetProcAddressARB", NULL, 0);
if (pglXGetProcAddressARB == NULL) {
ERR("Could not find glXGetProcAddressARB in libGL, disabling OpenGL.\n");
goto failed;
credits:
RoKFenris WINE patch
Sednogmah glswapbuffer hook
NOTE: the address to the libGL library may vary on different systems. "/usr/lib/i386-linux-gnu/libGL.so" for me (ubuntu 32bit).
Last edited: