ANDROID: How to gain root access in an Android app

2019-01-03 13:47发布

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?

2条回答
不美不萌又怎样
2楼-- · 2019-01-03 14:14

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.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-03 14:31

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();
}
查看更多
登录 后发表回答