“Java 安全” 学习笔记 - 2

12/11/20202 阅读自:p牛 “Java 安全漫谈 - 02.反射篇(2)”

java 的普通类 c1 中支持编写内部类 c2 ,而在编译的时候,会生成两个文件:C1.classC1$C2.class ,我们可以把他们看作两个无关的类,通过 Class.forName("C1$C2") 即可加载这个内部类。

class.newInstance() 可以调用反射的类的无参构造函数,但再构造poc时,经常不成功,原因有:

  • 使用的类没有无参构造函数
  • 使用的类构造函数是私有的

java.lang.Runtime 就不能直接这样执行命令:

Class clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec", String.class).invoke(clazz.newInstance(), "id");
image.png

导致这个错误的原因是 Runtime 类的构造方法是私有的。这就涉及到 “单例模式”。

//privateC.java

public class privateC {
    private static privateC instance = new privateC();
    public static privateC getInstance(){
        return instance;
    }
    private privateC(){
        System.out.println("this is a private method");
    }
}

例如WEB应用,数据库连接只需要一次,而不是每次用到时新建立连接,这时候就可以把类的构造函数设置为私有,然后编写一个静态方法来获取。这样,只有类初始化的时候执行一次构造函数,后面只能通过 getInstance 方法来获取这个对象,避免简历多个数据库连接。

本个例子,其实相当于在 privateC 内部实例化了,而外部仅仅是获取这个对象。

image.png

同理,Runtime 也是单例模式,我们只能通过 Runtime.getRuntime() 来获取到 Runtime 对象。

image.png
image
public class A {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("java.lang.Runtime");
        clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz), "open -na Calculator ");
    }
}

*总结

getMethod 的作用是通过反射获取一个类的某个特定的共有方法。此处的 Runtime.exe 有6个重载方法,上述使用的只有一个参数,类型是 String 的。因此我们使用的是 getMethod("exec", String.class) 来获取的方法

invoke 的作用是执行方法,它的第一个参数是:

  • 如果这个方法是一个普通的方法,那么第一个参数是类对象
  • 如果这个方法是一个静态方法,那么第一个参数是类

正常执行的方法是:[1].method( [2], [3], [4] ...)

对应到反射中就是:method.invoke( [1], [2] ,[3] ,[4] ...)

你可能感兴趣的:(“Java 安全” 学习笔记 - 2)