mirror of
https://github.com/topjohnwu/Fingerface.git
synced 2024-11-23 11:49:48 +00:00
Rewrite Xposed hooks
This commit is contained in:
parent
b632715b61
commit
880db8c1e5
@ -4,6 +4,7 @@
|
|||||||
package="com.edison.fingerface">
|
package="com.edison.fingerface">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
|
package android.hardware.fingerprint
|
||||||
|
|
||||||
|
import android.hardware.biometrics.BiometricPrompt
|
||||||
|
|
||||||
|
class MyAuthenticationCallback(private val callback: FingerprintManager.AuthenticationCallback) :
|
||||||
|
BiometricPrompt.AuthenticationCallback() {
|
||||||
|
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
|
callback.onAuthenticationError(errorCode, errString)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence) {
|
||||||
|
callback.onAuthenticationHelp(helpCode, helpString)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
callback.onAuthenticationFailed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||||
|
callback.onAuthenticationSucceeded(MyAuthenticationResult(result))
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
package android.hardware.fingerprint;
|
|
||||||
|
|
||||||
public class MyAuthenticationResult extends FingerprintManager.AuthenticationResult {
|
|
||||||
|
|
||||||
FingerprintManager.CryptoObject cryptoObject;
|
|
||||||
|
|
||||||
public void setCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
|
|
||||||
this.cryptoObject = cryptoObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FingerprintManager.CryptoObject getCryptoObject() {
|
|
||||||
if (cryptoObject != null) {
|
|
||||||
return cryptoObject;
|
|
||||||
}
|
|
||||||
return super.getCryptoObject();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,20 @@
|
|||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
|
package android.hardware.fingerprint
|
||||||
|
|
||||||
|
import android.hardware.biometrics.BiometricPrompt
|
||||||
|
|
||||||
|
class MyAuthenticationResult(private val result: BiometricPrompt.AuthenticationResult) :
|
||||||
|
FingerprintManager.AuthenticationResult() {
|
||||||
|
|
||||||
|
private fun BiometricPrompt.CryptoObject.toLegacy() = when {
|
||||||
|
cipher != null -> FingerprintManager.CryptoObject(cipher)
|
||||||
|
mac != null -> FingerprintManager.CryptoObject(mac)
|
||||||
|
signature != null -> FingerprintManager.CryptoObject(signature)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCryptoObject(): FingerprintManager.CryptoObject? {
|
||||||
|
return result.cryptoObject?.toLegacy()
|
||||||
|
}
|
||||||
|
}
|
@ -1,175 +0,0 @@
|
|||||||
package android.hardware.fingerprint;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.hardware.biometrics.BiometricPrompt;
|
|
||||||
import android.os.CancellationSignal;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.security.keystore.KeyGenParameterSpec;
|
|
||||||
import android.security.keystore.KeyPermanentlyInvalidatedException;
|
|
||||||
import android.security.keystore.KeyProperties;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.KeyGenerator;
|
|
||||||
import javax.crypto.NoSuchPaddingException;
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.*;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
|
|
||||||
public class MyFingerprintManager extends FingerprintManager {
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
|
|
||||||
private KeyGenerator keyGenerator;
|
|
||||||
private KeyStore keyStore;
|
|
||||||
private Cipher cipher;
|
|
||||||
|
|
||||||
private String KEY_NAME = "MyFingerprintManager";
|
|
||||||
|
|
||||||
public void SetContext(Context context) {
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isHardwareDetected() {
|
|
||||||
|
|
||||||
Log.d("XposedHandler", "isHardwareDetected");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasEnrolledFingerprints() {
|
|
||||||
Log.d("XposedHandler", "hasEnrolledFingerprints");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void authenticate(final CryptoObject crypto, CancellationSignal cancel,
|
|
||||||
int flags, final AuthenticationCallback callback, Handler handler) {
|
|
||||||
|
|
||||||
BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(mContext).setTitle("FaceID").setNegativeButton(mContext.getString(android.R.string.cancel), mContext.getMainExecutor(), new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
}).build();
|
|
||||||
|
|
||||||
BiometricPrompt.CryptoObject c = null;
|
|
||||||
|
|
||||||
if (crypto == null) {
|
|
||||||
|
|
||||||
generateKey();
|
|
||||||
initCipher();
|
|
||||||
c = new BiometricPrompt.CryptoObject(cipher);
|
|
||||||
|
|
||||||
} else if (crypto.getCipher() != null) {
|
|
||||||
c = new BiometricPrompt.CryptoObject(crypto.getCipher());
|
|
||||||
} else if (crypto.getMac() != null) {
|
|
||||||
c = new BiometricPrompt.CryptoObject(crypto.getMac());
|
|
||||||
} else if (crypto.getSignature() != null) {
|
|
||||||
c = new BiometricPrompt.CryptoObject(crypto.getSignature());
|
|
||||||
}
|
|
||||||
|
|
||||||
biometricPrompt.authenticate(c, cancel, mContext.getMainExecutor(), new BiometricPrompt.AuthenticationCallback() {
|
|
||||||
@Override
|
|
||||||
public void onAuthenticationError(int errorCode, CharSequence errString) {
|
|
||||||
callback.onAuthenticationError(errorCode, errString);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
|
|
||||||
callback.onAuthenticationHelp(helpCode, helpString);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
|
|
||||||
|
|
||||||
BiometricPrompt.CryptoObject BioCrypto = result.getCryptoObject();
|
|
||||||
|
|
||||||
CryptoObject c = null;
|
|
||||||
|
|
||||||
if (BioCrypto.getCipher() != null) {
|
|
||||||
c = new CryptoObject(BioCrypto.getCipher());
|
|
||||||
} else if (BioCrypto.getMac() != null) {
|
|
||||||
c = new CryptoObject(BioCrypto.getMac());
|
|
||||||
} else if (BioCrypto.getSignature() != null) {
|
|
||||||
c = new CryptoObject(BioCrypto.getSignature());
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthenticationResult fingerprintResult = new AuthenticationResult();
|
|
||||||
|
|
||||||
if (crypto != null) {
|
|
||||||
fingerprintResult = new MyAuthenticationResult();
|
|
||||||
((MyAuthenticationResult) fingerprintResult).setCryptoObject(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.onAuthenticationSucceeded(fingerprintResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAuthenticationFailed() {
|
|
||||||
callback.onAuthenticationFailed();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void generateKey() {
|
|
||||||
try {
|
|
||||||
|
|
||||||
keyStore = KeyStore.getInstance("AndroidKeyStore");
|
|
||||||
keyStore.load(null);
|
|
||||||
|
|
||||||
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
|
|
||||||
keyGenerator.init(new
|
|
||||||
KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
|
||||||
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
|
||||||
.setUserAuthenticationRequired(true)
|
|
||||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
keyGenerator.generateKey();
|
|
||||||
|
|
||||||
} catch (KeyStoreException
|
|
||||||
| NoSuchAlgorithmException
|
|
||||||
| NoSuchProviderException
|
|
||||||
| InvalidAlgorithmParameterException
|
|
||||||
| CertificateException
|
|
||||||
| IOException exc) {
|
|
||||||
exc.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean initCipher() {
|
|
||||||
try {
|
|
||||||
cipher = Cipher.getInstance(
|
|
||||||
KeyProperties.KEY_ALGORITHM_AES + "/"
|
|
||||||
+ KeyProperties.BLOCK_MODE_CBC + "/"
|
|
||||||
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException |
|
|
||||||
NoSuchPaddingException e) {
|
|
||||||
throw new RuntimeException("Failed to get Cipher", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
keyStore.load(null);
|
|
||||||
SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,
|
|
||||||
null);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
} catch (KeyPermanentlyInvalidatedException e) {
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} catch (KeyStoreException | CertificateException
|
|
||||||
| UnrecoverableKeyException | IOException
|
|
||||||
| NoSuchAlgorithmException | InvalidKeyException e) {
|
|
||||||
|
|
||||||
throw new RuntimeException("Failed to init Cipher", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,75 @@
|
|||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
|
package android.hardware.fingerprint
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.hardware.biometrics.BiometricManager
|
||||||
|
import android.hardware.biometrics.BiometricPrompt
|
||||||
|
import android.os.CancellationSignal
|
||||||
|
import android.os.Handler
|
||||||
|
import android.util.Log
|
||||||
|
import com.edison.fingerface.HandlerExecutor
|
||||||
|
|
||||||
|
class MyFingerprintManager(private val context: Context) : FingerprintManager() {
|
||||||
|
|
||||||
|
private val manager = context.getSystemService(BiometricManager::class.java)!!
|
||||||
|
|
||||||
|
override fun isHardwareDetected(): Boolean {
|
||||||
|
Log.d(TAG, "isHardwareDetected")
|
||||||
|
return when (manager.canAuthenticate()) {
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED,
|
||||||
|
BiometricManager.BIOMETRIC_SUCCESS -> true
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE,
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> false
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasEnrolledFingerprints(): Boolean {
|
||||||
|
Log.d(TAG, "hasEnrolledFingerprints")
|
||||||
|
return when (manager.canAuthenticate()) {
|
||||||
|
BiometricManager.BIOMETRIC_SUCCESS -> true
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED,
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE,
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> false
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CryptoObject.toBio() = when {
|
||||||
|
cipher != null -> BiometricPrompt.CryptoObject(cipher)
|
||||||
|
mac != null -> BiometricPrompt.CryptoObject(mac)
|
||||||
|
signature != null -> BiometricPrompt.CryptoObject(signature)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun authenticate(
|
||||||
|
crypto: CryptoObject?, cancel: CancellationSignal?,
|
||||||
|
flags: Int, legacyCallback: AuthenticationCallback, handler: Handler?
|
||||||
|
) {
|
||||||
|
Log.d(TAG, "authenticate")
|
||||||
|
|
||||||
|
val bioCrypto = crypto?.toBio()
|
||||||
|
val cancelSignal = cancel ?: CancellationSignal()
|
||||||
|
val executor = handler?.let { HandlerExecutor(it) } ?: context.mainExecutor
|
||||||
|
val callback = MyAuthenticationCallback(legacyCallback)
|
||||||
|
|
||||||
|
val biometricPrompt = BiometricPrompt.Builder(context).setTitle("Fingerface")
|
||||||
|
.setNegativeButton(
|
||||||
|
context.getString(android.R.string.cancel),
|
||||||
|
executor,
|
||||||
|
DialogInterface.OnClickListener { dialog, _ -> dialog.dismiss() })
|
||||||
|
.build()
|
||||||
|
|
||||||
|
if (bioCrypto == null) {
|
||||||
|
biometricPrompt.authenticate(cancelSignal, executor, callback)
|
||||||
|
} else {
|
||||||
|
biometricPrompt.authenticate(bioCrypto, cancelSignal, executor, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "Fingerface"
|
||||||
|
}
|
||||||
|
}
|
13
app/src/main/java/com/edison/fingerface/HandlerExecutor.kt
Normal file
13
app/src/main/java/com/edison/fingerface/HandlerExecutor.kt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.edison.fingerface
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import java.util.concurrent.RejectedExecutionException
|
||||||
|
|
||||||
|
class HandlerExecutor(private val handler: Handler) : Executor {
|
||||||
|
override fun execute(command: Runnable) {
|
||||||
|
if (!handler.post(command)) {
|
||||||
|
throw RejectedExecutionException("$handler is shutting down");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
package com.edison.fingerface
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.content.res.XModuleResources
|
|
||||||
import android.hardware.fingerprint.FingerprintManager
|
|
||||||
import android.util.Log
|
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
|
||||||
import de.robv.android.xposed.XSharedPreferences
|
|
||||||
import de.robv.android.xposed.XposedBridge
|
|
||||||
import android.hardware.fingerprint.MyFingerprintManager
|
|
||||||
|
|
||||||
|
|
||||||
class ModFingerface {
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
fun initAndroid(prefs: XSharedPreferences, classLoader: ClassLoader, modRes: XModuleResources) {
|
|
||||||
val getSystemServiceHook = object : XC_MethodHook() {
|
|
||||||
override fun afterHookedMethod(param: MethodHookParam?) {
|
|
||||||
if (param!!.args[0].toString() == Context.FINGERPRINT_SERVICE) {
|
|
||||||
Log.d("XposedHandler", "Get Fingerpring service, call from:${param!!.method.name}, thisObj:${param!!.result}")
|
|
||||||
val mgr = MyFingerprintManager()
|
|
||||||
mgr.SetContext(param!!.thisObject as Context)
|
|
||||||
param!!.result = mgr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XposedBridge.hookAllMethods(
|
|
||||||
Class.forName("android.app.ContextImpl"),
|
|
||||||
"getSystemService",
|
|
||||||
getSystemServiceHook
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package com.edison.fingerface
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.content.res.XModuleResources
|
|
||||||
import android.hardware.fingerprint.FingerprintManager
|
|
||||||
import android.util.Log
|
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
|
||||||
import de.robv.android.xposed.XSharedPreferences
|
|
||||||
import de.robv.android.xposed.XposedBridge
|
|
||||||
import android.hardware.fingerprint.MyFingerprintManager
|
|
||||||
import de.robv.android.xposed.XposedHelpers
|
|
||||||
import android.R.attr.classLoader
|
|
||||||
|
|
||||||
|
|
||||||
class ModPackageManagerService {
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
fun initAndroid(prefs: XSharedPreferences, classLoader: ClassLoader, modRes: XModuleResources) {
|
|
||||||
|
|
||||||
val hasSystemFeatureHook = object : XC_MethodHook() {
|
|
||||||
|
|
||||||
override fun afterHookedMethod(param: MethodHookParam?) {
|
|
||||||
if (param!!.args[0].toString() == PackageManager.FEATURE_FINGERPRINT) {
|
|
||||||
param!!.result = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XposedHelpers.findAndHookMethod("android.app.ContextImpl", classLoader,
|
|
||||||
"getPackageManager", object : XC_MethodHook() {
|
|
||||||
@Throws(Throwable::class)
|
|
||||||
override fun afterHookedMethod(param: MethodHookParam?) {
|
|
||||||
if (param!!.result is PackageManager) {
|
|
||||||
val clazz = param.result.javaClass
|
|
||||||
val packageMethod = clazz.getDeclaredMethod("hasSystemFeature", String::class.java)
|
|
||||||
|
|
||||||
XposedBridge.hookMethod(packageMethod, hasSystemFeatureHook)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
package com.edison.fingerface;
|
|
||||||
|
|
||||||
import android.app.AndroidAppHelper;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.PermissionInfo;
|
|
||||||
import android.content.res.XModuleResources;
|
|
||||||
import android.content.res.XResources;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.util.Pair;
|
|
||||||
import de.robv.android.xposed.*;
|
|
||||||
import de.robv.android.xposed.callbacks.XC_InitPackageResources;
|
|
||||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class XposedHandler implements IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources {
|
|
||||||
public static final String PACKAGE_NAME = XposedHandler.class.getPackage().getName();
|
|
||||||
private static final String TAG = "Fingerface";
|
|
||||||
|
|
||||||
private static XSharedPreferences prefs;
|
|
||||||
public static XModuleResources modRes;
|
|
||||||
private static String MODULE_PATH = null;
|
|
||||||
|
|
||||||
public static List<Pair<XResources, String>> packageResources = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initZygote(StartupParam startupParam) throws Throwable {
|
|
||||||
MODULE_PATH = startupParam.modulePath;
|
|
||||||
modRes = XModuleResources.createInstance(MODULE_PATH, null);
|
|
||||||
prefs = new XSharedPreferences(PACKAGE_NAME);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam resparam) throws Throwable {
|
|
||||||
|
|
||||||
if (resparam.packageName.equals("android")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
|
|
||||||
|
|
||||||
if (!lpparam.processName.equals("android") && !lpparam.processName.equals("com.android.systemui")) {
|
|
||||||
ModFingerface.initAndroid(prefs, lpparam.classLoader, modRes);
|
|
||||||
ModPackageManagerService.initAndroid(prefs, lpparam.classLoader, modRes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
62
app/src/main/java/com/edison/fingerface/XposedHandler.kt
Normal file
62
app/src/main/java/com/edison/fingerface/XposedHandler.kt
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package com.edison.fingerface
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.res.XModuleResources
|
||||||
|
import android.hardware.fingerprint.MyFingerprintManager
|
||||||
|
import de.robv.android.xposed.*
|
||||||
|
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||||
|
|
||||||
|
class XposedHandler : IXposedHookZygoteInit, IXposedHookLoadPackage {
|
||||||
|
|
||||||
|
private lateinit var modulePath: String
|
||||||
|
private lateinit var modRes: XModuleResources
|
||||||
|
private lateinit var prefs: XSharedPreferences
|
||||||
|
|
||||||
|
override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) {
|
||||||
|
modulePath = startupParam.modulePath
|
||||||
|
modRes = XModuleResources.createInstance(modulePath, null)
|
||||||
|
prefs = XSharedPreferences(BuildConfig.APPLICATION_ID)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
|
||||||
|
if (lpparam.processName != "android" && lpparam.processName != "com.android.systemui") {
|
||||||
|
hookFingerprintService(lpparam.classLoader)
|
||||||
|
hookPackageManager(lpparam.classLoader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hookFingerprintService(cl: ClassLoader) {
|
||||||
|
val getSystemServiceHook = object : XC_MethodHook() {
|
||||||
|
override fun afterHookedMethod(param: MethodHookParam) {
|
||||||
|
if (param.args[0].toString() == Context.FINGERPRINT_SERVICE) {
|
||||||
|
param.result = MyFingerprintManager(param.thisObject as Context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XposedHelpers.findAndHookMethod(
|
||||||
|
"android.app.ContextImpl", cl,
|
||||||
|
"getSystemService", String::class.java,
|
||||||
|
getSystemServiceHook
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hookPackageManager(cl: ClassLoader) {
|
||||||
|
val hasSystemFeatureHook = object : XC_MethodHook() {
|
||||||
|
override fun afterHookedMethod(param: MethodHookParam) {
|
||||||
|
if (param.args[0].toString() == PackageManager.FEATURE_FINGERPRINT) {
|
||||||
|
param.result = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XposedHelpers.findAndHookMethod(
|
||||||
|
"android.app.ApplicationPackageManager", cl,
|
||||||
|
"hasSystemFeature", String::class.java,
|
||||||
|
hasSystemFeatureHook
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user