feat: Optimized kill signature verification feature

Added a public method, `replaceApplication`. This method uses Xposed to intercept `android.app.ApplicationPackageManager`'s `getApplicationInfo` and `getApplicationInfoAsUser`. It allows for dynamic changes to the application's `sourceDir` and `publicSourceDir` to redirect the location where the system loads APKs.
This commit is contained in:
NkBe 2025-10-07 21:33:04 +08:00
parent d644c22ade
commit 5d21b9c599
No known key found for this signature in database
GPG Key ID: 525137026FF031DF
2 changed files with 31 additions and 1 deletions

View File

@ -204,6 +204,7 @@ public class LSPApplication {
}
Log.i(TAG,"createLoadedApkWithContext cost: " + (System.currentTimeMillis() - timeStart) + "ms");
SigBypass.replaceApplication(appInfo.packageName, appInfo.sourceDir, appInfo.publicSourceDir);
return context;
} catch (Throwable e) {
Log.e(TAG, "createLoadedApk", e);

View File

@ -3,6 +3,7 @@ package org.lsposed.lspatch.loader;
import static org.lsposed.lspatch.share.Constants.ORIGINAL_APK_ASSET_PATH;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
@ -31,7 +32,7 @@ import de.robv.android.xposed.XposedHelpers;
public class SigBypass {
private static final String TAG = "LSPatch-SigBypass";
private static final String TAG = "NPatch-SigBypass";
private static final Map<String, String> signatures = new HashMap<>();
private static void replaceSignature(Context context, PackageInfo packageInfo) {
@ -116,6 +117,34 @@ public class SigBypass {
}
}
public static void replaceApplication(String packageName, String sourceDir, String resourcesDir) throws IOException {
try {
Log.i(TAG, "Start Replace application info for `" + packageName + "`");
XposedBridge.hookAllMethods(Class.forName("android.app.ApplicationPackageManager"), "getApplicationInfo", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (packageName.equals(param.args[0])) {
ApplicationInfo info = (ApplicationInfo) param.getResult();
info.sourceDir = sourceDir;
info.publicSourceDir = sourceDir;
}
}
});
XposedBridge.hookAllMethods(Class.forName("android.app.ApplicationPackageManager"), "getApplicationInfoAsUser", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (packageName.equals(param.args[0])) {
ApplicationInfo info = (ApplicationInfo) param.getResult();
info.sourceDir = sourceDir;
info.publicSourceDir = sourceDir;
}
}
});
} catch (Throwable e) {
Log.w(TAG, "fail to replace getApplicationInfo", e);
}
}
static void doSigBypass(Context context, int sigBypassLevel) throws IOException {
if (sigBypassLevel >= Constants.SIGBYPASS_LV_PM) {
hookPackageParser(context);