问题描述
我正在构建一个项目,该项目需要修改一些仿生方法(例如 getaddrinfo、__android_print)的行为。我已经能够使用独立编译器或使用 Cmake 将其直接包含在 Apk 中创建挂钩库。我已经能够使用 setprop wrap.com.foo.bar 和 LD_PRELOAD 预加载共享库,并且它正在工作并且我得到了我想要的结果。但是,我想以编程方式预加载挂钩库,因此我不需要每次在重新启动设备后都执行 LD_PRELOAD 的具体步骤(即禁用 SELinux、根设备、setprop)。
我尝试使用
// MainActivity
companion object {
System.load("/data/data/com.foo.bar/lib/libhookedmethod.so")
}
但我没有看到方法被替换。
int __android_print(varargs a) {
int realmethod(...);
realmethod = dlsym("__android_print");
doStuff();
int res = realmethod(a) ;
return res;
}
同样,编译和使用 LD_PRELOAD 是有效的,但我想在不使用 LD_PRELOAD 的情况下实现它... 什么都有帮助!提前致谢
解决方法
LD_PRELOAD
的工作原理是要求动态加载器在之前加载引用的库。加载器通过按加载顺序搜索加载的库来解析对给定符号的引用。
一旦一个符号被解析到一个特定的库,它就不会在这个过程中被重新绑定到其他库。
以上解释应该清楚为什么在程序已经运行后加载 libhookedmethod.so
没有效果。
关于实现您想要的唯一方法是setenv()
(如果尚未设置)并重新exec()
当前进程。像这样:
int main(int argc,char *argv[])
{
char *e = getenv("LD_PRELOAD");
if (e == NULL || /* any other checks that show LD_PRELOAD to not be as we want it */) {
setenv("LD_PRELOAD",...,1);
execvp(argv[0],argv);
}
// LD_PRELOAD is to our liking. Run the actual program.
...
}