Home > C, Linux, OpenGL, Programming > Overriding dynamic library calls (function interposition)

Overriding dynamic library calls (function interposition)

About function interposition

I was wondering how I could override dynamic library calls in Linux, and I came across this technique known as function interposition. It is a powerful technique that allows you to override dynamic library calls. It might sound dull, but it can be very, very useful. There are some memory trace tools that make use of this technique to work, but perhaps a cooler example is the OpenGL capture system which was created by nullkey: it can capture OpenGL frames by overriding certain OpenGL functions. Another example are cheat tools (wallhacks, aimbots) which also make use of this technique a lot.

Some background

While Googling (did I spell that right?) I came across this recent blog article which explains the background very well. I will quote it here:

First, some background. When a program that uses dynamic libraries is compiled, a list of undefined symbols is included in the binary, along with a list of libraries the program is linked with. There is no correspondence between the symbols and the libraries; the two lists just tell the loader which libraries to load and which symbols need to be resolved. At runtime, each symbol is resolved using the first library that provides it. This means that if we can get a library containing our wrapper functions to load before other libraries, the undefined symbols in the program will be resolved to our wrappers instead of the real functions.

So if we create a custom shared library which overrides some of the functions of the original library, our functions will be called instead of those of the original library.

How to do it

  • Write new functions which override existing functions
  • Compile the written code to a dynamic library that is linked to the dynamic linking interface library
  • Use the LD_PRELOAD environment variable when running an application to preload your custom library before all other dynamic libraries

The article by Jay Conrod has an example which shows you the basic implementation of a simple memory allocation tracer.

I have also cooked up an example myself. Because I’ve been busy learning more about OpenGL, I thought that it shouldn’t be too hard to create a wallhack for one of my favourite games: Soldier of Fortune 2 running in Wine. Just for testing purposes of course! I am no cheater :D It turned out to be relatively simple, although my first tries weren’t so very successful:

  • Epic fail – At least I know my library is used now.
  • Partial success – Disabling depth testing completely was only a partial success.
  • Success – A debugger can tell that players are drawn using glDrawElements(). By knowing the number of elements for each character, we can disable depth testing selectively.
Soldier of Fortune 2 wallhack example

Soldier of Fortune 2 wallhack example

For those of you who are interested in the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
    Simple wallhack example for Soldier of Fortune 2 (Wine) in Linux using function interposition

    This code snippet was written by Wesley Stessens (wesley@ubuntu.com)
    It is released in the Public Domain.

    Compilation: gcc -Wall -ansi -pedantic -shared -ldl -fPIC glhack.c -o glhack.so
    Usage: LD_PRELOAD=glhack.so wine game.exe
*/


#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdint.h>
#include <GL/gl.h>

/* Override the glDrawElements function */
GLAPI void GLAPIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
    /* Store the actual function in a static function pointer */
    static void (*glDrawElements_)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) = NULL;
    if (!glDrawElements_) {
        glDrawElements_ = (void(*)())(intptr_t)dlsym(RTLD_NEXT, "glDrawElements");
        puts("GLHack: glDrawElements call has been overridden");
    }

    /* Disable depth testing if the number of elements to draw is one of the following, which means a player is being drawn */
    /* To avoid abuse of this code by cheaters, I have changed all count constants below to VALUEX */
    if (count == VALUE1 || count == VALUE2 || count == VALUE3 || count == VALUE4)
        glDisable(GL_DEPTH_TEST);
    else
        glEnable(GL_DEPTH_TEST);
    glDrawElements_(mode, count, type, indices);
}

Interesting thought about multiplayer cheats and Wine

If anti-cheat tools would perform a sanity check of the OpenGL or DirectX DLL, they would only find the virtual DLL’s when a game is run in Wine, right? I’m wondering whether this sort of cheats can be made undetectable then. In a way I hope not, because cheaters are very annoying when you’re playing a game, but on the other hand, it would be an amazing technological achievement. Anyway, anti-cheat tools like PunkBuster don’t even work with Wine at the moment, so it might be a non-issue. What are your thoughts?

VN:F [1.6.3_896]
Rating: +1 (from 1 vote)
Share and Enjoy:
  • Print this article!
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • StumbleUpon
  • Twitter
Categories: C, Linux, OpenGL, Programming
  1. August 18th, 2009 at 11:04 | #1

    Programs that use rootkit-like functionality in Windows can’t work in Wine, and a similar attack is plausible within Windows without such rootkits. So there’s not much to worry about here for Wine users.

  2. August 18th, 2009 at 12:30 | #2

    LD_PRELOAD is possibly one of the most useful features of the runtime linker on POSIXy systems. I have a “line-buffer” script in my $HOME/bin which preloads a shared library which basically does setvbuf(stdout, NULL, _IOLBF, 0) in a function marked __attribute__((constructor)) to force line buffering for misbehaving (ie: badly written) software for which I have no source code, or for which I don’t feel like recompiling the source code.

    I’m also a great fan of tsocks, which uses LD_PRELOAD to wrap socket functions to force communications through a SOCKS proxy (like ssh -D).

  3. Jeff
    August 18th, 2009 at 17:09 | #3

    Cool stuff!

    Your post inspired me and my friend tonight to re-implement ForceBindIP (http://www.r1ch.net/stuff/forcebindip/) for Linux. It’ll be going up on GitHub shortly.

    StarCraft has problems with multiple network interfaces, so to play over a VPN we’d been running it in a VM that knew only about the VPN, but no physical network interfaces. Now those of us who would like to forgo the virtualisation can happily do so.

    Thanks for the inspiration! =)

  4. wouter verhelst
    August 18th, 2009 at 17:37 | #4

    It might be smart to hide the numbers in your code example if you don’t want actual cheaters to abuse your system.

  5. TGM
    August 18th, 2009 at 18:48 | #5

    EverQuest 2 Bots FTW! :D

  6. Wesley
    August 18th, 2009 at 23:12 | #6

    @wouter verhelst
    Yea, okay. I have hidden the numbers now. Although it’s not too hard to find out the needed numbers with a debugger, it will at least be a bit harder for cheaters now.

  7. August 18th, 2009 at 23:34 | #7

    You can easily LD_PRELOAD-override the functions that perform the sanity check of the OpenGL or DirectX DLL, too. Or you can perform post-execution library injection and Global-Offset-Table rewrites after the sanity checks have already finished. (Basically, manually performing the same things the linker does with LD_PRELOAD, but after the program is running, a bit complex, but doable.)

  1. No trackbacks yet.