Android Native禁止使用系统私有库详解

系统私有库指的是,存放在android系统/system/lib/和/vendor/lib下面,但是Android NDK中没有公开API的lib库。

从Android N开始(SDK >= 24),通过dlopen打开系统私有库,或者lib库中依赖系统私有库,都会产生异常,甚至可能导致app崩溃。具体可以阅读官方文档说明。

这个变更会有怎样的影响呢?

曾经的美好

在以前,在ndk层面,我们是可以使用一些hack的手段得到系统的私有api的。

比如,你想使用虚拟机中的一些内部符号,在N以下版本,你可以这么搞


这样你就能得到
art::Thread::DumpJavaStack的函数指针,然后愉快地调用它了。

晴天霹雳

但是到了N以后,


这就很奇怪了,我们能够得到handle指针,就说明libart.so是找到了。但是为什么libart.so中却没有找到
art::Thread::DumpJavaStack的符号呢?

看一下内存映射表,我们发现了一个有趣的东西


难怪,我们知道dlopen参数为libart.so的话,系统会先找到
/system/fake-libs64/libart.so,而不是/system/lib64/libart.so。


/system/fake-libs64/libart.so又是什么鬼?从名字上看,就知道他是个假的libart。在系统源码文件art/libart_fake/README.md中,我们找到了对他的解释,


这就是为了以防你们这些图谋不轨(misbehaving)的APP们做一些奇怪的事而专门设的套啊!

只要你自己的lib库依赖了libart.so或者试图打开libart.so,在linker查找libart.so时,因为fake-libs路径被设置在了查找路径表的靠前处,就会先找到
/system/fake-libs64/libart.so,而不是真正的/system/lib64/libart.so。

设置fake-libs代码:


而这个
/system/fake-libs64/libart.so的内容基本上的空的(art/libart_fake/fake.cc),所以在它里面当然什么符号都找不到啦~

霸王硬上弓

既然如此,那我们在dlopen中直接指定lib的绝对路径总行了吧?像这样:


可是很遗憾,它报了一个错:


也就是说,你被允许访问的路径(包含ld_library_paths、default_library_paths、permitted_paths)只有


所以,试图访问/system/lib64/下的libart.so当然是不行的啦。

真是魔高一尺道高一丈啊。

至此,我们算是知道了Google封杀在ndk中访问系统私有库的方法。本质是在linker中加入一系列校验机制来做限制。linker作为最基础的lib库链接器,所有链接行为都会被限制住。

缓兵之计

不过,在Android N,你可以指定APP的sdk为API级别23或更低。那么,对于以下灰名单中的lib,仍然可以正常使用:


这样的话,每次使用dlopen或者链接以上lib都会打印出一个警告,然后仍然正常执行原有功能。

同时Google也声明了,在将来的版本会将这些lib的支持也一并移除。因此,这只是提供了一个让你尽快在代码中去除相关依赖的过渡期。

可见,不久的将来就无法愉快地使用系统的非公开符号了。

突出重围

那我们真的就没办法了吗?

也不是绝对的,Android限制的只是dlopen这个途径,而我们访问内存是随心所欲的:)

方法就是,通过内存映射表找到libart.so的真实起始位置:


然后在加载地址起始位置手动解析libart.so的elf格式,提取出所需符号的位置信息。相当于你自己实现linker原本的查找逻辑。

当然,这种遍历内存解析elf的实现是比较复杂的。因此,这一次Google算是封死了一大波底层hack的手段。

不过,网上仍然有很多绕过这个限制的方式,大家有兴趣的可以自己发掘一下。

Android Native禁止使用系统私有库详解

查看更多:
https://yqh.aliyun.com/detail/6896?utm_content=g_1000107051

上云就看云栖号:更多云资讯,上云案例,最佳实践,产品入门,访问:https://yqh.aliyun.com/

来源:阿里云云栖号

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年2月6日
下一篇 2020年2月6日

相关推荐