This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Determine if running on a rooted device
How do you determine (programmatically) if an Android device is: rooted Running a cracked copy of your software or rom.
I have some sensitive information in my database, and I would like to encrypt it when the phone is rooted aka the user has access to the database. How do I detect that?
Rooting detection is a cat and mouse game and it is hard to make rooting detection that will work on all devices for all cases.
See Android Root Beer https://github.com/scottyab/rootbeer for advanced root detection which also uses JNI and native CPP code compiled into .so native library.
If you need some simple and basic rooting detection check the code below:
/**
* Checks if the device is rooted.
*
* #return <code>true</code> if the device is rooted, <code>false</code> otherwise.
*/
public static boolean isRooted() {
// get from build info
String buildTags = android.os.Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
return true;
}
// check if /system/app/Superuser.apk is present
try {
File file = new File("/system/app/Superuser.apk");
if (file.exists()) {
return true;
}
} catch (Exception e1) {
// ignore
}
// try executing commands
return canExecuteCommand("/system/xbin/which su")
|| canExecuteCommand("/system/bin/which su") || canExecuteCommand("which su");
}
// executes a command on the system
private static boolean canExecuteCommand(String command) {
boolean executedSuccesfully;
try {
Runtime.getRuntime().exec(command);
executedSuccesfully = true;
} catch (Exception e) {
executedSuccesfully = false;
}
return executedSuccesfully;
}
Probably not always correct. Tested on ~10 devices in 2014.
If the information is sensitive you should probably just encrypt it for all users. Otherwise a user could install your app unrooted, then root and read your database once the data's been written.
The official licensing guide says:
A limitation of the legacy
copy-protection mechanism on Android
Market is that applications using it
can be installed only on compatible
devices that provide a secure internal
storage environment. For example, a
copy-protected application cannot be
downloaded from Market to a device
that provides root access, and the
application cannot be installed to a
device's SD card.
It seems that you would benefit from using that legacy cop-protection to prevent your application from being installed on rooted devices.
You might release a separate version that can be installed on rooted devices with an encrypted database.
Related
How to run Android App in Kiosk Mode, keep Safe Mode disabled and prevent the device from Hard Reset?
I have following 3 requirements for my app:
Show only specific apps to school students in the normal mode of the device. This can be possible by disabling default launcher and enabling kiosk launcher.
Disable or set the password to safe mode to avoid usage of system apps or built-in apps (youtube, video player, music app, etc.).
Restrict hard reset of a device by disabling long press of hard keys (power button, volume buttons) of a device.
I have interpreted these requirements and came up with below detailed understanding.
We can redesign the school students app to make itself a launcher app which will run in kiosk mode. That implies we will not require any other (trial version) launcher apps.
We can disable safe mode access to the system or third-party apps via the AppLock app or similar other apps. It will work only up to Android Marshmallow 6.0. But there is an Android imposed limitation – it won’t work on Nougat / Oreo devices. Alternatively, we tried to handle the power button key press for preventing the device from going into safe mode. But Android doesn't allow the access or listen to power key press from our app as per this link and various other.
IMPORTANT NOTE FOR ANDROID 7.0 (NOUGAT) AND 8.0 (OREO) - link here
As per MMGuardian App, at this time, Safe Mode Lock cannot be enabled for phones running on Android 7.0 or 8.0. If an older phone for which Safe Mode Lock was previously enabled is updated to these versions of Android, the Safe Mode Lock function will become disabled.
We cannot prevent any device from hard reset as it is mostly done after the phone is switched off leaving the apps with no control. But there is an expensive alternative. We can use a COSU device and design a custom firmware. More details about COSU are available on below links.
https://developer.android.com/work/cosu.html
https://developers.google.com/android/work/requirements/cosu
Can someone help me to add more thoughts to it for me to understand this situation in more details?
Am I going in the right direction? or Have I detailed it correctly?
100% Kiosk Mode impossible.
Restrict hard reset : The hard reset option is a part of bootloader, so it's hard to prevent device getting factory reset,
I had solution, but only works if the device rooted
Restrict hard reset : copy your apk file to system/app, when device got restored Android will automatically reinstall all apps from system/app folder
Disable System APP : to disable system apps or any apps run a shell command
pm disable <package name>
Interpret Volume Keys : To run this you don't need root access, Use this code in your Activity Class
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
// TODO Auto-generated method stub
if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN))
{
// Do what ever you want
}
if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP))
{
// Do what ever you want
}
return true;
}
Bonus disable navigation bar and status bar
To Hide
private void hideNavigationBar(){
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("pm disable com.android.systemui\n");
os.flush();
try {
Process process = null;
process = Runtime.getRuntime().exec("su");
DataOutputStream osReboot = new DataOutputStream(process.getOutputStream());
osReboot.writeBytes("reboot\n");
osReboot.flush();
process.waitFor();
}
catch (IOException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}catch (IOException e) {
e.printStackTrace();
}
}
Restore back to normal
private void showNavigationBar(){
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("pm enable com.android.systemui\n");
os.flush();
os.writeBytes("reboot\n");
os.flush();
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Note : Device will reboot after running shell commands
Your playing with root, so you and your own, If any doubt please command before start coding
Take a look at Android Management API, seems more can't be done without custom device firmware.
Can you design and then deploy your app as DeviceOwner? This gives you the greatest possibilities on the device, but deployment can be painful depending on the context: not suitable for a public release, but doable if you can manage the devices fleet.
N.B.: This question about the serial number of the physical SD card, not the UUID of the mounted volume. These are two independent pieces of data.
In some versions of Android, and other variants of Linux, it's possible to get the serial number of a mounted SD card, e.g. by reading the contents of /sys/class/mmc_host/mmc0/mmc0:0001/serial or /sys/block/mmcblk0/device/serial (specific numbers may vary). In my testing this has worked pretty reliably, as long as the SD card is inserted in a built-in SD card slot (not mounted via USB adapter).
But as of Android 7.0 Nougat, the OS is said to be blocking access to this information, at least on some devices. I tested this by running a test app on a new Alcatel A30 GSM (Android 7.0), and in fact the above approach fails with a permission error:
java.io.FileNotFoundException: /sys/block/mmcblk0/device/serial (Permission denied)
at java.io.FileInputStream.open(Native Method)
For future reference, we (testing from an adb shell) have permissions to ls -ld the following:
/sys/class/mmc_host but not /sys/class/mmc_host/mmc0
/sys/block but not /sys/block/mmcblk0
Since the above approach no longer works,
Is there another way to obtain the serial number of a mounted SD card in Android 7.0 or later?
Failing that, is there any documentation or other statement from Google on plans for providing or not providing this function? I haven't found anything in the Android issue tracker, but maybe I'm not searching right.
To make sure the question is clear, I'm talking about what an ordinary (non-system) app running on a non-rooted device can do, with any permissions that an app can normally request and receive.
FYI, the /sbin directory doesn't seem to be readable, so commands like /sbin/udevadm aren't an option.
In Android N access to /sys nad /proc was significantly restricted, this was done to provide stricter sandboxes where applications run. This is explained in https://issuetracker.google.com/issues/37091475 as intentional. Actually its not said that all the data in /sys is not accessible, and Google is open to allow access to other files from this location:
If there are specific files in /sys you believe should be available to applications, but are not, please file a new bug where the request can be evaluated. For instance, /sys/devices/system/cpu is available to all processes, so it's inaccurate to say all of /sys is restricted.
I have a bad feeling that google is making changes similar to Apple where it is not allowed to gain hardware id-s. If that is not resolved then the solution is to use google account IDs instead. But I am aware it is not always possible, and will require major changes in business logic (licensing etc.).
Hopefully your bug report will be considered positively.
another related SO I found : File system changes in Android Nougat
Use StorageVolume.getUuid() on StorageVolume which you get from StorageManager.
The value is volume ID assigned during formatting of the card, and its length/format differs depending on file system type. For FAT32 it is XXXX-XXXX, for NTFS it's longer hex string, for Internal mass storage it returns null.
public String getSDCARDiD()
{
String sd_cid = null;
try {
File file = new File("/sys/block/mmcblk1");
String memBlk;
if (file.exists() && file.isDirectory()) {
memBlk = "mmcblk1";
} else {
//System.out.println("not a directory");
memBlk = "mmcblk0";
}
Process cmd = Runtime.getRuntime().exec("cat /sys/block/"+memBlk+"/device/cid");
BufferedReader br = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
sd_cid = br.readLine();
//System.out.println(sd_cid);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sd_cid;
}
try this: reference original link :Android get id of SD Card programmatically
adb shell cat /sys/class/mmc_host/mmc1/mmc1:*/cid
You can also try
sudo hwinfo --disk
to get information on your disks, including SD Cards.
Also try
sudo hdparm -I /dev/sdb | more
As an FYI to those looking into UUID or volume serial numbers of FAT type volumes under Android: Some Fujifilm cameras, including the X-T30 (Firmware 1.10) do not write a volume serial number into the FAT volume when formatting.
Under Windows, CHKDSK displays no volume serial number at all.
On Android, calling StorageVolume.getUuid() returns "0000-0000".
This is all fine and dandy, until you on Android mount two Fujifilm-formatted cards via a hub. Then there seems to be identity collision, where the Android OS prompts the user to format one of the cards. Separately they are accessible.
I'm guessing there are two combined problems here:
1) Fujifilm is not writing a volume serial number when formatting, and
2) Android uses the volume serial number as part of the mount point path, leading to collision.
Fujifilm and Google might both want to pay attention to this issue.
EDIT: Card formatted in a Nikon D810 also has the same problem, no Volume Serial Number.
My app (S Educate) requires me to get the DeviceId (for Analytics/Recommendations) and hence I added the permission, READ_PHONE_STATE and although the documentation is harmless, when the user installs, the app permissions window shows, "Phone Calls - Monitor, record, and process phone calls" which obviously prevents user from installing and users have informed that they are not installing simply because of this permission.
Screenshot (click for larger variant)
Here are my options:
I state clearly in my app description that I require this permission to get DeviceId and not to monitor/record phone calls and hope the users believe me and install the app
I find an alternate way to get DeviceId - which to my knowledge is not available without using the above mentioned permission
Please advise how do I get around this permission issue.
Please use an app-generated UUID. This will allow you to distinguish one app installation from another, without violating user privacy.
There are different ways you can retrieve Unique device id in Android.
IMEI (for this, You will need to add READ_PHONE_STATE Permission in Manifest)
Pseudo Unique ID (no need to add READ_PHONE_STATE permission)
Android ID
MAC Address
Check out the details below.
http://www.pocketmagic.net/2011/02/android-unique-device-id/#.UsMCatIW2vE
From Android Developers Blog
In the past, when every Android device was a phone, things were simpler: TelephonyManager.getDeviceId() is required to return (depending on the network technology) the IMEI, MEID, or ESN of the phone, which is unique to that piece of hardware.
Mac Address
It may be possible to retrieve a Mac address from a device’s WiFi or
Bluetooth hardware. We do not recommend using this as a unique
identifier. To start with, not all devices have WiFi. Also, if the
WiFi is not turned on, the hardware may not report the Mac address.
Serial Number
Since Android 2.3 (“Gingerbread”) this is available via
android.os.Build.SERIAL. Devices without telephony are required to
report a unique device ID here; some phones may do so also.
ANDROID_ID
More specifically, Settings.Secure.ANDROID_ID. This is a 64-bit
quantity that is generated and stored when the device first boots. It
is reset when the device is wiped.
ANDROID_ID seems a good choice for a unique device identifier. There
are downsides: First, it is not 100% reliable on releases of Android
prior to 2.2 (“Froyo”). Also, there has been at least one
widely-observed bug in a popular handset from a major manufacturer,
where every instance has the same ANDROID_ID.
Solution is given on android blog. Use Installation.id(context).
public class Installation {
private static String sID = null;
private static final String INSTALLATION = "INSTALLATION";
public synchronized static String id(Context context) {
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists())
writeInstallationFile(installation);
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
private static String readInstallationFile(File installation) throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeInstallationFile(File installation) throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
out.write(id.getBytes());
out.close();
}
}
I expect that my android application is allowed to install only on real device, and android-emulator can't.How can I limit my android application installed on real device only ?
Thanks for any replies.
There's one way how to handle it. Just check device id (IMEI code). For emulator it's always null, so you can define either someone tries to launch it in real device or in emulator.
TelephonyManager tm=(TelephonyManager )activity.getSystemService(Context.TELEPHONY_SERVICE);
if(tm==null || !this.hasTelephony())
{
Log.v(TAG, "Can't get telephony service. Forcing shut down!");
return false;
}
String deviceId=tm.getDeviceId();
if(deviceId==null || deviceId.length() < 2)
{
Log.v(TAG, "Looks like emulator - bail out!");
Toast.makeText(activity, "This special version not intended to run in this device!", 5000).show();
return false;
}
Unfortunately you cannot stop people from installing in emulator, but if you have Google Licensing installed it will make sure that it does not run on unlicensed devices.
I am writing an application to access the many of the system device nodes. To open the device nodes, I wrote native methods, When I am trying to execute it, I am unable to open the device node as there is no root permissions to my application. Could any one please tell give root permission to my android application. device details: android 2.0.1 - motorola milestone.
rtc_fd=open("/dev/rtc",0777);
if(rtc_fd == -1) {
__android_log_write(ANDROID_LOG_ERROR, "","UNABLE TO OPEN THE DEVICE....");
strcpy(result_string,"Fail: /dev/rtc open error\n");
__android_log_write(ANDROID_LOG_ERROR, ""," DEVICE...ERROR. ");
return result_string;
}
ret = ioctl(rtc_fd, RTC_RD_TIME, &rtc_tm);
if (ret == -1) {
strcpy(result_string,"Fail: rtc ioctl RTC_RD_TIME error\r\n");
return result_string;
}
It is always saying UNABLE TO OPEN DEVICE, could any one please suggest a solution to open a device node.
First and foremost, you will obviously need a rooted phone for any of this to work.
That being said, Android does not allow for a user-application to gain super-user rights, even on a rooted phone. Instead, it allows you to launch a new process with super-user rights.
The easiest method for running things as super-user is to create a virtual terminal, as follows:
Process proc = Runtime.getRuntime().exec("su");
DataOutputStream standard_in = new DataOutputStream(proc.getOutputStream());
DataInputStream standard_out = new DataInputStream(proc.getInputStream());
Using the input and output streams you now effectively have console access as root, which you can use to run typical command-line commands, or to run the process that accesses your device for you.