diff --git a/src/full/java/com/topjohnwu/magisk/MagiskFragment.java b/src/full/java/com/topjohnwu/magisk/MagiskFragment.java index 9e63c578a..d3edabbef 100644 --- a/src/full/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/src/full/java/com/topjohnwu/magisk/MagiskFragment.java @@ -23,8 +23,8 @@ import com.topjohnwu.magisk.asyncs.CheckUpdates; import com.topjohnwu.magisk.components.AlertDialogBuilder; import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.Fragment; -import com.topjohnwu.magisk.utils.ISafetyNetHelper; import com.topjohnwu.magisk.utils.Const; +import com.topjohnwu.magisk.utils.ISafetyNetHelper; import com.topjohnwu.magisk.utils.RootUtils; import com.topjohnwu.magisk.utils.ShowUI; import com.topjohnwu.magisk.utils.Topic; diff --git a/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java b/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java index 657da4bdd..9fb81bbac 100644 --- a/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java +++ b/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java @@ -3,8 +3,8 @@ package com.topjohnwu.magisk.asyncs; import android.app.Activity; import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.utils.ISafetyNetHelper; import com.topjohnwu.magisk.utils.Const; +import com.topjohnwu.magisk.utils.ISafetyNetHelper; import com.topjohnwu.magisk.utils.WebService; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; @@ -13,7 +13,6 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; diff --git a/src/full/java/com/topjohnwu/magisk/asyncs/HideManager.java b/src/full/java/com/topjohnwu/magisk/asyncs/HideManager.java index 753b65afd..9c821a7c0 100644 --- a/src/full/java/com/topjohnwu/magisk/asyncs/HideManager.java +++ b/src/full/java/com/topjohnwu/magisk/asyncs/HideManager.java @@ -7,17 +7,15 @@ import android.widget.Toast; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.utils.Const; +import com.topjohnwu.magisk.utils.PatchAPK; import com.topjohnwu.magisk.utils.RootUtils; -import com.topjohnwu.magisk.utils.ZipUtils; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.superuser.io.SuFile; import com.topjohnwu.superuser.io.SuFileOutputStream; -import com.topjohnwu.utils.JarMap; -import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.security.SecureRandom; -import java.util.jar.JarEntry; public class HideManager extends ParallelTask { @@ -48,51 +46,6 @@ public class HideManager extends ParallelTask { return builder.toString(); } - private int findOffset(byte buf[], byte pattern[]) { - int offset = -1; - for (int i = 0; i < buf.length - pattern.length; ++i) { - boolean match = true; - for (int j = 0; j < pattern.length; ++j) { - if (buf[i + j] != pattern[j]) { - match = false; - break; - } - } - if (match) { - offset = i; - break; - } - } - return offset; - } - - /* It seems that AAPT sometimes generate another type of string format */ - private boolean fallbackPatch(byte xml[], String from, String to) { - - byte[] target = new byte[from.length() * 2 + 2]; - for (int i = 0; i < from.length(); ++i) { - target[i * 2] = (byte) from.charAt(i); - } - int offset = findOffset(xml, target); - if (offset < 0) - return false; - byte[] dest = new byte[target.length - 2]; - for (int i = 0; i < to.length(); ++i) { - dest[i * 2] = (byte) to.charAt(i); - } - System.arraycopy(dest, 0, xml, offset, dest.length); - return true; - } - - private boolean findAndPatch(byte xml[], String from, String to) { - byte target[] = (from + '\0').getBytes(); - int offset = findOffset(xml, target); - if (offset < 0) - return fallbackPatch(xml, from, to); - System.arraycopy(to.getBytes(), 0, xml, offset, to.length()); - return true; - } - @Override protected void onPreExecute() { dialog = ProgressDialog.show(getActivity(), @@ -104,28 +57,17 @@ public class HideManager extends ParallelTask { protected Boolean doInBackground(Void... voids) { MagiskManager mm = MagiskManager.get(); - // Generate a new unhide app with random package name + // Generate a new app with random package name SuFile repack = new SuFile("/data/local/tmp/repack.apk", true); String pkg = genPackageName("com.", Const.ORIG_PKG_NAME.length()); try { - // Read whole APK into memory - JarMap apk = new JarMap(new FileInputStream(mm.getPackageCodePath())); - JarEntry je = new JarEntry(Const.ANDROID_MANIFEST); - byte xml[] = apk.getRawData(je); - - if (!findAndPatch(xml, Const.ORIG_PKG_NAME, pkg)) + if (!PatchAPK.patchPackageID( + mm.getPackageCodePath(), + new SuFileOutputStream(repack), + Const.ORIG_PKG_NAME, pkg)) return false; - if (!findAndPatch(xml, Const.ORIG_PKG_NAME + ".provider", pkg + ".provider")) - return false; - - // Write in changes - apk.getOutputStream(je).write(xml); - - // Sign the APK - ZipUtils.signZip(apk, new SuFileOutputStream(repack)); - } catch (Exception e) { - e.printStackTrace(); + } catch (FileNotFoundException e) { return false; } diff --git a/src/full/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java b/src/full/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java new file mode 100644 index 000000000..33e2f82ce --- /dev/null +++ b/src/full/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java @@ -0,0 +1,48 @@ +package com.topjohnwu.magisk.receivers; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Handler; + +import com.topjohnwu.magisk.utils.Const; +import com.topjohnwu.magisk.utils.PatchAPK; +import com.topjohnwu.magisk.utils.Utils; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; + +public class ManagerUpdate extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + Utils.dlAndReceive( + context, new PatchedInstall(), + intent.getStringExtra(Const.Key.INTENT_SET_LINK), + intent.getStringExtra(Const.Key.INTENT_SET_FILENAME) + ); + } + + private static class PatchedInstall extends ManagerInstall { + @Override + public void onDownloadDone(Context context, Uri uri) { + if (!context.getPackageName().equals(Const.ORIG_PKG_NAME)) { + AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { + String o = uri.getPath(); + String p = o.substring(0, o.lastIndexOf('.')) + "-patched.apk"; + try { + PatchAPK.patchPackageID(o, new BufferedOutputStream(new FileOutputStream(p)), + Const.ORIG_PKG_NAME, context.getPackageName()); + } catch (FileNotFoundException ignored) { } + super.onDownloadDone(context, Uri.fromFile(new File(p))); + }); + } else { + super.onDownloadDone(context, uri); + } + } + } +} diff --git a/src/full/java/com/topjohnwu/magisk/utils/PatchAPK.java b/src/full/java/com/topjohnwu/magisk/utils/PatchAPK.java new file mode 100644 index 000000000..516ed365b --- /dev/null +++ b/src/full/java/com/topjohnwu/magisk/utils/PatchAPK.java @@ -0,0 +1,77 @@ +package com.topjohnwu.magisk.utils; + +import com.topjohnwu.utils.JarMap; + +import java.io.OutputStream; +import java.util.jar.JarEntry; + +public class PatchAPK { + + private static int findOffset(byte buf[], byte pattern[]) { + int offset = -1; + for (int i = 0; i < buf.length - pattern.length; ++i) { + boolean match = true; + for (int j = 0; j < pattern.length; ++j) { + if (buf[i + j] != pattern[j]) { + match = false; + break; + } + } + if (match) { + offset = i; + break; + } + } + return offset; + } + + /* It seems that AAPT sometimes generate another type of string format */ + private static boolean fallbackPatch(byte xml[], String from, String to) { + + byte[] target = new byte[from.length() * 2 + 2]; + for (int i = 0; i < from.length(); ++i) { + target[i * 2] = (byte) from.charAt(i); + } + int offset = findOffset(xml, target); + if (offset < 0) + return false; + byte[] dest = new byte[target.length - 2]; + for (int i = 0; i < to.length(); ++i) { + dest[i * 2] = (byte) to.charAt(i); + } + System.arraycopy(dest, 0, xml, offset, dest.length); + return true; + } + + private static boolean findAndPatch(byte xml[], String from, String to) { + byte target[] = (from + '\0').getBytes(); + int offset = findOffset(xml, target); + if (offset < 0) + return fallbackPatch(xml, from, to); + System.arraycopy(to.getBytes(), 0, xml, offset, to.length()); + return true; + } + + public static boolean patchPackageID(String fileName, OutputStream out, String from, String to) { + try { + JarMap apk = new JarMap(fileName); + JarEntry je = apk.getJarEntry(Const.ANDROID_MANIFEST); + byte xml[] = apk.getRawData(je); + + if (!findAndPatch(xml, from, to)) + return false; + if (!findAndPatch(xml, from + ".provider", to + ".provider")) + return false; + + // Write in changes + apk.getOutputStream(je).write(xml); + + // Sign the APK + ZipUtils.signZip(apk, out); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } +} diff --git a/src/full/java/com/topjohnwu/magisk/utils/ShowUI.java b/src/full/java/com/topjohnwu/magisk/utils/ShowUI.java index 009005504..d05b7b36d 100644 --- a/src/full/java/com/topjohnwu/magisk/utils/ShowUI.java +++ b/src/full/java/com/topjohnwu/magisk/utils/ShowUI.java @@ -113,7 +113,7 @@ public class ShowUI { .setPositiveButton(R.string.yes, (d, i) -> { Utils.dlAndReceive(activity, new DownloadReceiver() { @Override - public void onDownloadDone(Uri uri) { + public void onDownloadDone(Context context, Uri uri) { new InstallMagisk(activity, uri).exec(); } }, mm.magiskLink, filename); @@ -167,7 +167,7 @@ public class ShowUI { activity, new DownloadReceiver() { @Override - public void onDownloadDone(Uri uri) { + public void onDownloadDone(Context context, Uri uri) { Intent intent = new Intent(mm, FlashActivity.class); intent.setData(uri) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) @@ -185,7 +185,7 @@ public class ShowUI { case 0: receiver = new DownloadReceiver() { @Override - public void onDownloadDone(Uri uri) { + public void onDownloadDone(Context context, Uri uri) { SnackbarMaker.showUri(activity, uri); } }; @@ -196,7 +196,7 @@ public class ShowUI { return; receiver = new DownloadReceiver() { @Override - public void onDownloadDone(Uri uri) { + public void onDownloadDone(Context context, Uri uri) { Intent intent = new Intent(mm, FlashActivity.class); intent.setData(uri) .putExtra(Const.Key.FLASH_SET_BOOT, boot) @@ -221,7 +221,7 @@ public class ShowUI { return; receiver = new DownloadReceiver() { @Override - public void onDownloadDone(Uri uri) { + public void onDownloadDone(Context context, Uri uri) { Intent intent = new Intent(mm, FlashActivity.class); intent.setData(uri) .putExtra(Const.Key.FLASH_SET_BOOT, boot) diff --git a/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java b/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java index 5cdff9c87..72aa7654f 100644 --- a/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java +++ b/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java @@ -32,7 +32,7 @@ public abstract class DownloadReceiver extends BroadcastReceiver { switch (status) { case DownloadManager.STATUS_SUCCESSFUL: Uri uri = Uri.parse(c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))); - onDownloadDone(uri); + onDownloadDone(context, uri); break; default: MagiskManager.toast(R.string.download_file_error, Toast.LENGTH_LONG); @@ -55,5 +55,5 @@ public abstract class DownloadReceiver extends BroadcastReceiver { return this; } - public abstract void onDownloadDone(Uri uri); + public abstract void onDownloadDone(Context context, Uri uri); } diff --git a/src/main/java/com/topjohnwu/magisk/receivers/ManagerInstall.java b/src/main/java/com/topjohnwu/magisk/receivers/ManagerInstall.java new file mode 100644 index 000000000..87138a77f --- /dev/null +++ b/src/main/java/com/topjohnwu/magisk/receivers/ManagerInstall.java @@ -0,0 +1,29 @@ +package com.topjohnwu.magisk.receivers; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.support.v4.content.FileProvider; + +import java.io.File; + +public class ManagerInstall extends DownloadReceiver { + @Override + public void onDownloadDone(Context context, Uri uri) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE); + install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + Uri content = FileProvider.getUriForFile(context, + context.getPackageName() + ".provider", new File(uri.getPath())); + install.setData(content); + context.startActivity(install); + } else { + Intent install = new Intent(Intent.ACTION_VIEW); + install.setDataAndType(uri, "application/vnd.android.package-archive"); + install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(install); + } + } +} diff --git a/src/main/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java b/src/main/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java deleted file mode 100644 index 7a28c16cf..000000000 --- a/src/main/java/com/topjohnwu/magisk/receivers/ManagerUpdate.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.topjohnwu.magisk.receivers; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.support.v4.content.FileProvider; - -import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Utils; - -import java.io.File; - -public class ManagerUpdate extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - Utils.dlAndReceive( - context, - new DownloadReceiver() { - @Override - public void onDownloadDone(Uri uri) { - if (!context.getPackageName().equals(Const.ORIG_PKG_NAME)) { - Utils.getMagiskManager(context).dumpPrefs(); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE); - install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Uri content = FileProvider.getUriForFile(context, - context.getPackageName() + ".provider", new File(uri.getPath())); - install.setData(content); - context.startActivity(install); - } else { - Intent install = new Intent(Intent.ACTION_VIEW); - install.setDataAndType(uri, "application/vnd.android.package-archive"); - install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(install); - } - } - }, - intent.getStringExtra(Const.Key.INTENT_SET_LINK), - intent.getStringExtra(Const.Key.INTENT_SET_FILENAME) - ); - } -} diff --git a/src/stub/AndroidManifest.xml b/src/stub/AndroidManifest.xml index be13a2b7e..32b570274 100644 --- a/src/stub/AndroidManifest.xml +++ b/src/stub/AndroidManifest.xml @@ -11,8 +11,6 @@ - - \ No newline at end of file diff --git a/src/stub/java/com/topjohnwu/magisk/NoUIActivity.java b/src/stub/java/com/topjohnwu/magisk/NoUIActivity.java index 83bff37f6..4caa96115 100644 --- a/src/stub/java/com/topjohnwu/magisk/NoUIActivity.java +++ b/src/stub/java/com/topjohnwu/magisk/NoUIActivity.java @@ -2,12 +2,11 @@ package com.topjohnwu.magisk; import android.Manifest; import android.app.AlertDialog; -import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import com.topjohnwu.magisk.components.Activity; -import com.topjohnwu.magisk.receivers.ManagerUpdate; +import com.topjohnwu.magisk.receivers.ManagerInstall; import com.topjohnwu.magisk.utils.Const; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebService; @@ -46,10 +45,7 @@ public class NoUIActivity extends Activity { .setMessage(R.string.upgrade_msg) .setPositiveButton(R.string.yes, (d, w) -> runWithPermission(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> { - Intent intent = new Intent(this, ManagerUpdate.class); - intent.putExtra(Const.Key.INTENT_SET_LINK, apkLink); - intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename); - sendBroadcast(intent); + Utils.dlAndReceive(this, new ManagerInstall(), apkLink, filename); finish(); })) .setNegativeButton(R.string.no_thanks, (d, w) -> finish())