I am currently developing an app that reads out SMS/Emails while driving. Many users wished support for WhatsApp / KakaoTalk.
However, as there is no "official" way to receive their messages, there would be only three options, all requiring root:
The easier way of scanning their database in a given intervall.
Easy to implement.
However not battery efficient
Also the messages are not read out immediately.
An other way would be to run a service with root rights and register a receiver that listens for their push notifications. This has to be done with root, as both packages require a signature based permission for receiving their push notifications.
Harder to implement
Better user experience
Also another thing came to my mind: Would it be possible to manually add permissions to an APK after installing? In that case I could add the c2dm permissions to my package.
This would make things very easy
However, I am a little bit scared of changing my app's permissions, as this is completely against the Android Sandbox principle.
Still, if it would be possible, let me know!
The problem is, how exactly do I run a service with root rights (is it actually possible)? I know how to run shell commands or binaries with root, but I have no idea how to start a part of an APK as root.
Also, would it be possible to integrate a BroadcastReceiver into a binary? I have actually no experience with C/C++, especially in an android environment.
Can you help me with that?
Thanks.
edit: Like I said in the comment, I do not want to use an AccesibilityService, as it does not fit my needs (eg it will give me "2 unread messages" if more then one is unread, also it does not include the full body).
edit2: Just to clarify things: I know how to run commands with root. What I need to know is how to register a Broadcastreceiver, that receives a specific broadcast "normal" receivers don't get, as the Broadcast itself requires a signature based permission I don't have.
This is far from trivial but should work when the apps you want to monitor use sqlite databases or, more generically, write messages to a file when they arrive.
You will indeed need to have root access to the device as this violates the android security system:
Write a native process which runs as a daemon using the NDK and spawn it once after boot as root. You have now 3 major problems to solve:
How to find out if something changed?
This is the easy part. You would need to utilize the Linux inotify interface which should be accessible on every Android phone as the SDK has a FileObserver since API 1, so you are on the safe side here.
Another interesting approach may be to catch the C2DM messages. I have found a NDK class called BroadcastReceiver, so the NDK may be able to catch them. But I personally wouldn't do that as it feels wrong to steal intents. Also you would have to redistribute them or let them travel to real recipient, so I will not describe this in detail here. It may work, but it may be harder and should only be a fallback.
So, when you have solved this, the next problem arises:
How to read the changes in a safe way?
You have a problem, a big one, here. The file doesn't belong to the client, and the client doesn't even have the permission to know where it is (normally). So the monitored app is not aware of the client and will act like the file is exclusively owned only by itself. If they use some plain old textfile to write messages to you have to find out a way to read from it safely as it may be overwritten or extended at any time. But you may be lucky when they use sqlite, according to this it's totally valid to have more than one simultaneous reader, just only one writer. We are in the specs, everything fine again. When you have now read out the new data, more problems to solve:
How to get the new data back into the main app?
You should do only the bare minimum in this C/C++ program because it runs as root. You should also protect your app users from security breaches, so please write the program with this in mind. I have no real idea for this could work really good, but here are some thoughts:
Write the collected data into your own sqlite database (easy in C/C++ and Java),
Write the collected data into a plain file (not recommended at all, pain in the rear),
Send an Intent which contains the new data (maybe not that easy in C/C++, but easy in Java)
Use sockets/pipes/..., just every RPC mechanism you could imagine which is brought to you by Linux (same as the file, don't do it)
As stated in the text above, please be careful when you write this daemon as it is a potential security hazard. It may be hard to do this when you have no knowledge about C/C++ at all, even if you have written simple programs this should be a non trivial task.
On my search through the web I have found the NDK C++ classes I mentioned above. It can be found at Google code. I have neither experience with the NDK nor the C++ wrapper but it may be worth a look when you plan to write this.
Force, I must tell you that an Android Service do not require root access instead some actions(i.e. Access, Read, Write system resources) requires Root Permissions. Every Android Service provided in Android SDK can be run without ROOT ACCESS.
You can make the actions to execute with root permissions with the help of shell commands.
I have created an abstract class to help you with that
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import android.util.Log;
public abstract class RootAccess {
private static final String TAG = "RootAccess";
protected abstract ArrayList<String> runCommandsWithRootAccess();
//Check for Root Access
public static boolean hasRootAccess() {
boolean rootBoolean = false;
Process suProcess;
try {
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream is = new DataInputStream(suProcess.getInputStream());
if (os != null && is != null) {
// Getting current user's UID to check for Root Access
os.writeBytes("id\n");
os.flush();
String outputSTR = is.readLine();
boolean exitSu = false;
if (outputSTR == null) {
rootBoolean = false;
exitSu = false;
Log.d(TAG, "Can't get Root Access or Root Access deneid by user");
} else if (outputSTR.contains("uid=0")) {
//If is contains uid=0, It means Root Access is granted
rootBoolean = true;
exitSu = true;
Log.d(TAG, "Root Access Granted");
} else {
rootBoolean = false;
exitSu = true;
Log.d(TAG, "Root Access Rejected: " + is.readLine());
}
if (exitSu) {
os.writeBytes("exit\n");
os.flush();
}
}
} catch (Exception e) {
rootBoolean = false;
Log.d(TAG, "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}
return rootBoolean;
}
//Execute commands with ROOT Permission
public final boolean execute() {
boolean rootBoolean = false;
try {
ArrayList<String> commands = runCommandsWithRootAccess();
if ( commands != null && commands.size() > 0) {
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
// Execute commands with ROOT Permission
for (String currentCommand : commands) {
os.writeBytes(currentCommand + "\n");
os.flush();
}
os.writeBytes("exit\n");
os.flush();
try {
int suProcessRetval = suProcess.waitFor();
if ( suProcessRetval != 255) {
// Root Access granted
rootBoolean = true;
} else {
// Root Access denied
rootBoolean = false;
}
} catch (Exception ex) {
Log.e(TAG, "Error executing Root Action", ex);
}
}
} catch (IOException ex) {
Log.w(TAG, "Can't get Root Access", ex);
} catch (SecurityException ex) {
Log.w(TAG, "Can't get Root Access", ex);
} catch (Exception ex) {
Log.w(TAG, "Error executing operation", ex);
}
return rootBoolean;
}
}
Extend your class with RootAccess or create an instance of RootAccess class and Override runCommandsWithRootAccess() method.
running something as root is not the right way of solving this.
instead, consider an accessibility service that can watch for new notifications:
AccessibilityEvent
It is not possible to run a Service (or any other application component for that matter) as root, if you are targeting unaltered, non-rooted devices. Allowing that would make all security mechanisms in Android pointless.
It is not possible to alter the permissions of an APK at runtime either. Permissions are always granted or rejected at APK install-time. Please refer to http://developer.android.com/guide/topics/security/security.html for some more info on the subject.
"What I need to know is how to register a Broadcastreceiver, that receives a specific broadcast "normal" receivers don't get, as the Broadcast itself requires a signature based permission I don't have."
You can't. Period. End of story. And thank ghod for that.
Yes, if you use the scary rooted device facilities to have some code run as root, you can in theory do whatever you want. In practice, it may be quite hard to get around this restriction, and the platform is often designed to be that way. You will at the very least need to mess around with the state maintained and/or stored by the package manager, and will likely need to cause the user to reboot the device to get changes you make as root to actually have an impact. And of course you are then messing with deeply internal implementation details of the platform, which means breaking all over the place across different versions of the platform and different builds from different manufacturers.
you can use
pm grant your.permission
as a shell command to grant additional permissions to your app.
I think that command was added quite recently, so if you target older versions you may have to directly alter the 'packages.xml'.
It is possible to execute an app/dex file as root with the app_process command, but I haven't figured out yet how to get a valid context (with this you can use the java.io.File api to access all files, but non static android methods like bindService etc. will fail because you are running without an app context).
Of course you can change the permissions of your applications. If the permissions will be changed, the user will just have to manually update the app, and the new permission will be displayed to the user. But I do not exactly know how changing your app permission will help you in solving this problem.
Another thing I can tell you, is that you can not run a Service or whatever as root, only on rooted devices, and it will not be an easy task to root the devices through your application, and also it won't be something that many user will want.
How are you currently accessing the SMS?
If you have a BroadcastReceiveryou could set the MAX_PRIORITY for your receiver and maybe it will intercept the messages before other applications. This can be done as follows:
<receiver android:name=".SmsReceiver" >
<intent-filter android:priority="100" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
You could also use the SMS Provider, which is not public now but maybe if you query at a given interval this Provider you can check for new messages. You could also have a look at this thread : Android SMS Provider if you have not done this allready.
Related
So in 4.3 there was a concept of System applications. APKs that were placed in /system/app were given system privileges. As of 4.4, there is a new concept of "privileged app". Privileged apps are stored in /system/priv-app directory and seem to be treated differently. If you look in the AOSP Source code, under PackageManagerService, you will see new methods such as
static boolean locationIsPrivileged(File path) {
try {
final String privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app")
.getCanonicalPath();
return path.getCanonicalPath().startsWith(privilegedAppDir);
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
return false;
}
So here is an example of a situation where these differ.
public final void addActivity(PackageParser.Activity a, String type) {
...
if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
intent.setPriority(0);
Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
+ a.className + " with priority > 0, forcing to 0");
}
...
This affects the priority of any activities that are not defined as system applications. This seems to imply you can not add an activity to the package manager whose priority is higher than 0, unless you are a system app. This does not preclude privileged apps as far as I can tell (there is a lot of logic here, I may be wrong.).
My question is what exactly does this imply? If my app is privileged, but not system, what difference will that make? In PackageManagerService you can find various things that differ between system and privileged apps, they are not exactly the same. There should be some kind of ideology behind privileged apps, otherwise they would have just said:
if locationIsPrivileged: app.flags |= FLAG_SYSTEM
and been done with it. This is a new concept, and I think it would be important to know the difference between these kinds of apps for anyone who is doing AOSP development as of 4.4.
So after some digging, it's clear that apps in priv-app are eligible for system permissions, the same way that old apps used to be eligible to claim system permissions by being in system-app. The only official Google documentation I could find on this came in the form of a commit message:
Commit hash: ccbf84f44c9e6a5ed3c08673614826bb237afc54
Some system apps are more system than others
"signatureOrSystem" permissions are no longer available to all apps
residing en the /system partition. Instead, there is a new
/system/priv-app directory, and only apps whose APKs are in that
directory are allowed to use signatureOrSystem permissions without
sharing the platform cert. This will reduce the surface area for
possible exploits of system- bundled applications to try to gain
access to permission-guarded operations.
The ApplicationInfo.FLAG_SYSTEM flag continues to mean what it is says
in the documentation: it indicates that the application apk was
bundled on the /system partition. A new hidden flag FLAG_PRIVILEGED
has been introduced that reflects the actual right to access these
permissions.
Update: As of Android 8.0 priv-app has changed slightly with the addition of Privileged Permission Whitelisting. Beyond just being in priv-app, your app must also be added to a whitelist in order to gain various system permissions. Information on this can be found here: https://source.android.com/devices/tech/config/perms-whitelist
Is there a way to reboot a device with phonegap/cordova? How would I go about doing this? I think it may not be possible on an ipad/iphone but it would be on androids.
First basically it can't be done unless your device is rooted/jailbreaken (depending are we talking about Android or iOS).
Now comes the fun part even if you have rooted/jailbreaken device you will not be able to do that unless you can do some Java/Objective C development.
Basically Phonegap plugin don't exist simply because this functionality is usually not needed unless you are doing something with your phone on a basic level. But if you have enough knowledge you can do it by your self. Phonegap plugin can be created very easy, and you can find more in this tutorial. What you want to do is create a simple plugin that will execute Java/Objective C code when you need it.
Android/Java example :
try {
Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", "reboot" });
proc.waitFor();
} catch (Exception ex) {
Log.i(TAG, "Could not reboot", ex);
}
iOS/Objective C example
Unfortunately I don't have that much experience with this functionality on iOS so you will need to trust this answer.
I needed same functionality, made a plugin based on Gajotres example:
cordova-plugin-reboot
I know this has been asked many times already, with no answers, but I still hope that someone has finally solved the problem.
The problem: I have a non-rooted device running Android 2.3. I need to create a service which:
makes a phone call;
waits until the call is answered;
hangs the phone after the call is answered (with a timeout);
Like many others, I've got stuck with #2. Below is the summary of the solutions ever suggested:
Use PhoneStateListener (most popular): does not work, for an outgoing call it cannot detect what I need.
Use com.android.internal.telephony.CallManager and its methods like registerForPreciseCallStateChanged (e.g., this one): does not work, no phones are registered within it, so the events do not fire.
Use com.android.internal.telephony.PhoneFactory to obtain a com.android.internal.telephony.Phone instance (which is the key to everything): does not work, the factory is not initialized; attempts to initialize it with a makeDefaultPhones call result in a security exception (like here).
Detect the outgoing ringtone (link): the author - Dany Poplawec - states that detecting ringtones may help to solve the problem, but does not provide any details, so I was not able to try this technique.
It looks like everything has been tried already, but there still may be one more trick that will save me :)
I'm trying to get this too and can't find any solution yet.
Looking on the Android Source Code I found these lines in ~/kitchen/jellybean/frameworks/opt/telephony/src/java/com/android/internal/telephony/Call.java
public enum State {
IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;
public boolean isAlive() {
return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING);
}
public boolean isRinging() {
return this == INCOMING || this == WAITING;
}
public boolean isDialing() {
return this == DIALING || this == ALERTING;
}
}
I think one could know if an outgoing call was answered checking the ACTIVE state, but I don't know how to read this value from an app, maybe modifying the framework by adding a specific function for this like:
public boolean isActive() {
return this == ACTIVE;
}
This is just an idea, but I'm not sure how to implement this, because obviously other modifications have to be done for accessing this new function from the application layer.
If you find this viable or know how to do it, help and feedback will be very appreciated.
The solution in your 3rd bullet should be possible in rooted devices, if you follow the instructions in Android INJECT_EVENTS permission
Step by step, it is something like:
Signing the app with the platform certificate. This requires the following steps:
add android:sharedUserId="android.uid.phone" to the manifest-tag of your apkĀ“s manifest.
add android:process="com.android.phone" to the application-tag of the manifest.
you may need to add a few extra permissions to your manifest, and will also need to change the severity for ProtectedPermission in the "Android Lint Preferences" of your project.
get the platform.pk8 + platform.x509.pem from {Android Source}/build/target/product/security (I have used the ones for 4.4.4r1 in https://android.googlesource.com/platform/build/+/android-4.4.4_r1/target/product/security/)
Download keytool-importkeypair from https://github.com/getfatday/keytool-importkeypair
Use this script to obtain the keystore for the platform with command: keytool-importkeypair -k google_certificate.keystore -p android -pk8 platform.pk8 -cert platform.x509.pem -alias platform . I ran it on cygwin, with a minor modification of the script.
Sign the apk using this keystore.
install the application as a system app using adb:
adb root
adb remount
adb push MyApp.apk /system/app
adb shell chmod 644 /systen/app/MyApp.apk
Restart the device.
I have actually tried the solution in the 2nd bullet and it does not work for me either (on a Galaxy S5 running Kitkat).
The solution in the 3rd bullet item does work quite OK. Regardless of the package name, the app runs as com.android.phone , so you need to attach to that process if you want to debug the app.
I'm writing an application that must not run on rooted devices. I want to store some secure data and which is possible only on non-rooted devices as nobody can access files in /data/data/package-name.
Does anyone know:
1) Is it possible to prevent the installation of an application on rooted devices? I read something about the "copy-protection mechanism" of Android Market. This feature seems to be outdated and replaced by the licensing feature. However, licensing is only possible for paid application and mine is free...
2) Is it possible to check programmatically whether a device is rooted or not? If it would be possible to do so I could simply stop the application if the device is rooted.
Any help regarding this topic is appreciated!
Execute
Runtime.getRuntime().exec("su");
and check the result code.
In other words, if you can exec su, then you have root access. it doesn't matter if the user allows or denies it, you have your answer.
I think your approach is a bit flawed. First of all, the user can first install your application and data, then "root" the device (even if rooting wipes the data, one can make the backup first). Next, the general rule is that whatever is in user's hands is not yours anymore. The hacker will find a way to get to your data sooner or later.
If you care about secure data, don't put it to device. As Android is net-centric device (yes, I know, that's subjective, but it was initially developed and positioned as such), accessing the data online is not uncommon.
What I would say is to run su and then check the output. If the user allows your app to have root, then use root to uninstall your own application (one way might be to place a script into init.d and then force a reboot).
If the user DOES NOT allow your app to run as root, then:
They DENIED your app permissions.
They are not rooted.
Now, denying permissions (and rooted) means that they have some sort of SUPERUSER management app, and that's where this next part comes in.
I would then proceed to use PackageManager to retrieve a list of all packages and then check them against the handful SuperUser management apps available, namely the ones by Koush, ChainsDD, and Chainfire
The relevant package names are:
com.noshufou.android.su
eu.chainfire.supersu
com.koushikdutta.superuser
Use those methods which will help you check for root
public static boolean findBinary(String binaryName) {
boolean found = false;
if (!found) {
String[] places = { "/sbin/", "/system/bin/", "/system/xbin/",
"/data/local/xbin/", "/data/local/bin/",
"/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/" };
for (String where : places) {
if (new File(where + binaryName).exists()) {
found = true;
break;
}
}
}
return found;
}
private static boolean isRooted() {
return findBinary("su");
}
Now try to check whether the device is rooted.
if (isRooted() == true){
//Do something to prevent run this app on the device
}
else{
//Do nothing and run app normally
}
For example you can force stop the app if the device is rooted
If you are trying to protect data for the user, it's their business to worry about other apps.
If you are trying to protect data from the user, what business do you have putting it on their device?
To answer your question, they are in control of the machine so expect them to be able to trap any call to an API checking 'Is this rooted?' and lie to you. Instead, encrypt the data on the client with a key known to the client, but make it non-obvious where and how you are doing it. Generally make things annoying for whoever is looking.
Enjoy the ensuing game of whack-a-mole. Every time someone cracks into it, you'll make a better fix, they'll make a better crack, and all along the way you will be raising the barrier for cracking it.
Don't fight against freedom - why should you turn away customers with free devices anyway? - instead, if you want a particular outcome, make it so Bother To Get Data > Value Of Getting Data. Then it won't happen. If you truly must have fool-proof security, keep the data server-side.
I believe that one of the 'drawbacks' of the traditional copy protection was that it did not allow the application to be installed on rooted devices, but it also has its own share of problems and will be deprecated soon.
As for client-side checks, you simply cannot rely on a programmatic approach to detect if you're running on a rooted device or not -- anything that is in client-side code can and will be hacked and removed. You'd be surprised at how easy it is to modify even Proguard-obfuscated code. At best, you force the hacker to spend a few hours or days to edit the code and recompile. This is security through obscurity, and not a viable protection mechanism.
1) no. how would you deny installation? why would a rooted device deny installation of something the user wants to install on the fs? being the whole point of rooting that you can make the device do basically whatever.
2) no. not for your purposes. you can check if you can gain root for your application through the usual methods. so you can make a check for a positive but you cannot prove programmatically that it is not rooted, from within your app.
also, what you are asking if you can make perfect copy protection drm system - you might also be missing the point that the user can alter your application, removing your root check. if you have a checksum/crc check of some kind, the user can fake the result of that as well.
When you want to change the mobile system date or time in your application, how do you go about doing it?
You cannot on a normal off the shelf handset, because it's not possible to gain the SET_TIME permission. This permission has the protectionLevel of signatureOrSystem, so there's no way for a market app to change global system time (but perhaps with black vodoo magic I do not know yet).
You cannot use other approaches because this is prevented on a Linux level, (see the long answer below) - this is why all trials using terminals and SysExecs gonna fail.
If you CAN gain the permission either because you rooted your phone or built and signed your own platform image, read on.
Short Answer
It's possible and has been done. You need android.permission.SET_TIME. Afterward use the AlarmManager via Context.getSystemService(Context.ALARM_SERVICE) and its method setTime().
Snippet for setting the time to 2010/1/1 12:00:00 from an Activity or Service:
Calendar c = Calendar.getInstance();
c.set(2010, 1, 1, 12, 00, 00);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.setTime(c.getTimeInMillis());
If you which to change the timezone, the approach should be very similar (see android.permission.SET_TIME_ZONE and setTimeZone)
Long Answer
As it has been pointed out in several threads, only the system user can change the system time. This is only half of the story. SystemClock.setCurrentTimeMillis() directly writes to /dev/alarm which is a device file owned by system lacking world writeable rights. So in other words only processes running as system may use the SystemClock approach. For this way android permissions do not matter, there's no entity involved which checks proper permissions.
This is the way the internal preinstalled Settings App works. It just runs under the system user account.
For all the other kids in town there's the alarm manager. It's a system service running in the system_server process under the - guess what - system user account. It exposes the mentioned setTime method but enforces the SET_TIME permission and in in turn just calls SystemClock.setCurrentTimeMillis internally (which succeeds because of the user the alarm manager is running as).
Cheers
According to this thread, user apps cannot set the time, regardless of the permissions we give it. Instead, the best approach is to make the user set the time manually. We will use:
startActivity(new Intent(android.provider.Settings.ACTION_DATE_SETTINGS));
Unfortunately, there is no way to link them directly to the time setting (which would save them one more click). By making use of ellapsedRealtime, we can ensure that the user sets the time correctly.
A solution for rooted devices could be execute the commands
su
date -s YYYYMMDD.HHMMSS
You can do this by code with the following method:
private void changeSystemTime(String year,String month,String day,String hour,String minute,String second){
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
String command = "date -s "+year+month+day+"."+hour+minute+second+"\n";
Log.e("command",command);
os.writeBytes(command);
os.flush();
os.writeBytes("exit\n");
os.flush();
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Just call the previous method like this:
changeSystemTime("2015","04","06","13","09","30");
I didn't see this one on the list anywhere but it works for me. My device is rooted and I have superuser installed, but if superuser works on non-rooted devices, this might work. I used an AsyncTask and called the following:
protected String doInBackground(String... params){
Runtime.getRuntime().exec("su && date -s " + params[0]);}
In our application case, the dirty workaround was:
When the user is connected to Internet, we get the Internet Time (NTP server) and compare the difference (-) of the internal device time (registederOffsetFromInternetTime). We save it on the config record file of the user.
We use the time of the devide + registederOffsetFromInternetTime to consider the correct updated time for OUR application.
All GETHOUR processes check the difference between the actual time with the time of the last comparission (with the Internet time). If the time over 10 minutes, do a new comparission to update registederOffsetFromInternetTime and mantain accuracy.
If the user uses the App without Internet, we can only use the registederOffsetFromInternetTime stored as reference, and use it. Just if the user changes the hour in local device when offline and use the app, the app will consider incorrect times. But when the user comes back to internet access we warn he about the clock changed , asking to resynchronize all or desconsider updates did offline with the incorrect hour.
thanks penquin. In quickshortcutmaker I catch name of date/time seting activity exactly. so to start system time setting:
Intent intent=new Intent();
intent.setComponent(new ComponentName("com.android.settings",
"com.android.settings.DateTimeSettingsSetupWizard"));
startActivity(intent);
`