概述
app_process是Android原生的一个可执行程序,位于/system/bin目录下,zygote进程便是由这个执行文件启动的。
基本用法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | Usage: app_process [java-options] cmd-dir start-class-name [options]
 java-options     - 传递给 JVM 的参数
 cmd-dir          - 命令执行路径
 start-class-name - 程序入口, main() 方法所在的类名
 options          - 可以是下面这些
 --zygote 启动 zygote 进程用的
 --start-system-server 启动系统服务(也是启动 zygote 进程的时候用的)
 --application 启动应用程序
 --nice-name= 启动之后的进程名称
 
 | 
app_process没有帮助程序,但是可以从源代码进行分析:
- 传入 –zygote 会启动 com.android.internal.os.ZygoteInit,否则启动 com.android.internal.os.RuntimeInit。
- –start-system-server 只在启动 zygote 时有效。
- 在非 zygote 模式中,有无 –application 的选项的区别只是是否将 stdout 和 stderr 重定向到 AndroidPrintStream。
- 只有在非 zygote 的情况下,–nice-name= 选项有效。
与 Java 相似, Android 支持在环境变量 CLASSPATH 中指定类搜索路径 (CLASSPATH),此外还可以在虚拟机参数中指定 -Djava.class.path= 。但是, Android 使用 ART 环境运行 Java ,传统的 Java 字节码文件(.class) 是不能直接运行的,app_process 支持在 CLASSPATH 中指定 dex 或 apk 文件。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | # 使用 dex$ export CLASSPATH=/sdcard/app.dex
 $ app_process /system/bin com.hearing.Main
 # 或者
 $ app_process -Djava.class.path=/sdcard/app.dex /system/bin com.hearing.Main
 
 # 使用 apk
 $ export CLASSPATH=/sdcard/app.apk
 $ app_process /system/bin com.hearing.Main
 # 或者
 $ app_process -Djava.class.path=/sdcard/app.apk /system/bin com.hearing.Main
 
 | 
实例-C/S静默卸载
通过adb的方式由app_process开启一个Server,客户端通过Socket与之连接并调用需要系统权限的功能。(需要手动adb启动Server,实际可行性不大,并不能实现自动化启动)(如果在代码里自动调用app_process启动Server,该Server进程并不能获得系统权限)
Main
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | public class Main {public static void main(String[] args) {
 
 Looper.prepareMainLooper();
 System.out.println("*****************hack server starting****************");
 
 new Thread(new Runnable() {
 @Override
 public void run() {
 new SocketService(new SocketService.SocketListener() {
 @Override
 public String onMessage(String msg) {
 
 return resolveMsg(msg);
 }
 });
 }
 }).start();
 Looper.loop();
 }
 
 private static String resolveMsg(String msg) {
 
 ShellUtil.ExecResult execResult = ShellUtil.execute("pm uninstall " + msg);
 return execResult.getMessage();
 }
 }
 
 | 
Server
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 
 | public class SocketService {private final int PORT = 10500;
 private SocketListener listener;
 
 public SocketService(SocketListener listener) {
 this.listener = listener;
 try {
 
 ServerSocket serverSocket = new ServerSocket(PORT);
 System.out.println("server running " + PORT + " port");
 ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);
 
 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MILLISECONDS, queue);
 while (true) {
 Socket socket = serverSocket.accept();
 
 executor.execute(new MsgProcess(socket));
 }
 } catch (Exception e) {
 System.out.println("SocketServer create Exception:" + e);
 }
 }
 
 class MsgProcess implements Runnable {
 Socket socket;
 
 public MsgProcess(Socket s) {
 socket = s;
 }
 
 public void run() {
 try {
 
 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
 String line = bufferedReader.readLine();
 System.out.println("server receive: " + line);
 PrintWriter printWriter = new PrintWriter(socket.getOutputStream());
 String repeat = listener.onMessage(line);
 System.out.println("server send: " + repeat);
 
 printWriter.print(repeat);
 printWriter.flush();
 printWriter.close();
 bufferedReader.close();
 socket.close();
 } catch (IOException e) {
 System.out.println("socket connection error:" + e.toString());
 }
 }
 }
 
 public interface SocketListener {
 
 String onMessage(String text);
 }
 }
 
 | 
Client
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 
 | public class SocketClient {private final String TAG = "HackRoot SocketClient";
 private final int PORT = 10500;
 private SocketListener listener;
 private PrintWriter printWriter;
 
 public SocketClient(final String cmd, SocketListener listener) {
 this.listener = listener;
 new Thread(new Runnable() {
 @Override
 public void run() {
 Socket socket = new Socket();
 try {
 
 socket.connect(new InetSocketAddress("127.0.0.1", PORT), 3000);
 socket.setSoTimeout(3000);
 printWriter = new PrintWriter(socket.getOutputStream(), true);
 Log.d(TAG, "client send: " + cmd);
 
 printWriter.println(cmd);
 printWriter.flush();
 
 readServerData(socket);
 } catch (IOException e) {
 Log.d(TAG, "client send fail: " + e.getMessage());
 e.printStackTrace();
 }
 }
 }).start();
 }
 
 private void readServerData(final Socket socket) {
 try {
 InputStreamReader ipsReader = new InputStreamReader(socket.getInputStream());
 BufferedReader bfReader = new BufferedReader(ipsReader);
 String line = null;
 while ((line = bfReader.readLine()) != null) {
 Log.d(TAG, "client receive: " + line);
 listener.onMessage(line);
 }
 
 ipsReader.close();
 bfReader.close();
 printWriter.close();
 socket.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 
 interface SocketListener {
 void onMessage(String msg);
 }
 }
 
 | 
ShellUtil
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 
 | public class ShellUtil {private static final String COMMAND_LINE_END = "\n";
 private static final String COMMAND_EXIT = "exit\n";
 
 public static void runShell(String command) {
 Process process = null;
 BufferedReader bufferedReader = null;
 StringBuilder mShellCommandSB = new StringBuilder();
 System.out.println("runShell: " + command);
 mShellCommandSB.delete(0, mShellCommandSB.length());
 String[] cmd = new String[]{"/system/bin/sh", "-c", command};
 try {
 process = Runtime.getRuntime().exec(cmd);
 bufferedReader = new BufferedReader(new InputStreamReader(
 process.getInputStream()));
 String line;
 
 while ((line = bufferedReader.readLine()) != null) {
 mShellCommandSB.append(line);
 }
 System.out.println("runShell result: " + mShellCommandSB.toString());
 process.waitFor();
 } catch (IOException | InterruptedException e) {
 e.printStackTrace();
 } finally {
 if (bufferedReader != null) {
 try {
 bufferedReader.close();
 } catch (IOException e) {
 
 }
 }
 
 if (process != null) {
 process.destroy();
 }
 }
 }
 
 public static ExecResult execute(String command) {
 return execute(new String[]{command});
 }
 
 public static ExecResult execute(String[] commands) {
 if (commands == null || commands.length == 0) {
 return new ExecResult(false, "empty command");
 }
 int result = -1;
 Process process = null;
 DataOutputStream dataOutputStream = null;
 BufferedReader sucResult = null, errResult = null;
 StringBuilder sucMsg = null, errMsg = null;
 
 try {
 
 process = Runtime.getRuntime().exec("sh");
 dataOutputStream = new DataOutputStream(process.getOutputStream());
 for (String command : commands) {
 if (command == null) continue;
 System.out.println("execute command: " + command);
 
 dataOutputStream.write(command.getBytes());
 dataOutputStream.writeBytes(COMMAND_LINE_END);
 
 dataOutputStream.flush();
 }
 dataOutputStream.writeBytes(COMMAND_EXIT);
 dataOutputStream.flush();
 result = process.waitFor();
 sucMsg = new StringBuilder();
 errMsg = new StringBuilder();
 sucResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
 errResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
 String s;
 while ((s = sucResult.readLine()) != null) {
 sucMsg.append(s);
 }
 while ((s = errResult.readLine()) != null) {
 errMsg.append(s);
 }
 
 } catch (IOException | InterruptedException e) {
 e.printStackTrace();
 } finally {
 try {
 
 assert dataOutputStream != null;
 dataOutputStream.close();
 assert sucResult != null;
 sucResult.close();
 assert errResult != null;
 errResult.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 process.destroy();
 }
 ExecResult execResult;
 if (result == 0) {
 execResult = new ExecResult(true, sucMsg.toString());
 } else {
 execResult = new ExecResult(false, errMsg.toString());
 }
 
 return execResult;
 }
 
 public static class ExecResult {
 private boolean success;
 private String message;
 
 public ExecResult(boolean success, String message) {
 this.success = success;
 this.message = message;
 }
 
 public boolean getSuccess() {
 return this.success;
 }
 
 public String getMessage() {
 return this.message;
 }
 }
 }
 
 | 
客户端
- 通过app_process部署Server;
- 客户端通过调用SocketClient中的方法,向Server端发送想要执行的命令即可。