As of El Capitan, I came across a super stupid issue with Apple being a bit over secure. Function hooking can only be done on user installed applications AND require modification on the assembly level. So we require a new way of hooking called DYLD-Interposing instead of Trampolines.
SIP: http://apple.stackexchange.com/quest...capitan-really
Hooking functions on Linux and Windows:
Load original module.
Get pointer to all original functions.
Name your functions the same as the originals (same signature too).
Have your functions call the originals.
Example (for the Pascal guys):
Pascal Code:
{$ifdef windows}
var module: HMODULE;
module := LoadLibraryA('opengl32.dll');
original_glEnable := GetProcAddress(module, "glEnable");
{$else}
var module: pointer;
module := dlopen('libGL.so', RTLD_LAZY | RTLD_GLOBAL);
original_glEnable := dlsym(module, 'glEnable');
{$endif}
...
..
..
procedure glEnable(caps: GLenum);
begin
original_glEnable(caps);
end;
For the C/C++ guys:
C++ Code:
#if defined(_WIN32) || defined(_WIN64)
void* module = LoadLibrary("opengl32.dll");
original_glEnable = GetProcAddress(module, "glEnable");
#else
void* module = dlopen("libGL.so", RTLD_LAZY | RTLD_GLOBAL);
original_glEnable = dlsym(module, "glEnable");
#endif
...
..
..
void glEnable(GLenum caps)
{
//do your hook code here..
original_glEnable(caps);
}
In both cases, the hook function is the exact same name as the original. You do your hook code then you do the original. It's pretty much a trampoline.
The program calls your hook first. Your hook runs and then calls the original. This is because the runtime sees your symbols first and they are given priority over any modules loaded afterwards.
However, on OSX (El Capitan and above), the above approaches will NEVER work. It used to work on Yosemite ={
The new approach requires a technique call Function Interposing.. It's the same thing, but on the machine level/assembly level.
C++ Code:
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \
__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };
void pGLEnable(GLEnum caps)
{
glEnable(caps);
}
DYLD_INTERPOSE(pGLEnable, glEnable);
//Hook glEnable so that it points to pGLEnable (our function).
//
How the above works? It replaces the original function in the .data section of the executable/assembly/module with your hook function. However, since the original function is also loaded, you then have to call the original function within your hook just like before. Instead of calling it through a pointer obtained through dlsym and dlopen, you call it directly. This gets rid of Apple's SIP and DYLD_FORCE_NAMESPACE=1 requirements.
It may seem easier and in reality, it is because you don't have to load the original, store pointers, etc.. However, if writing cross platform code, you have to do that anyway! + the special Apple way -_-..
You still have to do DYLD_INSERT_LIBRARIES (equivalent of Linux's LD_PRELOAD). I'm not sure if this will work on system level applications though. It fails for Safari and any Apple signed applications as the root entitlements block DYLD_INSERT_LIBRARIES.