APatch代码解析(一)

0x00 前言

​ 玩内核root有一段时间了,朋友的手机RedMI note9,使用APatch的时候存在BUG。主要是在使用adb shell的时候找不到root权限,对应的折中的解决办法则是,使用termux来获取root权限来执行命令。但是这不禁让人好奇,为什么会存在这种BUG,以及内核层面的root是怎么实现的?和Magisk的root有什么区别?

0x01 Patch boot

​ APatch的使用无需多言,网上有非常多的教程,可以看他们的官网上的文档。首先其第一个功能就是对boot.img进行patch。根据AndroidManifest.xml文件中写的内容可以看出。首先是执行了.APApplication这个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<application
android:name=".APApplication"
android:allowBackup="true"
android:requestLegacyExternalStorage="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="false"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="APatch"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.APatch"
android:usesCleartextTraffic="true"
tools:targetApi="34">

在APApplication类中存在几个关键函数,这里可以先看onCreate函数,判断是不是arm64架构的手机,如果不是的话就没有办法运行。之后获取到config文件中的内容赋值给sueprKey。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
override fun onCreate() {
super.onCreate()
apApp = this

val isArm64 = Build.SUPPORTED_ABIS.any { it == "arm64-v8a" }
if (!isArm64) {
Toast.makeText(applicationContext, "Unsupported architecture!", Toast.LENGTH_LONG)
.show()
Thread.sleep(5000)
exitProcess(0)
}
sharedPreferences = getSharedPreferences(SP_NAME, Context.MODE_PRIVATE)
APatchKeyHelper.setSharedPreferences(sharedPreferences)
superKey = APatchKeyHelper.readSPSuperKey()
}

所以这一步其实只是检查机器架构的,那么之后还有显示调用的installApatch函数。可以看到其实是依次执行了cmds里的命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
fun installApatch() {
val state = _apStateLiveData.value
if (state != State.ANDROIDPATCH_NOT_INSTALLED &&
state != State.ANDROIDPATCH_NEED_UPDATE
) {
return
}
_apStateLiveData.value = State.ANDROIDPATCH_INSTALLING
val nativeDir = apApp.applicationInfo.nativeLibraryDir

Natives.resetSuPath(LEGACY_SU_PATH)

val cmds = arrayOf(
"mkdir -p $APATCH_BIN_FOLDER",
"mkdir -p $APATCH_LOG_FOLDER",

// TODO: kpatch extracted from kernel
"cp -f ${nativeDir}/libkpatch.so $KPATCH_PATH",
"chmod +x $KPATCH_PATH",
"ln -s $KPATCH_PATH $KPATCH_LINK_PATH",
"restorecon $KPATCH_PATH",

"cp -f ${nativeDir}/libapd.so $APD_PATH",
"chmod +x $APD_PATH",
"ln -s $APD_PATH $APD_LINK_PATH",
"restorecon $APD_PATH",

"cp -f ${nativeDir}/libmagiskpolicy.so $MAGISKPOLICY_BIN_PATH",
"chmod +x $MAGISKPOLICY_BIN_PATH",
"cp -f ${nativeDir}/libresetprop.so $RESETPROP_BIN_PATH",
"chmod +x $RESETPROP_BIN_PATH",
"cp -f ${nativeDir}/libbusybox.so $BUSYBOX_BIN_PATH",
"chmod +x $BUSYBOX_BIN_PATH",

"touch $PACKAGE_CONFIG_FILE",
"touch $SU_PATH_FILE",
"[ -s $SU_PATH_FILE ] || echo $LEGACY_SU_PATH > $SU_PATH_FILE",
"echo ${Version.getManagerVersion().second} > $APATCH_VERSION_PATH",
"restorecon -R $APATCH_FOLDER",

"${nativeDir}/libmagiskpolicy.so --magisk --live",
)

val shell = getRootShell()
shell.newJob().add(*cmds).to(logCallback, logCallback).exec()

// clear shell cache
APatchCli.refresh()

Log.d(TAG, "APatch installed...")
_apStateLiveData.postValue(State.ANDROIDPATCH_INSTALLED)
}