概述
app_process是Android原生的一个可执行程序,位于/system/bin目录下,zygote进程便是由这个执行文件启动的。
基本用法
1 2 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 文件。
1 2 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
1 2 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
1 2 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
1 2 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
1 2 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端发送想要执行的命令即可。