Intercepting and Manipulating Function and System Calls in Linux ================================================================ Option 1: Preloading (`LD_PRELOAD`) {#preloading} ------------------------------------------------- From the [ENVIRONMENT section in the Linux manual page ld.so(8)](https://www.man7.org/linux/man-pages/man8/ld.so.8.html#ENVIRONMENT): > **`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`): ```c #include #include #include 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; } ``` ```shell # ./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=`) {#wrapper-functions} ---------------------------------------------------------------------------------- From the [OPTIONS section in the Linux manual page ld(1)](https://www.man7.org/linux/man-pages/man1/ld.1.html#OPTIONS): > **`--wrap=symbol`** > > Use a wrapper function for *symbol*. > Any undefined reference to *symbol* will be resolved to `__wrap_`. > Any undefined reference to `__real_` will be resolved to *symbol*. > > This can be used to provide a wrapper for a system function. > The wrapper function should be called `__wrap_`. > If it wishes to call the system function, it should call `__real_`. > [...] From the [OPTIONS section in the Linux manual page gcc(1)](https://www.man7.org/linux/man-pages/man1/gcc.1.html#OPTIONS): > **`-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_` * Call to real function inside wrapper: `__real_` * Works for *all* functions * Works only on dynamically linked executables * Intercepts only calls inside the given source file Example (`wrap.c`): ```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; } ``` ```shell gcc -o main_wrapped main.c wrap.c -Wl,--wrap=malloc ./main_wrapped ``` Option 3: Kernel module {#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?](https://litux.nl/mirror/networksecuritytools/0596007949/networkst-CHP-7-SECT-2.html) Option 4: Emulating {#emulating} -------------------------------- * Valgrind, GDB Option 5: Modifying the kernel {#kernel} ---------------------------------------- * Add a special Syscall to intercept/modify other Syscalls