Linux 重写libc open()库函数

Linux 重写libc open()库函数,linux,gcc,overriding,ld,glibc,Linux,Gcc,Overriding,Ld,Glibc,在我的库中,我有相同的被覆盖的open(),它是由glibc提供的&我首先用我的库设置了LD\u PRELOAD,因此当进程调用open()时,将调用库中定义的open 问题:-在glibc中还有其他几个函数调用open(),一旦这样的例子是getpt(),当getpt()调用open()时,open()在glibc中定义的open()被调用,我将如何使getpt()调用open()在我的库()中定义 约束条件:-我没有编译glibc的选项。我认为使用LD\u PRELOAD无法做到这一点 如果

在我的库中,我有相同的被覆盖的open(),它是由glibc提供的&我首先用我的库设置了
LD\u PRELOAD
,因此当进程调用
open()
时,将调用库中定义的open

问题:-在glibc中还有其他几个函数调用open(),一旦这样的例子是
getpt()
,当
getpt()
调用
open()
时,
open()
glibc中定义的
open()
被调用,我将如何使
getpt()
调用
open()
在我的库()中定义


约束条件:-我没有编译glibc的选项。

我认为使用LD\u PRELOAD无法做到这一点

如果您查看libc的反汇编(例如使用
objdump--disassemble/lib64/libc.so.6 | grep-A20):“
,您可以看到
getpt()
调用
\u open()
,这是
open()
的别名

0000000000 11e9d0:
11e9d0:53推送%rbx
[...]
11e9ee:e8 dd d9 fb ff呼叫dc3d0
但是,对uu open的调用是一个不通过PLT的PC相关调用-这意味着您可以使用LD_PRELOAD插入符号,因为libc中的所有调用都不会使用PLT。这可能是因为libc与
-BSymbolic
链接


剩下的唯一选项是执行strace所做的操作,并使用ptrace附加到流程。请参阅其工作原理。

正如tmcguire正确指出的那样,从
posix\u openpt
\u open
的调用是对内部符号的调用,不能插入

有效地,<代码> GLUBC/<代码>开发人员认为这个调用是实现细节,您没有更改的业务。

我正在寻找编译时解决方案

你不能拥有它

超过运行时解决方案导致运行时解决方案将对性能产生影响

运行时解决方案不需要有任何性能影响(除了调用
open
而不是
glibc
s的开销)

我只知道库插入
glibc
内部调用的一种方法:运行时补丁

  • 查找
    libc.so.6
    open
    (这是
    \uu open
    的别名)的地址
  • 在运行时定位
    glibc
    .text
    部分的边界
  • 扫描它以查看
    CALL\u open
    说明
  • 对于任何此类指示
    • m保护它所在的页面,使其可写
    • 计算一条新指令,该指令是
      CALL my_open
      ,并将其修补到原始指令的“顶部”
    • m保护
      返回页面以读取和执行
这很难看,但它在i*86(32位)Linux上运行良好,
调用
可以“到达”4GB地址空间内的任何其他指令。它不适用于x86_64,在x86_64中,
调用
仍被限制在+/-2GB,但从库到
glibc
的距离可能会超过这个范围


在这种情况下,您需要在
libc.so.6
中找到一个合适的蹦床,您可以将原始
调用重定向到该蹦床,并且可以将寄存器间接
JMP
放置到最终目的地。幸运的是,
libc.so.6
通常有多个大小合适的未使用
NOP
区域,因为函数对齐。

我可以在编译时通过在库中定义getpt()函数来解决这个问题

此解决方案不完整,因为glibc[getpt()]中可能有其他函数可以调用open,然后将调用glibc中的open调用


我现在可以接受这个解决方案,但我需要在将来完全修复它。

虽然ptrace是一个不错的选择,但要使用ptrace,您需要一个不可接受的父子关系,因为我提供了一个库,如果我必须使用ptrace,那么我必须分叉,然后对孩子进行跟踪。我不认为我可以有这个解决方案如果你不能使用ptrace,那么我看不到拦截open()调用的方法,缺少像Intel的PIN库那样的动态运行时插装。嗯,好吧,让我们看看是否有其他人有想法,我正在寻找编译时解决方案,而不是运行时解决方案,因为运行时解决方案会对性能产生影响。好吧,在基于生产的环境中进行这种黑客攻击是不好的&正如您所说的,确实很难看。@user3465381 FWIW,使用
LD_PRELOAD
插入
open
只是稍微不那么难看,可以说你也不应该在生产中这样做。好的,我提供了一个库,可供内部应用程序和第三方应用程序使用。我没有编辑第三方代码的选项。dlopen也不是sa的选项我解释第三方代码无法编辑的原因。鉴于这些限制,您如何让第三方应用程序调用库中定义的open函数。?这不是LD_PRELOAD的确切用例吗。?我喜欢“实现细节”部分,尽管正如您所说,修补内容很难看。
000000000011e9d0 <posix_openpt>:
  11e9d0:       53                      push   %rbx
  [...]
  11e9ee:       e8 dd d9 fb ff          callq  dc3d0 <__open>