HighCapable / YukiHookAPI

⛱️ An efficient Hook API and Xposed Module solution built in Kotlin.
https://highcapable.github.io/YukiHookAPI/
Apache License 2.0
1.42k stars 105 forks source link

Migrating to 1.2.0 #58

Closed salvogiangri closed 11 months ago

salvogiangri commented 11 months ago

Hello, I have a few questions about the new code style and I don't know where else to ask if not here. I managed to migrate my module's syntax to 1.2.0 (https://github.com/BlackMesa123/KnoxPatch/commit/ae4caaa48acf239dc40077fcac7820f1eb7d497b), but I currently have two doubts:

I'm currently handling this exception to show a prettier error message in logs when the class to hook is not found:

findClass("com.samsung.android.security.keystore.AttestParameterSpec").hook {
    injectMember {
        method {
            name = "isVerifiableIntegrity"
            emptyParam()
            returnType = BooleanType
        }
            replaceToTrue()
        }
}.onHookClassNotFoundFailure {
    loggerE(msg = "$TAG: couldn't access class " +
        "com.samsung.android.security.keystore.AttestParameterSpec " +
        "(${it.javaClass.simpleName})")
}

This is because the class I'm trying to hook isn't part of android frameworks (framework.jar) but rather of a separate library (samsungkeystoreutils.jar), that if not declared in the manifest of the app:

<uses-library android:name="samsungkeystoreutils" android:required="false" />

will make hooking the class to fail. This is what I'm currently using, but I'm not sure if it's correct:

"com.samsung.android.security.keystore.AttestParameterSpec".toClass()
    .method {
        name = "isVerifiableIntegrity"
        emptyParam()
        returnType = BooleanType
    }.hook {
        replaceToTrue()
    }.onAllFailure {
        YLog.error(msg = "$TAG: couldn't access class " +
            "com.samsung.android.security.keystore.AttestParameterSpec " +
            "(${it.javaClass.simpleName})")
    }

With the old syntax, I could hook multiple methods of the same class like this:

findClass("android.os.SemSystemProperties").hook {
    injectMember {
        method {
            name = "get"
            param(String::class.java)
            returnType = StringClass
        }
        beforeHook {
            val key: String = args(0).string()

            // Fixes:
            // - Legacy Secure Wi-Fi (ICD)
            // - SPCMAgent (SAK)
            when (key) {
                "ro.build.type" -> result = "eng"
                "ro.security.keystore.keytype" -> result = ""
            }
        }
    }

    injectMember {
        method {
            name = "get"
            param(String::class.java, String::class.java)
            returnType = StringClass
        }
        beforeHook {
            val key: String = args(0).string()
            val def: String = args(1).string()

            if (key == "ro.boot.flash.locked"
                || key == "ro.boot.verifiedbootstate"
                || key == "ro.boot.warranty_bit"
                || key == "ro.config.iccc_version") {
                result = def
            }
        }
    }
}

With the new syntax I ended up with something like this:

"android.os.SemSystemProperties".toClass()
    .method {
        name = "get"
        param(String::class.java)
        returnType = StringClass
    }.hook {
        before {
            val key: String = args(0).string()

            // Fixes:
            // - Legacy Secure Wi-Fi (ICD)
            // - SPCMAgent (SAK)
            when (key) {
                "ro.build.type" -> result = "eng"
                "ro.security.keystore.keytype" -> result = ""
            }
        }
    }

"android.os.SemSystemProperties".toClass()
    .method {
        name = "get"
        param(String::class.java, String::class.java)
        returnType = StringClass
    }.hook {
        before {
            val key: String = args(0).string()
            val def: String = args(1).string()

            if (key == "ro.boot.flash.locked"
                || key == "ro.boot.verifiedbootstate"
                || key == "ro.boot.warranty_bit"
                || key == "ro.config.iccc_version") {
                result = def
            }
        }
    }
fankes commented 11 months ago

You can use Kotlin's apply for a continuous call.

The exception catching for a class scope is about removed. You can try toClassOrNull when this class doesn't exists it will return null.

The exception catching in the Hook part is limited to the behavior of the Hook, and the exception catching in the Java reflection part has been decoupled from it.

Here is a example you can try it.

"android.os.SemSystemProperties".toClassOrNull()?.apply {
    method {
        // ...
    }.hook {
        // ...
    }
    method {
        // ...
    }.ignored() // Ignore the error log, do your exception check following.
        .onNoSuchMethod { e ->
            // Your exception check here.
        }
        .hook {
            // ...
        }
} ?: YLog.error("This class was not found yet.")

For more, you can visit here.