smart solutions for small devices
[ start | index | login ]
start > J2ME > Sending SMS from MIDlet without user intervention

Sending SMS from MIDlet without user intervention

Created by bjoernQ. Last edited by bjoernQ, 9 years and 178 days ago. Viewed 7,525 times. #6
[diff] [history] [edit] [rdf]
labels
attachments
One thing that many developers dream of is sending an SMS without any user intervention.

Well, that's normally impossible even if the midlet is signed and running in the trusted 3rd party protection domain. But after hacking around for a while I found a way to do this on my 6600. It may work on other Symbian phones but I havent tested it. (If you have success with any other phone please let me know. It's reported to be working on the 6630 and 3230, too. So the chances are very high that this works on all Symbian 7 / 8 phones.)

(This workaround is known to work on Nokia 6600,6630,6260,6680,6681,3230,7760,9500 on the new S60 3rd Edition phones you are out of luck!)

So here is how the magic works.

It's very much like the file reading thing. First we write an unsuspicious midlet that does almost nothing.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
import javax.wireless.messaging.*;

public class TestMIDsMIDlet extends MIDlet implements CommandListener { TextBox t; private Command exitCommand; // The exit command private Command xCommand; // The X command private Display display; // The display for this MIDlet

public TestMIDsMIDlet() { display = Display.getDisplay(this); exitCommand = new Command("Exit", Command.SCREEN, 2); xCommand = new Command("X", Command.SCREEN, 1); }

public void startApp() { t = new TextBox("Hello MIDlet", "Number", 256, 0); t.addCommand(exitCommand); t.addCommand(xCommand); t.setCommandListener(this); display.setCurrent(t); }

public void pauseApp() { }

public void destroyApp(boolean unconditional) { }

public void commandAction(Command c, Displayable s) { if (c == exitCommand) { destroyApp(false); notifyDestroyed(); } if (c == xCommand) { try{ try { String addr = "sms://"+t.getString(); MessageConnection conn = (MessageConnection)Connector.open(addr); TextMessage msg = (TextMessage)conn.newMessage(MessageConnection.TEXT_MESSAGE); msg.setPayloadText("Hello World!"); conn.send(msg); } catch (Exception e) { /// mhhhhh t.setString(e.toString()); e.printStackTrace(); } }catch(Exception ee){ t.setString(ee.toString()); }catch(Error ee){ t.setString(ee.toString()); }

}

} }

As you can see this midlet only sends an SMS to a number entered by the user. Certainly it will ask for permission.

Now we change the line:

String addr = "sms://"+t.getString();

into

String addr = "xsms://"+t.getString();

This certainly don't works since "xsms" is not an registered protocol.

So we add this protocol to the package com.symbian.midp.io.protocol.xsms: (To compile the com.symbian.midp.io.protocol.xsms.Protocol class you will need the "kmidp20.zip" from the Nokia Series_60_MIDP_SDK_2_1 (I guess an other version will do also) in your classpath.)

package com.symbian.midp.io.protocol.xsms;

import com.symbian.gcf.*; import com.symbian.javax.wireless.messaging.SMSConnectionSession; import java.io.IOException; import javax.microedition.io.Connection;

public final class Protocol extends ProtocolBase { public Protocol() { super("sms", "sms"); }

public void ensurePermission(String aName) { // do nothing … hehe }

public Connection openConnection(URI aUri, int aMode, boolean aTimeouts) throws IOException { if(aUri.toString().startsWith("xsms")){ aUri = new URI(aUri.toString().substring(1)); }

com.symbian.gcf.ConnectionSession session = SMSConnectionSession.getSession(); String host = aUri.getHost(); ConnectionEndPoint connection; if(isServerConnection(aUri)) { connection = null; } else { if(aMode == 1) throw new IllegalArgumentException(); connection = new SMSClientConnectionImpl(session, aUri, 2); } connection.open(); return connection; }

protected boolean isServerConnection(URI aUri) { return aUri.getHost().length() == 0; } }

and we need this in that package:

package com.symbian.midp.io.protocol.xsms;
import com.symbian.gcf.*;
import com.symbian.javax.wireless.messaging.*;
import com.symbian.midp.runtime.Security;
import com.symbian.util.BlockingOperation;
import com.symbian.util.NativeError;
import java.io.IOException;
import java.io.InterruptedIOException;
import javax.wireless.messaging.*;

class SMSClientConnectionImpl extends DatagramConnectionEndPoint implements MessageConnection {

SMSClientConnectionImpl(ConnectionSession aSession, URI aUri, int aMode) throws IOException { super(aSession, aUri, aMode); iUri = aUri; iSendPermissionArgs = new String[2]; }

public final Message newMessage(String aType) { String address = null; if(iUri.getHost().length() > 0) address = iUri.toString(); return newMessage(aType, address); }

public final Message newMessage(String aType, String aAddress) { Message msg; if(aType.equals("binary")) msg = new BinaryMessageImpl(aAddress, 0L); else if(aType.equals("text")) msg = new TextMessageImpl(aAddress, 0L); else throw new IllegalArgumentException(); return msg; }

public final int numberOfSegments(Message aMsg) { MessageImpl messageImpl = getMessageImpl(aMsg); int numberOfSegments = 0; synchronized(super.iCloseOperation.getLock()) { if(super.iState != 2) numberOfSegments = messageImpl.populateSmsData(super.iNativePeerHandle, 0); } if(numberOfSegments < 0) numberOfSegments = 0; return numberOfSegments; }

public final void send(Message aMsg) throws IOException, InterruptedIOException { String address = aMsg.getAddress(); if(address == null) throw new IllegalArgumentException("No address"); URI uri = new URI(address); MessageImpl messageImpl = getMessageImpl(aMsg); synchronized(super.iWriteOperation.getLock()) { synchronized(super.iWriteOperation) { synchronized(super.iCloseOperation.getLock()) { ensureOpen(); iSendPermissionArgs[0] = address; int numberOfSegments = messageImpl.populateSmsData(super.iNativePeerHandle, 1); if(numberOfSegments < 0) { if(numberOfSegments == -40) throw new IllegalArgumentException("Message too big"); NativeError.check(numberOfSegments); } iSendPermissionArgs[1] = Integer.toString(numberOfSegments); checkSecurity("javax.wireless.messaging.sms.send", iSendPermissionArgs); int status = _send(super.iNativePeerHandle, EMPTY_BYTE_ARRAY, 0, 0, address); checkError(status); } super.iWriteOperation.waitForCompletion(); } checkError(super.iWriteOperation.getResult()); } }

public void setMessageListener(MessageListener aListener) throws IOException { throw new IOException("Must be Server"); }

public Message receive() throws IOException, InterruptedIOException { throw new IOException("Must be Server"); }

private static MessageImpl getMessageImpl(Message aMessage) { MessageImpl messageImpl = null; try { messageImpl = (MessageImpl)aMessage; } catch(ClassCastException ex) { throw new IllegalArgumentException("Not from newMessage()"); } return messageImpl; }

protected static void checkSecurity(String aPermission, String aPermissionArgs[]) { // Security.ensurePermission(aPermission, aPermission, aPermissionArgs); }

protected static final int MESSAGE_TYPE = 0; private static final String MUST_BE_SERVER_MSG = "Must be Server"; private static final String SEND_PERMISSION = "javax.wireless.messaging.sms.send"; private static final int SEND_PERMISSION_ARGS_TOTAL = 2; private static final int SEND_PERMISSION_ARGS_URI_INDEX = 0; private static final int SEND_PERMISSION_ARGS_SEGMENTS_INDEX = 1; private static final byte EMPTY_BYTE_ARRAY[] = new byte[0]; private URI iUri; private String iSendPermissionArgs[];

}

Compile. Now transfer the resulting jar-file but don't install it! Locate the installed midlet (e.g. "E:/System/MIDlets/[12345678]" and overwrite the contained jar with the newly created one. (Use FExplorer for example to locate the jar in your phone's inbox and copy it as described above.)

Now launch the midlet and .... we're done. We can send an SMS without any notification.

We could even send an SMS to one of the restricted ports. (Since we don't check that anymore but haven't tested it.)

Unfortunately we can't receive SMS silently but sending is cool anyway.

Conclusion:

This is a rude hack and installing it involves a lot of user intervention. Since it could be possible to write a native Symbian SIS installer which does this trick for you it's still no security problem in my eyes. If someone installs a SIS she/he should know this beast can do anything with the phone.

So this isn't a security issue I guess. It's just a nice hack.

no comments | post comment
www.mobile-j.de | Bjoern Quentin