# 反射调用命令执行

### Preface

开发者设计本地命令执行的本意是实现某些程序功能

### Runtime

最简单的命令执行方法

```java
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

```java
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);
        } // ...
    }
}
```

```java
// ProcessBuilder processBuilder = new ProcessBuilder(Arrays.asList("calc"));
ProcessBuilder processBuilder = new ProcessBuilder("calc");
processBuilder.start();
```

### ProcessImpl

非public类，需要使用反射调用

```java
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`的构造方法

```java
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方法

![image-20230506140255428](/files/HyvqXvbFTVQuemKe6JsN)

Linux和Mac系统上则是交给`UNIXProcess#forkAndExec` native方法

![image-20230921171548250](/files/iJ3Y1HKpv7ARF2sH4aU9)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://p4d0rn.gitbook.io/java/prerequisites/fan-she/exec.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
