Dynamic load updated APK for patching
Magisk Manager sometimes updates the code for patching the APK due to several changes. When an old manager tries to patch an updated APK using its internal methods, it is sometimes incomplete, or simply won't work at all. This commit exposes an API that can be dynamically loaded from an old app to invoke the updated patchAPK method from the downloaded new APK.
This commit is contained in:
parent
2e10fa494f
commit
6d27eb7f64
@ -1,10 +1,13 @@
|
|||||||
package a;
|
package a;
|
||||||
|
|
||||||
import com.topjohnwu.core.utils.BootSigner;
|
import com.topjohnwu.core.utils.BootSigner;
|
||||||
|
import com.topjohnwu.magisk.utils.PatchAPK;
|
||||||
|
|
||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
public class a extends BootSigner {
|
public class a extends BootSigner {
|
||||||
/* stub */
|
public static boolean patchAPK(String in, String out, String pkg) {
|
||||||
|
return PatchAPK.patch(in, out, pkg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ import java.io.BufferedOutputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
|
import dalvik.system.DexClassLoader;
|
||||||
|
|
||||||
public class DownloadApp {
|
public class DownloadApp {
|
||||||
|
|
||||||
public static void upgrade(String name) {
|
public static void upgrade(String name) {
|
||||||
@ -72,10 +74,16 @@ public class DownloadApp {
|
|||||||
progress.update();
|
progress.update();
|
||||||
patched = new File(apk.getParent(), "patched.apk");
|
patched = new File(apk.getParent(), "patched.apk");
|
||||||
try {
|
try {
|
||||||
JarMap jarMap = PatchAPK.patch(apk.getPath(), app.getPackageName());
|
// Try using the new APK to patch itself
|
||||||
SignAPK.sign(jarMap, new BufferedOutputStream(new FileOutputStream(patched)));
|
ClassLoader loader = new DexClassLoader(apk.getPath(),
|
||||||
|
apk.getParent(), null, ClassLoader.getSystemClassLoader());
|
||||||
|
loader.loadClass("a.a")
|
||||||
|
.getMethod("patchAPK", String.class, String.class, String.class)
|
||||||
|
.invoke(null, apk.getPath(), patched.getPath(), app.getPackageName());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return;
|
e.printStackTrace();
|
||||||
|
// Fallback to use the current implementation
|
||||||
|
PatchAPK.patch(apk.getPath(), patched.getPath(), app.getPackageName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
APKInstall.install(app, patched);
|
APKInstall.install(app, patched);
|
||||||
|
@ -102,14 +102,8 @@ public class PatchAPK {
|
|||||||
File repack = new File(app.getFilesDir(), "patched.apk");
|
File repack = new File(app.getFilesDir(), "patched.apk");
|
||||||
String pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length());
|
String pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length());
|
||||||
|
|
||||||
try {
|
if (!patch(app.getPackageCodePath(), repack.getPath(), pkg))
|
||||||
JarMap apk;
|
|
||||||
if ((apk = patch(app.getPackageCodePath(), pkg)) == null)
|
|
||||||
return false;
|
return false;
|
||||||
SignAPK.sign(apk, new BufferedOutputStream(new FileOutputStream(repack)));
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install the application
|
// Install the application
|
||||||
repack.setReadable(true, false);
|
repack.setReadable(true, false);
|
||||||
@ -123,23 +117,24 @@ public class PatchAPK {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JarMap patch(String apk, String pkg) {
|
public static boolean patch(String in, String out, String pkg) {
|
||||||
try {
|
try {
|
||||||
JarMap jar = new JarMap(apk);
|
JarMap jar = new JarMap(in);
|
||||||
JarEntry je = jar.getJarEntry(Const.ANDROID_MANIFEST);
|
JarEntry je = jar.getJarEntry(Const.ANDROID_MANIFEST);
|
||||||
byte xml[] = jar.getRawData(je);
|
byte xml[] = jar.getRawData(je);
|
||||||
|
|
||||||
if (!findAndPatch(xml, BuildConfig.APPLICATION_ID, pkg) ||
|
if (!findAndPatch(xml, BuildConfig.APPLICATION_ID, pkg) ||
|
||||||
!findAndPatch(xml, R.string.app_name, R.string.re_app_name))
|
!findAndPatch(xml, R.string.app_name, R.string.re_app_name))
|
||||||
return null;
|
return false;
|
||||||
|
|
||||||
// Write in changes
|
// Write in changes
|
||||||
jar.getOutputStream(je).write(xml);
|
jar.getOutputStream(je).write(xml);
|
||||||
return jar;
|
SignAPK.sign(jar, new BufferedOutputStream(new FileOutputStream(out)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void hideManager() {
|
public static void hideManager() {
|
||||||
|
Loading…
Reference in New Issue
Block a user