From Anime Game to Android System Security Vulnerability
Fate/Grand Order
I’ve been fighting with all sorts of weird device integrity detection methods over the years, but nothing is near the level of FGO. For some reason, the developers at Aniplex is extremely obsessed with detecting Magisk, as if it was an ultimate mission they are destined to accomplish. Other than the standard and common sensitive binaries, mount point, and environment variables checks, they went out the way to ban USB debugging, blacklist the package name of Magisk Manager (com.topjohnwu.magisk
OnePlus 6 became my main development phone since I switched to Pixel 3 XL (I don’t usually use my daily driver for development), so all initial tests are done on that device. FGO has become a “benchmark” for the effectiveness of MagiskHide for quite a while, and one day I found out that the app no longer launches with the standard MagiskHide + Magisk Manager repackaging treatment. For the record, all tests are done with Fate/Grand Order US version (com.aniplex.fategrandorder.en
Experiments
To do any analysis, USB debugging (ADB) is pretty much required. The Aniplex devs are smart and sneaky: the app simply refuses to run with ADB enabled. I’ve got some tricks up my sleeves so it is possible for me to enable ADB without being detected. However, I decide not to disclose the trick publicly since I really don’t want to make my life more difficult in the future. Just keep in mind that all following steps are done in a USB debuggable environment.
The first step is to experiment using stripped down Magisk versions to isolate the issue. The process is pretty straightforward: start from nearly pure stock, and gradually add more features until we hit a wall. Let’s try nano-Magisk: root daemon is launched, but no binaries are exposed to any unprivileged process. FGO works fine, great! Now let’s try micro-Magisk: /sbin tmpfs
overlay is enabled. This does not include MagiskHide daemon, so the hiding procedures are done manually, which when applied the effect is both globally and permanently (meaning no process can ever gain root after applying the first hiding). FGO works fine, great! Next let’s try mini-Magisk: logcat monitor with MagiskHide is enabled, and no manual hiding is done. Finally FGO refuses to launch!
Analysis
MagiskHide exploits the fact that Android apps’ processes are isolated. Magisk modifications are only reverted and hidden in specific target processes, which is the reason why non-target processes can still use root graciously. Through experiments, the issue can theoretically be narrowed down to:
- The effectiveness of process monitoring (FGO spawns processes that are not handled by Magisk)
- MagiskHide is simply just too slow (FGO detects root before MagiskHide have a chance to hijack the process)
The 2nd reason is extremely unlikely, so let’s assume the first scenario. To monitor all new processes spawned from Zygote(app_process
)(we don’t care child process forked from target processes), we can go througham_proc_start
logs (accessed via events buffer: logcat -b events
) and check if there are any weird process launched in the background. Hmm… doesn’t seem to be the case, something is definitely fishy here. It’s about time to pull out the big guns.
Digging Deeper
We utilize the tool strace to analyze what’s going on with FGO without taking apart the APK and do reverse engineering. If you want the full strace output, here you go (the target process PID is 9184
). BTW here is an interesting info within the traces, the blacklisted packages (and some files):
com.cih.game_cih
com.hexview.android.memspector
cn.mm.gk
pl.Nyki.Dax
catch_.me_.if_.you_.can_
com.sbgamehacker
jp.kbc.ma34.devicefaker
com.saurik.substrate
de.robv.android.xposed.installer
com.felixheller.sharedprefseditor
cn.mc.sq
cn.mc1.sq
com.cih.game_cih
pl.aqua.gameguardian
org.sbtools.gamehack
com.hexview.android.memspector
mr.big.stuff
cat.dcat.roothide
de.robv.android.xposed.installer
com.saurik.substrate
com.topjohnwu.magisk
com.loserskater.suhidegui
eu.chainfire.suhide
eu.chainfire.supersu
eu.chainfire.supersu.pro
com.noshufou.android.su
com.koushikdutta.superuser
me.phh.superuser
/system/app/superuser.apk
/system/app/Superuser.apk
/system/app/SuperUser.apk
/system/app/SUPERUSER.apk
/su/suhide
It also attempts to read current mount points in /proc/self/mount
, environment variables via /proc/self/environ
, tries to open /root
, the path where Magisk store overlayed sbin binaries (access denied of course, who will let them read it