残页的小博客

残页的小博客

马上订阅 残页的小博客 RSS 更新: https://blog.canyie.top/atom.xml

Android Property 实现解析与黑魔法

2022年4月9日 17:30

Android Property (属性系统)可谓是 Android 中使用最广泛的进程间信息共享机制了,如 app 获取系统版本号,就是通过属性系统传递的信息;对于如此常用的底层机制,你可能知道 getprop SystemProperties __system_property_get 这些 API,但是,你真的了解它吗?这次,我们不但要会遵守规则用这些 API,我们还要成为规则的缔造者,让系统为我们服务!Let’s go!

系统实现分析

首先,我们有这几个问题需要解答:

  1. ro. 开头的属性是只读的,只能被设置一次,系统是怎么实现的?
  2. 系统里的属性那么多,难免会有一些 app 读取不了的敏感属性,系统是怎么限制我们读取的?

Linus 大神有句话很出名:“Read the F*cking Source Code。”想要解答这些问题,阅读源码是必须的。

Property Context

我们通常使用 __system_properties_get 这个 API 去获取系统属性,点开这个函数看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static SystemProperties system_properties;

__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int __system_property_get(const char* name, char* value) {
return system_properties.Get(name, value);
}

int SystemProperties::Get(const char* name, char* value) {
const prop_info* pi = Find(name);
if (pi != nullptr) {
return Read(pi, nullptr, value);
} else {
value[0] = 0;
return 0;
}
}

先去调用 Find() 函数找到一个叫做 prop_info* 的东西,然后从里面读出值来。

1
2
3
4
5
6
7
8
9
10
11
const prop_info* SystemProperties::Find(const char* name) {
if (!initialized_) {
return nullptr;
}
prop_area* pa = contexts_->GetPropAreaForName(name);
if (!pa) {
async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
return nullptr;
}
return pa->find(name);
}

看到这里你是不是一头雾水,这函数有个 initialized_ 一看就是要初始化的,谁去初始化的?contexts_ prop_area 又是什么?这里就不卖关子了,在 libc.so 被加载的时候,它的 .init.array 段里面的函数会被自动执行,而有 __attribute__((constructor(1)) 的函数就会被放到 .init.array 段从而被自动执行。里面兜兜转转,会调用一个 __system_properties_init() 函数,而这个函数正是初始化上面这些东西的关键所在。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21...

剩余内容已隐藏

查看完整文章以阅读更多