I know this question asked multiple time, i have googled it too but not found any working answer.
I am developing a android App with sqlite database and want to secure my database.db file from rooted phone, I have applied the check for rooted Device using below code but its not working on some Samsung and Redmi.
public class CheckRooted {
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("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;
}
}
Also suggest me how to protect my database.db file from rooted phones, I can't use any paid services like GreenDao or others.
I'm not very familiar with Android, but this can help you with your database encryption problem.
It is called "SQLCipher".
Check it out. It also has a community edition, which is also allowed to be used with commercial apps.
Further more, if the root checks aren't working on some Samsung and Redmi Devices, make sure they do not use slightly different commands.
Try testing for multiple root commands instead of just one single one.
Related
I'm creating an app that needs to change the data connection.
I found a solution: using su commands, but the problem is that Toast Warning shows every time when I execute the command....
Is possible using these commands without toast warning ?
Or
Is there a way to toggle the data connection enabled with TelephonyManager using reflections? I tried it, but it didn't works.
My code is below:
public static void setMobileDataState(boolean mMobileDataEnabled){
try{
if(mMobileDataEnabled)
Shell.runAsRoot(new String[]{"svc data enable"});
else
Shell.runAsRoot(new String[]{"svc data disable"});
}
catch (Exception ex){
Utilities.log(ex.toString());
}
}
public class Shell {
public static void runAsRoot(String[] mCommands){
try {
Process mProcess = Runtime.getRuntime().exec("su");
DataOutputStream mOS = new DataOutputStream(mProcess.getOutputStream());
for (String mCommand : mCommands) {
mOS.writeBytes(mCommand + "\n");
}
mOS.writeBytes("exit\n");
mOS.flush();
}catch (Exception o){
Utilities.log(o.toString());
}
}
}
I found the solution.....
I did the following:
I rooted my device
I installed my app as system app, it's simple, just copy your apk into /system/priv-app/myApk.apk and set chmod 644 permissions. If you have a doubt, check this post (If i set my android app to a system app, after a factory reset, will it be removed from the phone?).
I just removed the /system/app/SuperSU folder
I did a factory reset on device, and that is it ..... =D
I'm developing an application that is installed on the system partition and I would like to know if it's possible to get a screenshot of the current foreground application from a service. Of course, the application being any third party app.
I'm not interested in security issues or anything related to that matter. I only want to get a snapshot of the current foreground third party app.
Note: I'm aware of the /system/bin/screencap solution but I'm looking for a more elegant alternative that does everything programmatically.
The method that I'm going to describe below will let you to programmatically take screen shots of whatever app it's in the foreground from a background process.
I am assuming that you have a rooted device.
I this case you can use the uiautomator framework to get the job done.
This framework has a been created to automate black box testing of apps on android, but it will suite this purpose as well.
We are going to use the method
takeScreenshot(File storePath, float scale, int quality)
This goes in the service class:
File f = new File(context.getApplicationInfo().dataDir, "test.jar");
//this command will start uiautomator
String cmd = String.format("uiautomator runtest %s -c com.mypacket.Test", f.getAbsoluteFile());
Process p = doCmds(cmd);
if(null != p)
{
p.waitFor();
}
else
{
Log.e(TAG, "starting the test FAILED");
}
private Process doCmds(String cmds)
{
try
{
Process su = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(su.getOutputStream());
os.writeBytes(cmds + "\n");
os.writeBytes("exit\n");
os.flush();
os.close();
return su;
}
catch(Exception e)
{
e.printStackTrace();
Log.e(TAG, "doCmds FAILED");
return null;
}
}
This is the class for uiautomator:
public class Test extends UiAutomatorTestCase
{
public void testDemo()
{
UiDevice dev = UiDevice.getInstance();
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
dev.takeScreenshot(f, 1.0, 100);
}
}
It's best if you create a background thread in which uiautomator will run, that way it will not run onto the ui thread. (the Service runs on the ui thread).
uiatuomator doesn't know about or have a android context.
Once uiautomator gets the control you will be able to call inside it android methods that do not take a context parameter or belong to the context class.
If you need to communicate between uiautomator and the service (or other android components) you can use LocalSocket.
This will allow communication in both ways.
Months have passed since I asked this question but just now had the time to add this feature. The way to do this is simply by calling screencap -p <file_name_absolute_path> and then grabbing the file. Next is the code I used:
private class WorkerTask extends AsyncTask<String, String, File> {
#Override
protected File doInBackground(String... params) {
File screenshotFile = new File(Environment.getExternalStorageDirectory().getPath(), SCREENSHOT_FILE_NAME);
try {
Process screencap = Runtime.getRuntime().exec("screencap -p " + screenshotFile.getAbsolutePath());
screencap.waitFor();
return screenshotFile;
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(File screenshot_file) {
// Do something with the file.
}
}
Remember to add the <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> permission to the manifest. Otherwise screenshot.png will be blank.
This is much simpler than what Goran stated and is what I finally used.
Note: It only worked for me when the app is installed on the system partition.
I'm trying to use the SecureRandom workaround that Google posted in my android application:
http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html
This work around involve writing to (and reading from) /dev/urandom. However, it looks like Samsung has enabled SELinux in such a way that prevents applications from accessing /dev/urandom.
I don't have one of these devices, so it is a little hard for me to test solutions, other than to push out attempts at workarounds on the Android market, but it seems like this is not an error that I can trap with a try catch block. It also appears that File.canRead and canWrite return true. You can see my attempts at workaround in the supportedOnThisDevice method in the following class:
PRNGFixes.java
I'm looking for a reliable way to detect if I am an such a device, and if so, not apply the Google SecureRandom workaround.
This is my way to check if SELinux is in enforce-mode - can be done via any Shell-script, not depending on RootTools:
private static boolean isSELinuxEnforcing() {
try {
CommandCapture command = new CommandCapture(1, "getenforce");
RootTools.getShell(false).add(command).waitForFinish();
boolean isSELinuxEnforcing = command.toString().trim().equalsIgnoreCase("enforcing");
return isSELinuxEnforcing;
} catch (Exception e) {
// handle exception
}
return false;
}
I've heard Samsung is starting to ship devices with the SELinux policy set to Enforce, but I don't know if it's true or not. As far as I know most devices on 4.3 still have it set to permissive.
According to Google, "SELinux reinforcement is invisible to users and developers, and adds robustness to the existing Android security model while maintaining compatibility with existing applications." So you may need to check the system properties or test it through a shell to find out for sure.
If you can get someone to send you their build.prop you may be able to catch it by comparing their ro.build.selinux property via System.getProperty("ro.build.selinux"),
but you'll also want to verify you're able to access it more directly in case it is unreliable or getProperty() for that is broken in future updates.
Root (System user on SELinux) is another option when available, but either way a shell based solution is probably your best bet.
System.getProperty("ro.build.selinux")
Did not work for me on Samsung S4 Android 4.3. So I wrote this
private static final int JELLY_BEAN_MR2 = 18;
public static boolean isSELinuxSupported() {
// Didnt' work
//String selinuxStatus = System.getProperty(PROPERTY_SELINUX_STATUS);
//return selinuxStatus.equals("1") ? true : false;
String selinuxFlag = getSelinuxFlag();
if (!StringUtils.isEmpty(selinuxFlag)) {
return selinuxFlag.equals("1") ? true : false;
} else {
// 4.3 or later ?
if(Build.VERSION.SDK_INT >= JELLY_BEAN_MR2) {
return true;
}
else {
return false;
}
}
}
public static String getSelinuxFlag() {
String selinux = null;
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
selinux = (String) get.invoke(c, "ro.build.selinux");
} catch (Exception ignored) {
}
return selinux;
}
if you have access to the frameworks
import android.os.SELinux;
SELinux.isSELinuxEnforced();
Most devices as as of Jellybean MR2 and onwards will have SELinux enabled on their devices, but if you are working with OEMs or doing platform work this might not necessarily be true.
The method I am using to verify is with the getenforce shell command:
public boolean isSeLinuxEnforcing() {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec("getenforce");
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line);
}
} catch (Exception e) {
Log.e(TAG, "OS does not support getenforce");
// If getenforce is not available to the device, assume the device is not enforcing
e.printStackTrace();
return false;
}
String response = output.toString();
if ("Enforcing".equals(response)) {
return true;
} else if ("Permissive".equals(response)) {
return false;
} else {
Log.e(TAG, "getenforce returned unexpected value, unable to determine selinux!");
// If getenforce is modified on this device, assume the device is not enforcing
return false;
}
}
It appears that most devices are only writing a system property for selinux if they aren't running in enforcing status. You can additionally check the property: ro.boot.selinux to see if the Kernel passed in the permissive parameter on your current build.
UPDATE There are a number of other posts asking how to get a Screenshot in android but none seemed to have a full answer of how to do so. Originally I posted this as a question due to a particular issue I was running into while attempting to open a stream to the Frame Buffer. Now I've swapped over to dumping the Frame Buffer to a file so I've updated my post to show how I got there. For reference (and acknowledgement), I found the command to send the FrameBuffer to a file from this post (unfortunately he didn't provide how he got to that point). I'm just missing how to turn the raw data I pulled from the Frame Buffer into an actual image file.
My intention was to take a full dump of the actual screen on an Android Device. The only way I could find to do so without using the adb bridge was to directly access the Frame Buffer of the system. Obviously this approach will require root privileges on the device and for the app running it! Fortunately for my purposes I have control over how the Device is set up and having the device rooted with root privileges provided to my application is feasible. My testing is currently being done on an old Droid running 2.2.3.
I found my first hints of how to approach it from https://stackoverflow.com/a/6970338/1446554. After a bit more research I found another article that describes how to properly run shell commands as root. They were using it to execute a reboot, I use it to send the current frame buffer to an actual file. My current testing has only gotten as far as doing this via ADB and in a basic Activity (each being provided root). I will be doing further testing from a Service running in the background, updates to come! Here is my entire test activity that can export the current screen to a file:
public class ScreenshotterActivity extends Activity {
public static final String TAG = "ScreenShotter";
private Button _SSButton;
private PullScreenAsyncTask _Puller;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_SSButton = (Button)findViewById(R.id.main_screenshotButton);
_SSButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (_Puller != null)
return;
//TODO: Verify that external storage is available! Could always use internal instead...
_Puller = new PullScreenAsyncTask();
_Puller.execute((Void[])null);
}
});
}
private void runSuShellCommand(String cmd) {
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
StringBuilder sbstdOut = new StringBuilder();
StringBuilder sbstdErr = new StringBuilder();
try { // Run Script
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(cmd);
osw.flush();
osw.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
if (proc != null)
proc.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
sbstdOut.append(readBufferedReader(new InputStreamReader(proc.getInputStream())));
sbstdErr.append(readBufferedReader(new InputStreamReader(proc.getErrorStream())));
}
private String readBufferedReader(InputStreamReader input) {
BufferedReader reader = new BufferedReader(input);
StringBuilder found = new StringBuilder();
String currLine = null;
String sep = System.getProperty("line.separator");
try {
// Read it all in, line by line.
while ((currLine = reader.readLine()) != null) {
found.append(currLine);
found.append(sep);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
class PullScreenAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
File ssDir = new File(Environment.getExternalStorageDirectory(), "/screenshots");
if (ssDir.exists() == false) {
Log.i(TAG, "Screenshot directory doesn't already exist, creating...");
if (ssDir.mkdirs() == false) {
//TODO: We're kinda screwed... what can be done?
Log.w(TAG, "Failed to create directory structure necessary to work with screenshots!");
return null;
}
}
File ss = new File(ssDir, "ss.raw");
if (ss.exists() == true) {
ss.delete();
Log.i(TAG, "Deleted old Screenshot file.");
}
String cmd = "/system/bin/cat /dev/graphics/fb0 > "+ ss.getAbsolutePath();
runSuShellCommand(cmd);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
_Puller = null;
}
}
}
This also requires adding the android.permission.WRITE_EXTERNAL_STORAGE permission to the Manifest. As suggested in this post. Otherwise it runs, doesn't complain, doesn't create the directories nor the file.
Originally I couldn't get usable data from the Frame Buffer due to not understanding how to properly run shell commands. Now that I've swapped to using the streams for executing commands I can use '>' to send the Frame Buffer's current data to an actual file...
Programmatically you can run "adb shell /system/bin/screencap -p /sdcard/img.png" as below :
Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
An easy solution for ICS devices is to use the following from the command line
adb shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png screenshot.png
This'll save the screenshot.png file in the current directory.
Tested on a Samsung Galaxy SII running 4.0.3.
That would be different for different phones. It depends on the underlying graphics format of your device. You can poll what the graphics format is using system calls. If you are only going to run this on devices that you know the graphics format of you can write a converter that turns it into a known format.
You can have a look at the following project: http://code.google.com/p/android-fb2png/
If you look at the source code for fb2png.c you can see that they poll FBIOGET_VSCREENINFO which contains info about how the device stores the screen image in memory. Once you know that, you should be able to convert it into a format you can use.
I hope this helps.
I am developing an App in which I need to lock screen than if user unlocks, it should ask for password...
Help would be really appreciated.
What you basically need is a way to make sure that the user has a password set for their lock screen. There's no clean way of doing this. No formal API. If you're willing to risk a hack, you can try this. I cobbled it together some code I found on this site.
boolean hasPasswordOnLockScreen(){
String sLockPasswordFilename =
android.os.Environment.getDataDirectory().getAbsolutePath() +
"/system/password.key";
try {
// Check if we can read a byte from the file
RandomAccessFile raf = new RandomAccessFile(filename, "r");
raf.readByte();
raf.close();
return true;
} catch (FileNotFoundException fnfe) {
return false;
} catch (IOException ioe) {
return false;
}
}
Note that this is a hack and has the potential to not work in the future is the path and file name of the password file changes.