0%

app_process使用

概述

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让线程循环
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 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 {
// 与hackserver建立连接
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) {
// TODO: handle exception
}
}

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 {
// 获取shell级别的process
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端发送想要执行的命令即可。