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

简介: 解读Android Native对于系统私有库的限制,老版本的黑科技代码在N版本之后都可能导致APP崩溃。

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

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

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

曾经的美好

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

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

    void *handle = dlopen("libart.so", RTLD_NOW);
    
    void *originFunc = dlsym(handle, "_ZNK3art6Thread13DumpJavaStackERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE");

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

晴天霹雳

但是到了N以后,

void *handle = dlopen("libart.so", RTLD_NOW);
//  没问题,返回了handle指针。

void *originFunc = dlsym(handle, "_ZNK3art6Thread13DumpJavaStackERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE");
// 失败!得到的originFunc为空!

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

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

7de5d4d000-7de5d4e000 r-xp 00000000 fe:00 774                            /system/fake-libs64/libart.so
7de5d4e000-7de5d4f000 r--p 00000000 fe:00 774                            /system/fake-libs64/libart.so
7de5d4f000-7de5d50000 rw-p 00001000 fe:00 774                            /system/fake-libs64/libart.so
... ...
7de6a04000-7de6feb000 r-xp 00000000 fe:00 1414                           /system/lib64/libart.so
7de6feb000-7de6ffa000 r--p 005e6000 fe:00 1414                           /system/lib64/libart.so
7de6ffa000-7de6ffd000 rw-p 005f5000 fe:00 1414                           /system/lib64/libart.so

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

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

A fake libart made to satisfy some misbehaving apps that will attempt to link
against libart.so.

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

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

设置fake-libs代码:

@ frameworks/base/core/java/android/app/LoadedApk.java

public static void makePaths(...) {
...
    // Add fake libs into the library search path if we target prior to N.
    if (aInfo.targetSdkVersion <= 23) {
        outLibPaths.add("/system/fake-libs" +
            (VMRuntime.is64BitAbi(aInfo.primaryCpuAbi) ? "64" : ""));
    }
...
}

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

霸王硬上弓

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

void *handle = dlopen("/system/lib64/libart.so", RTLD_NOW);

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

01-11 13:16:10.413 19869-19869/com.patch.demo E/linker: library "/system/lib64/libart.so" ("/system/lib64/libart.so")
needed or dlopened by "/data/app/com.patch.demo-1/lib/arm64/libbcpatch.so"
is not accessible for the namespace:
[name="classloader-namespace", ld_library_paths="",
default_library_paths="/data/app/com.patch.demo-1/lib/arm64:/system/fake-libs64:/data/app/com.patch.demo-1/base.apk!/lib/arm64-v8a",
permitted_paths="/data:/mnt/expand:/data/data/com.patch.demo"]

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

/data/app/com.patch.demo-1/lib/arm64
/system/fake-libs64
/data/app/com.patch.demo-1/base.apk!/lib/arm64-v8a
/data
/mnt/expand
/data/data/com.patch.demo

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

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

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

缓兵之计

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

// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
// gradually remove libraries from this list until it is gone.
static bool is_greylisted(const char* name, const soinfo* needed_by) {
  static const char* const kLibraryGreyList[] = {
    "libandroid_runtime.so",
    "libbinder.so",
    "libcrypto.so",
    "libcutils.so",
    "libexpat.so",
    "libgui.so",
    "libmedia.so",
    "libnativehelper.so",
    "libskia.so",
    "libssl.so",
    "libstagefright.so",
    "libsqlite.so",
    "libui.so",
    "libutils.so",
    "libvorbisidec.so",
    nullptr
  };

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

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

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

突出重围

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

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

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

7de6a04000-7de6feb000 r-xp 00000000 fe:00 1414                           /system/lib64/libart.so
7de6feb000-7de6ffa000 r--p 005e6000 fe:00 1414                           /system/lib64/libart.so
7de6ffa000-7de6ffd000 rw-p 005f5000 fe:00 1414                           /system/lib64/libart.so

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

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

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


也可以来这里与我们共同讨论技术

目录
相关文章
|
9月前
|
Linux 测试技术 语音技术
【车载Android】模拟Android系统的高负载环境
本文介绍如何将Linux压力测试工具Stress移植到Android系统,用于模拟高负载环境下的CPU、内存、IO和磁盘压力,帮助开发者优化车载Android应用在多任务并发时的性能问题,提升系统稳定性与用户体验。
741 6
|
9月前
|
Java 数据库 Android开发
基于Android的电子记账本系统
本项目研究开发一款基于Java与Android平台的开源电子记账系统,采用SQLite数据库和Gradle工具,实现高效、安全、便捷的个人财务管理,顺应数字化转型趋势。
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
前端开发 Java 编译器
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
604 36
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
|
安全 搜索推荐 Android开发
Android系统SELinux安全机制详解
如此看来,SELinux对于大家来说,就像那位不眠不休,严阵以待的港口管理员,守护我们安卓系统的平安,维护这片海港的和谐生态。SELinux就这样,默默无闻,却卫士如山,给予Android系统一份厚重的安全保障。
469 18
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
671 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
算法 JavaScript Android开发
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
1167 38
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
979 15
Android 系统缓存扫描与清理方法分析

热门文章

最新文章