Java tutorial
/* Android IMSI-Catcher Detector | (c) AIMSICD Privacy Project * ----------------------------------------------------------- * LICENSE: http://git.io/vJaf6 | TERMS: http://git.io/vJMf5 * ----------------------------------------------------------- */ /* * @author Copyright Paul Kinsella paulkinsella29@yahoo.ie This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.SecUpwN.AIMSICD.smsdetection; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.os.IBinder; import android.support.v4.app.NotificationCompat; import android.util.Log; import com.SecUpwN.AIMSICD.AIMSICD; import com.SecUpwN.AIMSICD.R; import com.SecUpwN.AIMSICD.service.AimsicdService; import com.SecUpwN.AIMSICD.utils.Device; import com.SecUpwN.AIMSICD.utils.MiscUtils; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; /** * Copyright Paul Kinsella paulkinsella29@yahoo.ie on 19/04/15. * * * For this to work better Samsung users will have to * set debug level to high in SysDump menu *#9900# or *#*#9900#*#* * * To Use: * SmsDetector smsdetector = new SmsDetector(context); * * smsdetector.startSmsDetection(); * smsdetector.stopSmsDetection(); * * This is by no means a complete detection method but gives us something to work off. * * TODO if you feel like this class needs improvement feel free to make a PR. * * TODO @SecUpwn make a list of phones that this method works on with feedback from users. * * PHONE:Samsung S5 MODEL:SM-G900F ANDROID_VER:4.4.2 TYPE0:YES SILENTVOICE:YES * PHONE:Sony Xperia J MODEL:ST260i ANDROID_VER:4.1.2 TYPE0:NO SILENTVOICE:YES * */ public class SmsDetector extends Thread { final static String TAG = "SmsDetector"; private DataInputStream dis; private DataOutputStream dos; private AimsicdService mAimsicdService; private SharedPreferences prefs; private boolean mBound; SmsDetectionDbAccess dbacess; static Context tContext; String[] SILENT_ONLY_TAGS; String XPERIA_J_INDICATOR = "QCRIL_RPC#POSSIBLE TYPE 0 DETECTED", /*Experimental code to check for SMS_ACKNOWLEDGE true in logcat and sms true in Broadcast Receiver*/ CHECK_BROADCAST_REC = " SMS_ACKNOWLEDGE true #UNKNOWN_SILENT_SMS_DETECTED"; /* this array holds known values to get the senders number and sms data */ String DETECTION_PHONENUM_SMS_DATA[] = { "SMS originating address:", "SMS message body (raw):", "OrigAddr" }; public static boolean isrunning = false; public static boolean getSmsDetectionState() { return isrunning; } public static void setSmsDetectionState(boolean isrunning) { SmsDetector.isrunning = isrunning; } public SmsDetector(Context newcontext) { tContext = newcontext; dbacess = new SmsDetectionDbAccess(newcontext); dbacess.open(); ArrayList<AdvanceUserItems> silent_string = dbacess.getDetectionStrings(); dbacess.close(); SILENT_ONLY_TAGS = new String[silent_string.size()]; for (int x = 0; x < silent_string.size(); x++) { SILENT_ONLY_TAGS[x] = silent_string.get(x).getDetection_string() + "#" + silent_string.get(x).getDetection_type(); } prefs = newcontext.getSharedPreferences(AimsicdService.SHARED_PREFERENCES_BASENAME, 0); } public void startSmsDetection() { Intent intent = new Intent(tContext, AimsicdService.class); tContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); start(); Log.i(TAG, "sms detection started"); } public void stopSmsDetection() { setSmsDetectionState(false); // Unbind from the service if (mBound) { tContext.unbindService(mConnection); mBound = false; } Log.i(TAG, "sms detection stopped"); } @Override public void run() { setSmsDetectionState(true); try { try { new Thread().sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } try { String MODE = "logcat -b radio\n";// default Runtime r = Runtime.getRuntime(); Process process = r.exec("su"); dos = new DataOutputStream(process.getOutputStream()); dos.writeBytes(MODE); dos.flush(); dis = new DataInputStream(process.getInputStream()); } catch (IOException e) { e.printStackTrace(); } while (getSmsDetectionState()) { try { int bufferlen = dis.available(); //System.out.println("DEBUG>> Buff Len " +bufferlen); if (bufferlen != 0) { byte[] b = new byte[bufferlen]; dis.read(b); String split[] = new String(b).split("\n"); checkForSilentSms(split); } else { Thread.sleep(1000); } } catch (IOException e) { if (e.getMessage() != null) System.out.println(e.getMessage()); e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } finally { } } public void checkForSilentSms(String[] progress) { for (int arrayindex = 0; arrayindex < SILENT_ONLY_TAGS.length; arrayindex++) { int MAX_INT = progress.length - 4; for (int x = 0; x < progress.length; x++) {//check all progress buffer for strings if (progress[x].length() < 250) {//check only short strings for faster processing /* CHECK THAT THE BROADCAST RECEIVER PICKED UP AN SMS. future code Idea behind this code is if we pick up and SMS_ACK in logcat and the sms broadcast receiver did not pick up an sms then we received some sort of silent sms. When a new sms arrives, logcat picks up many SMS_ACKS so code is buggy at the moment. */ /* if (progress[x].contains(CHECK_BROADCAST_REC.split("#")[0])) { try { Thread.sleep(2000); if (!TextMessageReceiver.isIS_MESSAGE_RECEIVED()) { Toast.makeText(mContext, CHECK_BROADCAST_REC.split("#")[1], Toast.LENGTH_LONG).show(); break; } } catch (Exception err) { } }*/ /* THE ONLY INDICATION OF A TYPE 0 ON SONY XPERIA J IS 4 OF THIS STRING [QCRIL_RPC] RIGHT AFTER EACH OTHER. Code is to buggy to many QCRIL_RPC strings Disabled for now because its to unstable */ /* if (x <= MAX_INT) { if ((progress[x].contains(XPERIA_J_INDICATOR.split("#")[0]) && progress[x].length() < 11) && (progress[x + 1].contains(XPERIA_J_INDICATOR.split("#")[0])&& progress[x].length() < 11) && (progress[x + 2].contains(XPERIA_J_INDICATOR.split("#")[0])&& progress[x].length() < 11) && (progress[x + 3].contains(XPERIA_J_INDICATOR.split("#")[0])&& progress[x].length() < 11)) { //Toast.makeText(mContext, XPERIA_J_INDICATOR.split("#")[1], Toast.LENGTH_LONG).show(); break; } } */ if (progress[x].contains(SILENT_ONLY_TAGS[arrayindex].split("#")[0])) { System.out.println("Detected>>>>" + SILENT_ONLY_TAGS[arrayindex].split("#")[1]); if (SILENT_ONLY_TAGS[arrayindex].split("#")[1].equals("TYPE0")) { CapturedSmsData setmsg = new CapturedSmsData(); setmsg.setSenderNumber("unknown");//default setmsg.setSenderMsg("no data");//default /* * count back to get senders number if any * senders numuber is usually back about -15 * in the array. * */ int newcount = (x - 15); //System.out.println("NewCount >>> "+newcount+" Xcount>>>>> "+x); if (newcount > 0) {//only check if array length is not -minus (if minus we cant count back so skip) while (newcount < x) { if (progress[newcount].contains(DETECTION_PHONENUM_SMS_DATA[2].toString())) { try { //Looking for OrigAddr this is where type0 sender number is String number = progress[newcount] .substring(progress[newcount].indexOf("OrigAddr")) .replace(DETECTION_PHONENUM_SMS_DATA[2].toString(), "").trim(); setmsg.setSenderNumber(number);//default } catch (Exception ee) { Log.e(TAG, "Error parsing number"); } //System.out.println("Number>>>"+number); } else if (progress[newcount] .contains(DETECTION_PHONENUM_SMS_DATA[1].toString())) { try { String smsdata = progress[newcount].substring( progress[newcount].indexOf("'") + 1, progress[newcount].length() - 1); //System.out.println("SMS Data>>>"+smsdata); setmsg.setSenderMsg(smsdata); } catch (Exception ee) { Log.e(TAG, "Error parsing sms data"); } } newcount++; } } setmsg.setSmsTimestamp(MiscUtils.getCurrentTimeStamp()); setmsg.setSmsType("TYPE0"); setmsg.setCurrent_lac(mAimsicdService.getCellTracker().getMonitorCell().getLAC()); setmsg.setCurrent_cid(mAimsicdService.getCellTracker().getMonitorCell().getCID()); setmsg.setCurrent_nettype( Device.getNetworkTypeName(mAimsicdService.getCell().getNetType())); setmsg.setCurrent_roam_status(mAimsicdService.getCellTracker().getDevice().isRoaming()); //TODO is this the right place to get upto date geo location? setmsg.setCurrent_gps_lat(mAimsicdService.lastKnownLocation().getLatitudeInDegrees()); setmsg.setCurrent_gps_lon(mAimsicdService.lastKnownLocation().getLongitudeInDegrees()); dbacess.open(); dbacess.storeCapturedSms(setmsg); dbacess.close(); MiscUtils.startPopUpInfo(tContext, 6); } else if (SILENT_ONLY_TAGS[arrayindex].split("#")[1].trim().equals("SILENTVOICE")) { Log.i(TAG, "SILENT DETECTED"); CapturedSmsData setmsg = new CapturedSmsData(); setmsg.setSenderNumber("unknown");//default setmsg.setSenderMsg("no data");//default int newcount = (x - 15); //System.out.println("NewCount >>> "+newcount+" Xcount>>>>> "+x); if (newcount > 0) {//only check if array length is not -minus while (newcount < x) { if (progress[newcount].contains(DETECTION_PHONENUM_SMS_DATA[0].toString())) { /* This first try usually has the number of the sender * and second try is just there incase OrigAddr string shows. * */ try { String number = progress[newcount] .substring(progress[newcount].indexOf("+")); setmsg.setSenderNumber(number);//default } catch (Exception ee) { } //System.out.println("Number>>>"+number); } else if (progress[newcount] .contains(DETECTION_PHONENUM_SMS_DATA[2].toString())) { try { //Looking for OrigAddr this is where sender number is String number = progress[newcount] .substring(progress[newcount].indexOf("OrigAddr")) .replace(DETECTION_PHONENUM_SMS_DATA[2].toString(), "").trim(); setmsg.setSenderNumber(number);//default } catch (Exception ee) { Log.e(TAG, "Error parsing number"); } //System.out.println("Number>>>"+number); } else if (progress[newcount] .contains(DETECTION_PHONENUM_SMS_DATA[1].toString())) { try { String smsdata = progress[newcount].substring( progress[newcount].indexOf("'") + 1, progress[newcount].length() - 1); //System.out.println("SMS Data>>>"+smsdata); setmsg.setSenderMsg(smsdata); } catch (Exception ee) { Log.e(TAG, "Error parsing sms data"); } } newcount++; } } setmsg.setSmsTimestamp(MiscUtils.getCurrentTimeStamp()); setmsg.setSmsType("SILENTVOICE"); setmsg.setCurrent_lac(mAimsicdService.getCellTracker().getMonitorCell().getLAC()); setmsg.setCurrent_cid(mAimsicdService.getCellTracker().getMonitorCell().getCID()); setmsg.setCurrent_nettype( Device.getNetworkTypeName(mAimsicdService.getCell().getNetType())); setmsg.setCurrent_roam_status(mAimsicdService.getCellTracker().getDevice().isRoaming()); //TODO is this the right place to get upto date geo location? setmsg.setCurrent_gps_lat(mAimsicdService.lastKnownLocation().getLatitudeInDegrees()); setmsg.setCurrent_gps_lon(mAimsicdService.lastKnownLocation().getLongitudeInDegrees()); dbacess.open(); dbacess.storeCapturedSms(setmsg); dbacess.close(); MiscUtils.startPopUpInfo(tContext, 7); } else if (SILENT_ONLY_TAGS[arrayindex].split("#")[1].trim().equals("WAPPUSH")) { /* Wap Push in logcat shows no data only senders number TODO: data is probably in db content://raw/1? */ CapturedSmsData setmsg = new CapturedSmsData(); setmsg.setSenderNumber("unknown");//default setmsg.setSenderMsg("no data");//default int startindex = x - 2; int endindex = x + 3; /* wap push port DestPort 0x0B84 * its usually at this index of +3 in array * * */ if (progress[x + 3].contains("DestPort 0x0B84")) { Log.i(TAG, "WAPPUSH DETECTED"); /* loop thru array to find number */ if (endindex + 3 <= progress.length) { while (startindex < endindex) { //Log.i(TAG,"WAP>>>"+progress[startindex].toString() ); if (progress[startindex] .contains(DETECTION_PHONENUM_SMS_DATA[2].toString())) { try { //Looking for OrigAddr this is where sender number is String number = progress[startindex] .substring(progress[startindex].indexOf("OrigAddr")) .replace(DETECTION_PHONENUM_SMS_DATA[2].toString(), "") .trim(); setmsg.setSenderNumber(number);//default break; } catch (Exception ee) { Log.e(TAG, "Error parsing number"); } } startindex++; } } setmsg.setSmsTimestamp(MiscUtils.getCurrentTimeStamp()); setmsg.setSmsType("WAPPUSH"); setmsg.setCurrent_lac(mAimsicdService.getCellTracker().getMonitorCell().getLAC()); setmsg.setCurrent_cid(mAimsicdService.getCellTracker().getMonitorCell().getCID()); setmsg.setCurrent_nettype( Device.getNetworkTypeName(mAimsicdService.getCell().getNetType())); setmsg.setCurrent_roam_status( mAimsicdService.getCellTracker().getDevice().isRoaming()); //TODO is this the right place to get upto date geo location? setmsg.setCurrent_gps_lat( mAimsicdService.lastKnownLocation().getLatitudeInDegrees()); setmsg.setCurrent_gps_lon( mAimsicdService.lastKnownLocation().getLongitudeInDegrees()); dbacess.open(); dbacess.storeCapturedSms(setmsg); dbacess.close(); MiscUtils.startPopUpInfo(tContext, 8); } // end of if contains("DestPort 0x0B84") } break; } } } //for loop //TextMessageReceiver.setIS_MESSAGE_RECEIVED(false);//reset the boolean to false } } private final ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mAimsicdService = ((AimsicdService.AimscidBinder) service).getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { Log.e(TAG, "Service Disconnected Sms Detection"); mBound = false; } }; }