为什么 LD_PRELOAD 与系统调用一起工作??

yfr*_*com 4 c linux arm system-calls ld-preload

思路LD_PRELOAD是在原来的共享库之前加载一个共享库,比如我可以先编译mylib.so加载它libc.so,所以当进程要使用printf它时,它会在so那个加载的那个中一一搜索找到mylib.so(因为这个so是先加载的) ) 而不是libc.so,所以它使用printfinmylib.so而不是printfin libc.so

我明白为什么这个工程上都在实现的功能so一样printflibc.so

但是当我想挂钩write函数或其他syscall函数时,为什么会起作用?进程不搜索 中的函数so,它直接进入内核。

  1. 是否LD_PRELOAD适用于静态编译的二进制文件?为什么?在此重播中/sf/answers/970662801/提到LD PRELOAD不适用于静态二进制

  2. 为什么LD_PRELOAD在动态编译的二进制文件上工作以在系统调用上创建钩子?

架构是ARM。

Mar*_*lli 7

进程不搜索 中的函数so,它直接进入内核。

错误,您使用的系统调用函数 ( read(), write(), ...) 都是围绕真实系统调用的libc包装器,甚至是通用syscall()函数。下面的代码write()例如函数。从您的程序直接进入内核的唯一方法是手动发出系统调用(见下文)。

是否LD_PRELOAD适用于静态编译的二进制文件?为什么?

不,它没有。静态二进制文件不需要动态解析任何符号,因此不会调用动态加载器来解析通常的库函数符号。

为什么LD_PRELOAD在动态编译的二进制文件上工作以在系统调用上创建钩子?

因为那些只是普通的 libc 函数,仅此而已。


除了静态编译之外,在不通过 C 库(因此不进行符号解析)的情况下手动调用系统调用的唯一方法是使用内联汇编。您可以查看一下man 2 syscall使用哪些寄存器和指令。例如,在 ARM AArch64 上,您可以通过在 register 中加载系统调用号x8,在x0through 中加载参数x5,然后执行svc #0指令来调用系统调用。