涉及3个组成部分
loader.so
-Bsymbolic
编译,覆盖puts
并加载other.so
puts
,并且无法修改如何让other.so
使用puts
中覆盖的loader.so
?
请注意,我希望puts
从loader.so
开始(包括other.so
)被仅覆盖,主程序应该不受影响
跟随示例代码
main.c
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char *argv[]){
dlopen("./loader.so", RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND);
puts("Normal");
return 0;
}
loader.c
#include <stdio.h>
#include <dlfcn.h>
extern int puts(const char *s){
fputs("Hooked: ", stdout);
fputs(s, stdout);
fputc('\n', stdout);
return 0;
}
__attribute__((constructor))
void ctor(void) {
puts("Something");
void *other = dlopen("./other.so", RTLD_NOW);
}
other.c
#include <stdio.h>
__attribute__((constructor))
void ctor(void) {
puts("Hello!");
}
make.sh
#!/bin/bash
gcc main.c -o main -ldl
gcc loader.c -fPIC -shared -Wl,-Bsymbolic -o loader.so
gcc other.c -fPIC -shared -o other.so
所需的输出
Hooked: Something
Hooked: Hello!
Normal
实际输出
Hooked: Something
Hello!
Normal
答案 0 :(得分:1)
在解决了更多问题之后,我有一个解决方案,需要patchelf
的一些外部帮助,因此,如果有其他解决方法,我将等待接受该解决方案。 / p>
此解决方案的工作原理是,使用经过修改的shared.so
制作一个新的共享对象puts
,如下所示
int puts(const char *s){
fputs("Hooked: ", stdout);
fputs(s, stdout);
fputc('\n', stdout);
return 0;
}
然后我们需要强制other.so
依赖于这个新的共享对象,我们可以使用patchelf --add-needed shared.so other.so
此确实涉及对other.so
的修改,但是不需要从源头重新编译(这使该方法更可行)。
现在,当我们加载other.so
时,我们需要像这样在RTLD_DEEPBIND
内指定loader.c
void *other = dlopen("./libother.so", RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND);
,这样搜索顺序就不会从全局上下文开始,而是从库本身开始。
由于other.so
未定义puts
,因此将查找直接依赖项,并且将在puts
中找到shared.so
RTLD_DEEPBIND
的属性可确保即使最终的LD_PRELOAD
对象也被压倒了。
因此,如果在预加载的共享库中禁用了puts
,我们可以解决该问题并从glibc调用真正的,未经修改的puts
(并且仅适用于源自other.so
的调用)。 / p>
如果我们想要的只是恢复原始行为,我们就不需要patchelf
或shared.so
答案 1 :(得分:0)
尝试添加标志-Wl,--no-as-needed
gcc loader.c -fPIC -shared -Wl,-Bsymbolic -Wl,--no-as-needed -o loader.so
我成功地从time-machine的C库中挂钩了与时间相关的函数。