1
0
Files
BSc-Thesis/doc/README.md

3.5 KiB

Intercepting and Manipulating Function and System Calls in Linux

Option 1: Preloading (LD_PRELOAD)

From the ENVIRONMENT section in the Linux manual page ld.so(8):

LD_PRELOAD

A list of additional, user-specified, ELF shared objects to be loaded before all others. This feature can be used to selectively override functions in other shared objects. [...]

  • No need to re-link
  • Works for all functions
  • Works only on dynamically linked executables
  • Intercepts all calls (including calls inside libraries etc.)

Example (preload.c):

#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>

void *malloc(size_t size) {
    // before call to malloc
    void *(*_malloc)(size_t);
    if ((_malloc = dlsym(RTLD_NEXT, "malloc")) == NULL) {
        errno = ENOSYS;
        return NULL;
    }
    void *ret = _malloc(size);
    // after call to malloc
    return ret;
}
# ./main is already compiled and ready
gcc -shared -fPIC -o preload.so preload.c
LD_PRELOAD="$(pwd)/preload.so" ./main

Option 2: Wrapper functions (gcc -Wl,--wrap=, ld --wrap=)

From the OPTIONS section in the Linux manual page ld(1):

--wrap=symbol

Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_<symbol>. Any undefined reference to __real_<symbol> will be resolved to symbol.

This can be used to provide a wrapper for a system function. The wrapper function should be called __wrap_<symbol>. If it wishes to call the system function, it should call __real_<symbol>. [...]

From the OPTIONS section in the Linux manual page gcc(1):

-Wl,option

Pass option as an option to the linker. If option contains commas, it is split into multiple options at the commas. You can use this syntax to pass an argument to the option. For example, -Wl,-Map,output.map passes -Map output.map to the linker. When using the GNU linker, you can also get the same effect with -Wl,-Map=output.map.

  • Need to re-link(/-comiple)
  • Relatively simple code:
    • Function name: __wrap_<symbol>
    • Call to real function inside wrapper: __real_<symbol>
  • Works for all functions
  • Works only on dynamically linked executables
  • Intercepts only calls inside the given source file

Example (wrap.c):

extern void *__real_malloc(size_t size);

void *__wrap_malloc(size_t size) {
    // before call to malloc
    void *ret = __real_malloc(size);
    // after call to malloc
    return ret;
}
gcc -o main_wrapped main.c wrap.c -Wl,--wrap=malloc
./main_wrapped

Option 3: Kernel module

  • Only works with Linux system calls
  • Also works with statically linked executables
  • Only possible with some "hacks" inside the kernel module (to access the Syscall Table)
  • litux.nl?

Option 4: Emulating

  • Valgrind, GDB

Option 5: Modifying the kernel

  • Add a special Syscall to intercept/modify other Syscalls