Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open ServiceMode menu programmatically in Android

How to open the Android ServiceMode menu programmatically on Samsung Phones ?
Manually, I can do it by dialing the ussd code *#0011#.

enter image description here

like image 835
Pedro Lobito Avatar asked Nov 27 '13 16:11

Pedro Lobito


2 Answers

This was a challenge and I've been a few hours looking for a solution. But i am afraid i don't have good news.

1. First attemp, Intent.ACTION_DIAL

Is true that in the beginning, it was possible to directly call USSD codes from an app (using the intent Intent.ACTION_DIAL), and even from a website, just using the "tel:" schema. That opens the dialer, an puts the desired number. As when you put the last #, the code get send automatically, it was almost transparent to the user, whose interaction wasn't required. But that was actually considered a vulnerability of the system, since somebody could write malicious software, or even more, insert malicious code in a website that could even wipe your phone or block the sim card. You can read about this, for example in this link As of September 2012, it seems that Samsung finally fixed that vulnerability so for instance your S3 is not capable of that. At this point it will be hard to find any device still vulnerable.

2. Second Attempt, the workaround

Ok everything in Android is an app, even the phone itself is an app. So, why couldn't we try to replicate its code? And actually, what happens when the user manually sends a ussd? There was too possible answers:

  • The phone sends the code to the provider and waits for a response, or
  • The phone does something locally

Easy to test: I put my phone in flight mode, so if it has to send a code, hopefully it wont be able to. It was as i expected: i dialed the code, and the ServiceMode screen appeared! And it was empty, so we can say that the dialer opens a system application, and this application calls the provider. Its easy to find out which is this application. In Samsung devices, at least in S4, its name is ServiceMode. You can find it at Settings > Application manager > All. So we can try to find out how it is launched more by means of one of this:

2.1. Reading the phone application code

I tried, but it was pretty confusing at the beginning, so i went to option 2

2.2. Checking the Service mode app

I opened ES file explorer > app manager. connected the phone, and in phone/backups/apps i had the servicestatus apk. a few minutes or inverse engineering after, i had the manifest file, as revealing as it uses to be. There i could see a bunch of activities, and also a few broadcast receivers. I didn't know what i was more afraid of.

2.2.1 Lets try with the activities.

Since we know we can open an specific application from another, i will try to write a simple app, that open one of this activities. This is as simple as:

Intent i= new Intent(Intent.Action_MAIN);
i.setClass(  "package name",  "class name");
startActivity(i);

Since this app is not meant to be open from a launcher icon, it has not an activity with an intent filter that let us know that it is the main activity. So i have to try at least a few of them. But anyways, i saw something i didn't like. I will tell you later.

I tried, but, as i expected, i cannot open that activities. I get an activity not found exception. So, lets try with a receiver. At least this will be fun.

2.2.2 Lets try with the receivers.

There is a few, but specially i liked one with this intent-filter:

 <intent-filter>
                <action android:name="android.provider.Telephony.SECRET_CODE" />
  ... 

Looks good. I went yo Telephony.java, and there i could see this:

   /**
     * Broadcast Action: A "secret code" has been entered in the dialer. Secret codes are
     * of the form *#*#<code>#*#*. The intent will have the data URI:</p>
     *
     * <p><code>android_secret_code://&lt;code&gt;</code></p>
     */
    public static final String SECRET_CODE_ACTION =
            "android.provider.Telephony.SECRET_CODE";

Looks great, its an specific intent, probably the schema we need is not "tel:" but "android_secret_code://" and probably the codes has to be in a different internal format. I tried, more or less just for fun, since i knew that there is the same problem i saw in the activities, and is this:

 <permission android:name="com.sec.android.app.servicemodeapp.permission.KEYSTRING" android:protectionLevel="signatureOrSystem" />

The app declares this permission, and every component uses it. so, or you know how to declare and set a signature, or you are a system app. Otherwise you cannot interact with this app at all.

Of course you couldn't even think about creating your own servicemode app, since you wouldn't perform that kind of communication with the provider without being a system app (since you have to pass through some firmware apps that will say a sad "who do you think you are")

Conclusions

There is nothing we can do at his point, at least with a Samsung phone, and we can think every other phone will be the same.

Alternatives

Well, actually none really good. But lets see:

Alternative 1. Find another kind of ussd code

We know that there is 2 kind of USSD. The ones that when you dial the last #, the action is automatically triggered, and the other, which require that you press the call button.

If you try with a third-party dialer, you can see that

  • whe you dial the first type kind of code, nothing is triggered at all (only the firmware dialer can trigger them)
  • you can use the other kind (type code + press call). I suppose this means that this kind of codes are less risky, since doesn't change anything in the device, so they are allowed.
  • of course, if you type a code of the first type and press call, you get an error because that code doesn't work that way.

So, if a third-party can send that type of codes, every app could. So If you could try to find an alternative ussd code, of that type that are triggered after the usser press the call button, you could achieve your what you need. In that case, you should use an Intent.ACTION_CALL intent

//if you use the ACTION_DIAL intent, it open the dialer and put the given number in it. //meanwhile, if we use the ACTION_CALL, the app will directly call.

Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+ "*" + Uri.encode("#") + "0011" + Uri.encode("#"))); //here you woud put your alternative code
startActivity(intent);

Also you would need to declare this permission in your manifest

<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>

Probably you could find an alternative code to do this, since i ve seen a few in the internet, but at this point no one worked for me. You can give it a try

Alternative 2. Wait for an official api to come up

In the android project page at coogle code, there is a request to Add USSD API support. It has many subscribers, but it is quite old (more than 5 years), i'm afraid that's not really good. Anyways, that could happen, probably the android tem will consider to prepare an api so an app could declare some permissions, and make requests of some kind of codes. But, I know, this can be waiting forever.

So, what to say. Would luck looking for a solution, or for an alternative to your app. I'm sorry my research wasn't more fruitful :(

like image 91
Carlos Robles Avatar answered Nov 06 '22 02:11

Carlos Robles


I think that I got a solution.

By running the bellow code on a rooted phone you should open the Samsung ServiceModeApp (the service mode shown in this post). Programmatically, I think that one can run anything if logged as root. However, there are issues to face such as:

  1. Rooted phone. If you're creating apps for publishing, consider that less than 2% of all Android devices are rooted;
  2. Very specific application. This bellow code runs in a specific version of Samsung device (I've run it in a Galaxy SIII GT-9300). It may not run in other models, and surelly will not in other brands. You must re-implement each case.

Repare that 0011 is the argument that you must pass to the activity. Code follows:

PackageManager packageManager = this.getPackageManager();
if (packageManager != null) {
    measure_intent = new Intent(Intent.ACTION_MAIN).
            addCategory(Intent.CATEGORY_LAUNCHER).setComponent(new ComponentName(
                    "com.sec.android.app.servicemodeapp",
                    "com.sec.android.app.servicemodeapp.ServiceModeApp"));
    measure_intent.putExtra("keyString", "0011");
    ResolveInfo resolved = packageManager.resolveActivity(
            measure_intent, PackageManager.MATCH_DEFAULT_ONLY);
    if (resolved != null) {
        startActivity(measure_intent);
        return;
    } else {
        Toast.makeText(this, "version not implemented", Toast.LENGTH_LONG).show();
    }
}

I've reached to it by pulling ServiceModeApp from Android's /system/app directory, then decompiling the .apk file, and then analyzing its code. Hope it helps! :)

like image 31
Marcelo Avatar answered Nov 06 '22 02:11

Marcelo