反射调用命令执行
Preface
开发者设计本地命令执行的本意是实现某些程序功能
Runtime
最简单的命令执行方法
Runtime.getRuntime().exec("bash -c {echo,d2hvYW1p}|{base64,-d}|{bash,-i}");
跟踪调用栈可以发现,Runtime#exec
并不是命令执行的最终点
java.lang.Runtime#exec
-> java.lang.ProcessBuilder#start
-> java.lang.ProcessImpl#start
-> ProcessImpl#
-> native create
ProcessBuilder
public final class ProcessBuilder {
public ProcessBuilder(List<String> command) {
if (command == null)
throw new NullPointerException();
this.command = command;
}
public ProcessBuilder(String... command) {
this.command = new ArrayList<>(command.length);
for (String arg : command)
this.command.add(arg);
}
public Process start() throws IOException {
// ...
try {
return ProcessImpl.start(cmdarray,
environment,
dir,
redirects,
redirectErrorStream);
} // ...
}
}
// ProcessBuilder processBuilder = new ProcessBuilder(Arrays.asList("calc"));
ProcessBuilder processBuilder = new ProcessBuilder("calc");
processBuilder.start();
ProcessImpl
非public类,需要使用反射调用
Class clazz = Class.forName("java.lang.ProcessImpl");
Method start = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
start.setAccessible(true);
start.invoke(clazz, new String[]{"calc"}, null, null, null, false);
ProcessImpl#start
最终调用的是ProcessImpl
的构造方法
Class clazz = Class.forName("java.lang.ProcessImpl");
Constructor constructor = clazz.getDeclaredConstructor(String[].class, String.class, String.class, long[].class, boolean.class);
constructor.setAccessible(true);
constructor.newInstance(new String[]{"calc"}, null, null, new long[]{-1,-1,-1}, false);
最后调用的是ProcessImpl#create
native方法
Linux和Mac系统上则是交给UNIXProcess#forkAndExec
native方法
Last updated
Was this helpful?