nitanmarcel / magisk-frida-inject

Inject frida script when process starts
GNU General Public License v3.0
18 stars 9 forks source link

frida-inject injects too late #1

Open msmuenchen opened 1 year ago

msmuenchen commented 1 year ago

In some cases, particularly apps that are very fast in early root detection scripts, frida-inject is too slow. For me, it breaks at Samsung Health (apk available in result.downloadURI of this XML).

When launching tethered using frida -U -l com.sec.android.app.shealth.js -f com.sec.android.app.shealth, the script works because it begins to run at the same time as the process spawns and then can do a race against the classloader initialization, but it seems like the way frida-inject works (listening on the global eventlog and then spawning an external process) is too slow, and the root detection has already run by the time the payload script runs. This also applies if using Java.perform.

Ideally (assuming that's even possible?), frida-inject should hook in zygote and execute very early in the app creation process, or it should offer some way of hooking the load procedures of dalvik.system.PathClassLoader to catch when the paths of the apk directory are added.

I attached an example run log of the script from my PC and the source of my hotpatch script both when racing the ClassLoader and when using Frida bridge's Java.perform.

$ frida -U -l com.sec.android.app.shealth.js -f com.sec.android.app.shealth
     ____
    / _  |   Frida 16.1.4 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
   . . . .
   . . . .   Connected to SM T575 (id=xxx:5555)
Spawning `com.sec.android.app.shealth`...
Initializing com.sec.android.app.shealth anti-anti-root patcher
Attempting to check with dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/system_ext/lib64, /system/lib64, /system/system_ext/lib64]]]
Class not found, attempting next loader
Attempting to check with java.lang.BootClassLoader@8a0e187
Class not found, attempting next loader
Spawned `com.sec.android.app.shealth`. Resuming main thread!
Attempting to check with dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/system_ext/lib64, /system/lib64, /system/system_ext/lib64]]]
Class not found, attempting next loader
Attempting to check with java.lang.BootClassLoader@8a0e187
[SM T575::com.sec.android.app.shealth ]-> Class not found, attempting next loader
--- SNIP, it's ~30x just the two "Attempting to check" messages ---
Attempting to check with dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/system_ext/lib64, /system/lib64, /system/system_ext/lib64]]]
Class not found, attempting next loader
Attempting to check with java.lang.BootClassLoader@8a0e187
Class not found, attempting next loader
Attempting to check with dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/~~h3dzJSNtExEFLu57JzJ5IA==/com.sec.android.app.shealth-8Pg-v9-ba8xGlXIv_TNTBw==/base.apk"],nativeLibraryDirectories=[/data/app/~~h3dzJSNtExEFLu57JzJ5IA==/com.sec.android.app.shealth-8Pg-v9-ba8xGlXIv_TNTBw==/lib/arm64, /data/app/~~h3dzJSNtExEFLu57JzJ5IA==/com.sec.android.app.shealth-8Pg-v9-ba8xGlXIv_TNTBw==/base.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]]]
Found KnoxControl, hooking functions
console.log("Initializing com.sec.android.app.shealth anti-anti-root patcher");

global.t = setInterval(function() { // avoid java.lang.ClassNotFoundException
    Java.enumerateClassLoaders({
        onMatch: function(loader) {
            console.log("Attempting to check with", loader);
            Java.classFactory.loader = loader;
            var TestClass;

            // Hook the class if found, else try next classloader.
            try {
                TestClass = Java.use("com.samsung.android.sdk.healthdata.privileged.KnoxControl");
                console.log("Found KnoxControl, hooking functions");
                clearInterval(global.t);
                Java.use("com.samsung.android.sdk.healthdata.privileged.KnoxControl").checkKnoxCompromised.implementation = () => false;
                Java.use("com.samsung.android.app.shealth.tracker.stress.tile.StressHService").loadData.implementation = function() {
                    return;
                }
                Java.use("com.samsung.android.app.shealth.tracker.stress.tile.StressHService").isMeasurementEnabled.implementation = function() {
                    return false;
                }
                Java.use("android.os.Build").MODEL.value = "SM-G990B";
            } catch (error) {
                if (error.message.includes("ClassNotFoundException")) {
                    console.log("Class not found, attempting next loader");
                }
            }

        },
        onComplete: function() {}
    });
}, 0);
Java.perform(() => {
                console.log("App class loader should be present, hooking functions");
                Java.use("com.samsung.android.sdk.healthdata.privileged.KnoxControl").checkKnoxCompromised.implementation = () => false;
                Java.use("com.samsung.android.app.shealth.tracker.stress.tile.StressHService").loadData.implementation = function() { return; }
                Java.use("com.samsung.android.app.shealth.tracker.stress.tile.StressHService").isMeasurementEnabled.implementation = function() { return false; }
                Java.use("android.os.Build").MODEL.value="SM-G990B";
});
nitanmarcel commented 1 year ago

I'm not even sure it can hook into the app at initialization since it might break due to magisk's hide ptrace login