微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否可以以编程方式预加载共享库?

如何解决是否可以以编程方式预加载共享库?

我正在构建一个项目,该项目需要修改一些仿生方法(例如 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")
}

但我没有看到方法被替换。

作为参考,hooked 方法相当简单。这是一个极端的简化:


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.
  ...
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。