0%

MagiskBootPatch原理

boot.img解压

1
2
3
python /Volumes/android/aosp/system/tools/mkbootimg/unpack_bootimg.py \
--boot_img=/Users/juneleo/Downloads/magisk_patched-26300_WZdn1.img \
--out /Users/juneleo/Downloads/magisk_boot
1
2
3
python /Volumes/android/aosp/system/tools/mkbootimg/unpack_bootimg.py \
--boot_img=/Users/juneleo/Downloads/boot.img \
--out /Users/juneleo/Downloads/boot

解压产物

image.png
可以看出magisk生成的patch boot 大了1M。

ramdisk对比

其中的ramdisk是一个gzip格式文件,需要改后缀名为.zg,然后直接解压

image.png

image.png
image.png
image.png

这里我们大概明白了Magisk大概做了什么

  • 解压boot.img
  • 解压ramdisk
  • 修改init可执行文件
  • backup数据
  • 复制数据到overlay.d
  • 打包ramdisk和boot-patch.img

dtb对比

1
dtc -I dtb -O dts -o dtb.dts dtb
1
diff boot/dtb.dts magisk_boot/dtb.dts

image.png

Magisk boot patch

Magisk/scripts/boot_patch.sh **
这个文件最终会被复制到assets目录下
具体的大概逻辑是 通过
boot_patch.sh脚本将magiskinit可执行文件对ramdisk中的init文件进行了替换,**
当执行完成magiskinit后,调用execv(‘system/bin/init’,arg)继续执行原init
原init是一个链接文件
image.png
具体细节在这个文档magiskinit替换init加载逻辑

image.png

boot_patch.sh

Magisk/native/src/boot/main.cpp

日志

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
- Device platform: arm64-v8a
- Installing: 26.3 (26300)
- Copying image to cache
Parsing boot image: [/data/user_de/0/com.topjohnwu.magisk/install/boot.img]
HEADER_VER [2]
KERNEL_SZ [20997486]
RAMDISK_SZ [10735279]
SECOND_SZ [0]
RECOV_DTBO_SZ [0]
DTB_SZ [1002970]
OS_VERSION [10.0.0]
OS_PATCH_LEVEL [2020-07]
PAGESIZE [4096]
NAME []
CMDLINE [console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 service_locator.enable=1 androidboot.memcg=1 cgroup.memory=nokmem usbcore.autosuspend=7 androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 androidboot.boot_devices=soc/1d84000.ufshc buildvariant=user]
CHECKSUM [f1828bcca9442e53297ac10d0f6fd4dacbc50378000000000000000000000000]
- Unpacking boot image
KERNEL_FMT [lz4]
RAMDISK_FMT [gzip]
unexpected ASN.1 DER tag: expected SEQUENCE, got APPLICATION [1] (primitive)
VBMETA
- Checking ramdisk status
Loading cpio: [ramdisk.cpio]
- Stock boot image detected
- Patching ramdisk
- Pre-init storage partition: metadata
Loading cpio: [ramdisk.cpio]
Add file [init] (100750)
Create directory [overlay.d] (0750)
Create directory [overlay.d/sbin] (0750)
Add file [overlay.d/sbin/magisk32.xz] (100644)
Add file [overlay.d/sbin/magisk64.xz] (100644)
Add file [overlay.d/sbin/stub.xz] (100644)
Patch with flag KEEPVERITY=[true] KEEPFORCEENCRYPT=[true]
Loading cpio: [ramdisk.cpio.orig]
Backup [init] -> [.backup/init]
Record new entry: [overlay.d] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin/magisk32.xz] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin/magisk64.xz] -> [.backup/.rmlist]
Record new entry: [overlay.d/sbin/stub.xz] -> [.backup/.rmlist]
Create directory [.backup] (0000)
Add file [.backup/.magisk] (100000)
Dumping cpio: [ramdisk.cpio]
Loading dtbs from [dtb]
- Repacking boot image
Parsing boot image: [/data/user_de/0/com.topjohnwu.magisk/install/boot.img]
HEADER_VER [2]
KERNEL_SZ [20997486]
RAMDISK_SZ [10735279]
SECOND_SZ [0]
RECOV_DTBO_SZ [0]
DTB_SZ [1002970]
OS_VERSION [10.0.0]
OS_PATCH_LEVEL [2020-07]
PAGESIZE [4096]
NAME []
CMDLINE [console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 service_locator.enable=1 androidboot.memcg=1 cgroup.memory=nokmem usbcore.autosuspend=7 androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 androidboot.boot_devices=soc/1d84000.ufshc buildvariant=user]
CHECKSUM [f1828bcca9442e53297ac10d0f6fd4dacbc50378000000000000000000000000]
KERNEL_FMT [lz4]
RAMDISK_FMT [gzip]
unexpected ASN.1 DER tag: expected SEQUENCE, got APPLICATION [1] (primitive)
VBMETA
Repack to boot image: [new-boot.img]
HEADER_VER [2]
KERNEL_SZ [20997486]
RAMDISK_SZ [11244718]
SECOND_SZ [0]
RECOV_DTBO_SZ [0]
DTB_SZ [1002970]
OS_VERSION [10.0.0]
OS_PATCH_LEVEL [2020-07]
PAGESIZE [4096]
NAME []
CMDLINE [console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 service_locator.enable=1 androidboot.memcg=1 cgroup.memory=nokmem usbcore.autosuspend=7 androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 androidboot.boot_devices=soc/1d84000.ufshc buildvariant=user]
CHECKSUM [110782426b7905555aafca11e8c24144a070b180000000000000000000000000]

****************************
Output file is written to
/storage/emulated/0/Download/magisk_patched-26300_zEkUl.img
****************************
- All done!

handleFile

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
private fun handleFile(uri: Uri): Boolean {
val outStream: OutputStream
val outFile: MediaStoreUtils.UriFile

// Process input file
try {
uri.inputStream().buffered().use { src ->
...
srcBoot = if (tarMagic.contentEquals("ustar".toByteArray())) {
...
} else {
// raw image
outFile = MediaStoreUtils.getFile("$filename.img", true)
outStream = outFile.uri.outputStream()

try {
if (magic.contentEquals("CrAU".toByteArray())) {
processPayload(src)
} else if (magic.contentEquals("PK\u0003\u0004".toByteArray())) {
processZip(ZipInputStream(src))
} else {
// 这里开始复制到
// /data/user_de/0/com.topjohnwu.magisk/install/boot.img
console.add("- Copying image to cache")
installDir.getChildFile("boot.img").also {
src.copyAndCloseOut(it.newOutputStream())
}
}
} catch (e: IOException) {
outStream.close()
outFile.delete()
throw e
}
}
}
} catch (e: IOException) {
if (e is NoBootException)
console.add("! No boot image found")
console.add("! Process error")
Timber.e(e)
return false
}

// 这里开始打patch
if (!patchBoot()) {
outFile.delete()
return false
}

// Output file
try {
val newBoot = installDir.getChildFile("new-boot.img")
if (outStream is TarOutputStream) {
val name = with(srcBoot.path) {
when {
contains("recovery") -> "recovery.img"
contains("init_boot") -> "init_boot.img"
else -> "boot.img"
}
}
outStream.putNextEntry(newTarEntry(name, newBoot.length()))
}
newBoot.newInputStream().copyAndClose(outStream)
newBoot.delete()

console.add("")
console.add("****************************")
console.add(" Output file is written to ")
console.add(" $outFile ")
console.add("****************************")
} catch (e: IOException) {
console.add("! Failed to output to $outFile")
outFile.delete()
Timber.e(e)
return false
}

// Fix up binaries
srcBoot.delete()
"cp_readlink $installDir".sh()

return true
}

patchBoot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private fun patchBoot(): Boolean {
val newBoot = installDir.getChildFile("new-boot.img")
if (!useRootDir) {
// Create output files before hand
newBoot.createNewFile()
File(installDir, "stock_boot.img").createNewFile()
}
// 执行boot_patch.sh
val cmds = arrayOf(
"cd $installDir",
"KEEPFORCEENCRYPT=${Config.keepEnc} " +
"KEEPVERITY=${Config.keepVerity} " +
"PATCHVBMETAFLAG=${Info.patchBootVbmeta} " +
"RECOVERYMODE=${Config.recovery} " +
"LEGACYSAR=${Info.legacySAR} " +
"sh boot_patch.sh $srcBoot")
val isSuccess = cmds.sh().isSuccess
// 执行 magiskboot cleanup
shell.newJob().add("./magiskboot cleanup", "cd /").exec()

return isSuccess
}

patch

Magisk/native/src/boot/cpio.rs

1
2
3
4
5
6
7
8
9
10
11
12
./magiskboot cpio ramdisk.cpio \
"add 0750 $INIT magiskinit" \
"mkdir 0750 overlay.d" \
"mkdir 0750 overlay.d/sbin" \
"$SKIP32 add 0644 overlay.d/sbin/magisk32.xz magisk32.xz" \
"$SKIP64 add 0644 overlay.d/sbin/magisk64.xz magisk64.xz" \
"add 0644 overlay.d/sbin/stub.xz stub.xz" \
"patch" \
"$SKIP_BACKUP backup ramdisk.cpio.orig" \
"mkdir 000 .backup" \
"add 000 .backup/.magisk config" \
|| abort "! Unable to patch ramdisk"

Repack

magiskinit

入口:Magisk/native/src/init/init.cpp main()