I'm trying to create a ServerSocket on a port below 1024.
Obviously, this is restricted to root access only.
But I'm struggling on getting the right permissions for my app.
I'm using this code, for example, to test if I have root access (or trigger the dialog)
But it still doesn't let me ServerSocket work.
AFAIK, the process that is created with the SU command has the root access, not my app. How do I get root access into my own process?
public stat
ic boolean getRoot() {
try {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("echo \"Do I have root?\" >/system/sd/temporary.txt\n");
os.writeBytes("exit\n");
os.flush();
try {
p.waitFor();
if (p.exitValue() != 255) {
return true;
} else {
return false;
}
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Afaik you cannot open a port below 1024 under *nix systems if you're not root...
Related
I have a custom device android 4.3. Problem occurs with some commands, one of an example:
su -c 'pm enable com.android.systemui'
When I run this command over adb it works. However when I run the code programatically using this library it just does not work, no error is shown as well.
Interesting observations:
Shell.SU.available() : false
Shell.SU.isSELinuxEnforcing() : false
Ok so device is rooted. Any reason why you are trying to do that command using that library?
What I am trying to say is why can't you just run the shell command yourself?
runRootCommand method:
static boolean runRootCommand(String command) {
boolean status = true;
DataOutputStream os = null;
try {
Process process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
} catch (IOException | InterruptedException e) {
Log.e(TAG, e.toString());
status = false;
} finally {
try {
if (os != null)
os.close();
} catch (IOException e) {
Log.e(TAG, e.toString());
status = false;
}
}
return status;
}
And then call that method like this:
boolean success = runRootCommand("pm enable com.android.systemui");
if(success) {
// command was successful
} else {
// command was NOT successful
}
This will run the command as "su" (superuser).
Hope this helps.
I'm trying to ping a site to detect wether I have internet or not in my android app. On many devices this does work well, but today, with a new devices, it allways returns that I have no internet.
This is the code:
static public boolean isInternetAvailable(String url){
Runtime runtime = Runtime.getRuntime();
try {
String command = "/system/bin/ping -c 1 " + url;
Process ipProcess = runtime.exec(command);
int exitValue = ipProcess.waitFor();
return (exitValue == 0);
} catch (IOException e) { e.printStackTrace(); }
catch (InterruptedException e) { e.printStackTrace(); }
return false;
}
Even though the server is online, and I can ping it from various other devices, on the new device it allways returns false. Could it be possible that the ping command is blocked for some reason?
The new device is a Samsung GT-19305 with Android version 4.3.
You could try this:
Process process = new ProcessBuilder()
.command("/system/bin/ping", "android.com")
.redirectErrorStream(true)
.start();
try {
InputStream in = process.getInputStream();
OutputStream out = process.getOutputStream();
readStream(in);
finally {
process.destroy();
}
}
I want to run tap cmd like over 100 times and by using code below it will call su everytime and delay taps. So is it possible to request su when app first starts then run many commands fast? thanks!
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
String cmd = "/system/bin/input tap 350 370\n";
os.writeBytes(cmd);
os.writeBytes("exit\n");
os.flush();
os.close();
process.waitFor();
} catch (IOException e) {
// TODO Auto-generated catch block
}
This is the solution:
try {
Process process = Runtime.getRuntime().exec("su");
OutputStream out = process.getOutputStream();
String cmd = "input tap 350 370";
out.write(cmd.getBytes());
out.flush();
out.close();
process.waitFor();
} catch (IOException e) {
} catch (InterruptedException e) {
}
It worked for me
I'm developing my first Android application, and I'm curious if there are any "standard" ways for executing privileged shell commands. I've only been able to find one way to do it, by executing su, and then appending my commands to stdin of the su process.
DataOutputStream pOut = new DataOutputStream(p.getOutputStream());
DataInputStream pIn = new DataInputStream(p.getInputStream());
String rv = "";
// su must exit before its output can be read
pOut.writeBytes(cmd + "\nexit\n");
pOut.flush();
p.waitFor();
while (pIn.available() > 0)
rv += pIn.readLine() + "\n";
I've read about wrapping privileged (superuser) calls up in JNI: is this possible? If so, how would one go about accomplishing it? Other than that, are there any other ways of calling privileged instructions from Java?
As far as I know, you can only run command-line commands using root privileges. You can use this generic class I made that wraps the root access in your code:
http://muzikant-android.blogspot.com/2011/02/how-to-get-root-access-and-execute.html
All you need to do is extend this class and override the getCommandsToExecute method to return the commands you want to execute as root.
public abstract class ExecuteAsRootBase
{
public static boolean canRunRootCommands()
{
boolean retval = false;
Process suProcess;
try
{
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
if (null != os && null != osRes)
{
// Getting the id of the current user to check if this is root
os.writeBytes("id\n");
os.flush();
String currUid = osRes.readLine();
boolean exitSu = false;
if (null == currUid)
{
retval = false;
exitSu = false;
Log.d("ROOT", "Can't get root access or denied by user");
}
else if (true == currUid.contains("uid=0"))
{
retval = true;
exitSu = true;
Log.d("ROOT", "Root access granted");
}
else
{
retval = false;
exitSu = true;
Log.d("ROOT", "Root access rejected: " + currUid);
}
if (exitSu)
{
os.writeBytes("exit\n");
os.flush();
}
}
}
catch (Exception e)
{
// Can't get root !
// Probably broken pipe exception on trying to write to output stream (os) after su failed, meaning that the device is not rooted
retval = false;
Log.d("ROOT", "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}
return retval;
}
public final boolean execute()
{
boolean retval = false;
try
{
ArrayList<String> commands = getCommandsToExecute();
if (null != commands && commands.size() > 0)
{
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
// Execute commands that require root access
for (String currCommand : commands)
{
os.writeBytes(currCommand + "\n");
os.flush();
}
os.writeBytes("exit\n");
os.flush();
try
{
int suProcessRetval = suProcess.waitFor();
if (255 != suProcessRetval)
{
// Root access granted
retval = true;
}
else
{
// Root access denied
retval = false;
}
}
catch (Exception ex)
{
Log.e("ROOT", "Error executing root action", ex);
}
}
}
catch (IOException ex)
{
Log.w("ROOT", "Can't get root access", ex);
}
catch (SecurityException ex)
{
Log.w("ROOT", "Can't get root access", ex);
}
catch (Exception ex)
{
Log.w("ROOT", "Error executing internal operation", ex);
}
return retval;
}
protected abstract ArrayList<String> getCommandsToExecute();
}
A possible solution I know is to sign your application as system, which is not exactly the same as root as far as I know: How to sign Android app with system signature?. But I suppose this is not what you wanted.
Another thing I did is to create a native application that does what is needed, running it as an external process. But it is necessary to give this native application the privileges you need and the suid bit, provided the partition is not nosuid. But this is not what you needed either I suppose.
C code called through JNI should be subject to the same limitations as living in the same process, I suppose.
If you have the su binary available then you can run commands from java with something like: Runtime.getRuntime().exec("su -c reboot").
I don't remember any other way.
I was in the need of doing this in a rooted device recently and found out about libsu, which is a library allowing to execute su commands.
This library is written by the author of Magisk.
I have a rooted device with Magisk and libsu works pretty well from my app. The first time you execute a su command, Magisk will show a dialog where you grant or deny the root capabilities.
Running a command with libsu from an app is as simple as doing the following:
Shell.cmd("find /dev/block -iname boot").exec()
On a rooted android device, I tried to run a cat command that read kernel log, as follow:
Process p = Runtime.getRuntime().exec("su");
p = Runtime.getRuntime().exec("/system/bin/cat /proc/kmsg");
The su command was successfully executed but not the cat.
I tried to read the output of the command using getInputStream() but nothing was there, as follow:
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((read = err.read(buffer)) > 0)
{ //read error to buffer
catOutput.append(buffer, 0, read);
}
in.close();
I used the same code with ls command instead of displaying the kernel log, it worked just fine and show me the result.
I wonder if what error I am getting and wantted to see the error message on the shell when executing the cat command. Tried the p.getErrorStream() but it doesn't give me any result.
Could any one help me with this ? Thanks.
Here's a comprehensive example on how to do this - note that I got the idea from this answer:
public void catKmsg() {
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
StringBuilder sbstdOut = new StringBuilder();
StringBuilder sbstdErr = new StringBuilder();
String command="/system/bin/cat /proc/kmsg";
try { // Run Script
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(command);
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())));
if (proc.exitValue() != 0) {
}
}
I finally found the solution for the problem by using RootTools library.
Recently released (few months after my question was asked), RootTools provides a easy-to-use tool set that helps running commands that required root privilege. I created a wrapper to check if root access is available before executing shell command:
void testRootToolsCommand(String command){
if (RootTools.isRootAvailable())
toastMessage("Root is available !!!");
else {
toastMessage("NO ROOT !!! ");
return;
}
int timeOut = 1000;
try {
List<String> output = RootTools.sendShell(command,timeOut);
toastMessage("OUTPUT of the command \n" + output.toString());
} catch (RootToolsException re) {
toastMessage("Funny thing happened with RootTools!!! ");
} catch (TimeoutException te)
{
toastMessage("Timeout exception - Increase timeout !!! !!! ");
}
catch (Exception e) {
toastMessage(e.getMessage().toString());
}
}
An example of a function call is:
testRootToolsCommand("cat /proc/kmsg > /sdcard/jun11_4h51.txt");
Note: The Tool also support running multiple commands at once.