Wrapping dlsym. Copyright by h1web. Licensed under the GPL.
Today I've made an interesting discovery.
I found out how to wrap dlsym, which is kind of like the ELF equivalent to GetProcAddress.
This is interesting because it allows us to wrap several other functions that are being dynamically imported.
The concept was clear for me before, but a big problem occured. If you wrap dlsym, you somehow need to get the original address to dlsym to resolve the symbols the target program wants to resolve. But since we wrapped it, this is not possible anymore.
In fact it is. libc has a private backend to a lot of functions, including dlsym. So we just use that backend to solve that problem. The private function would be __libc_dlsym. It's declared like the normal one. Here's an example on what you can do with it. It's an ET wallhack:

/* dlsym wrap example.
   Copyright 2007, Henrik "h1web" Friedrichsen
   All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#define __USE_GNU
#include <dlfcn.h>
#include <GL/gl.h>

#include "sdk/cg_local.h"

typedef int (*syscall_t)(int callnum, ...);
syscall_t psyscall 0;
int syscall(int callnumintarg1intarg2intarg3intarg4intarg5intarg6intarg7intarg8intarg9intarg10)
{
        if(
callnum == CG_R_ADDREFENTITYTOSCENE) {
                
refEntity_tent = (refEntity_t*)arg1;
                
ent->renderfx RF_DEPTHHACK;
        }
        return (*
psyscall)(callnumarg1arg2arg3arg4arg5arg6arg7arg8arg9arg10);
}

typedef void (*dllEntry_t)(void*);
dllEntry_t pdllEntry 0;
void dllEntry(voidsyscallptr)
{
        
psyscall = (syscall_t)syscallptr;
        (*
pdllEntry)((void*)&syscall);
}

extern void *__libc_dlsym   (void *__map__const char *__name);
typedef void* (*dlsym_t)(void*, const char*);
dlsym_t pdlsym 0;
void *dlsym(void *handle, const char *symbol)
{
        
voidresult __libc_dlsym(handlesymbol); // the replacement we are going to use
        
if(!strcmp(symbol"dllEntry")) {
                
Dl_info info;
                if(
dladdr(result, &info) && strstr(info.dli_fname"cgame")) {
                        
pdllEntry = (dllEntry_t)result;
                        return (
void*)dllEntry;
                }
        }
        return 
result;