118 lines
3.5 KiB
Markdown
118 lines
3.5 KiB
Markdown
|
|
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 stack allocations etc.)
|
|
|
|
Example (`preload.c`):
|
|
```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;
|
|
}
|
|
```
|
|
|
|
```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_<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)](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_<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`):
|
|
```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
|