• JAVA 反序列化漏洞入门学习笔记(二)--JAVA反射


    参考文章

    Java 反序列化漏洞(2) – Java 反射机制

    看完参考后面忽略

    定义

    Java 反射机制是指在程序运行时,对于任何一个类,都能知道这个类的所有属性和方法,对于任何一个实例对象,都能调用该对象的任何一个属性和方法
    Java 中这种 "动态获取信息" 和 "动态调用属性 "方法的机制被称为 Java 反射机制
    实例对象可以通过反射机制获取它的类,类可以通过反射机制获取它的所有方法和属性,获取的属性可以设值,获取的方法可以调用
    Java 反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。
    反射最重要的用途是开发各种通用框架。很多框架都是通过 XML 文件来进行配置的(例如 struts.xml、spring-*.xml 等),即所谓的框架核心配置文件。为了确保框架的通用性,程序运行时需要根据配置文件中对应的内容加载不同的类或对象,调用不同的方法,这也依赖于 Java 反射机制

    简单示例:

    public class Reflectest{
        public static void main(String[] args) throws Exception {
            Object runtime = Class.forName("aaa.bbb.ccc").getMethod("ddd", String.class).invoke(null);
        }
    }
    


    可以看到,在程序编译时并未报错,在执行时才会提示 aaa.bbb.ccc 这个包不存在从而报错
    也就是说:反射就是在程序运行的时候才知道要加载哪些类,加载完成后再去调用类中的方法(是不是感觉在 Python 反序列化中也见过)

    反射机制步骤

    • 获取类
    • 获取类中方法及成员变量
    • 使用该类实例化一个对象
    • 调用实例对象中的方法/修改成员变量的值

    获取类

    • Class.forName("xxx.xxx.xxx")
    • 类.class
    • 对象.getClass()

    示例:

    class Ref{
        public Ref(){
            String name = "1ndex";
        }
    }
    
    public class RefTest{
        public static void main(String [] args) throws ClassNotFoundException {
            //Class.forName
            System.out.println("Class.forName():    " + Class.forName("Ref"));
            
            //类.class
            System.out.println("类.class:           " + Ref.class);
            
            //对象.getClass()
            Ref cls = new Ref();
            System.out.println("对象.getClass():    " + cls.getClass());
        }
    }
    

    获取类中方法及成员变量

    • className.getMethod(functionName,[parameterType.class]),获取 functionName 对应的特定 public 方法
    • className.getMethods(),获取该类所有的 public 方法,包括其继承类的公用方法
    • className.getDeclaredMethod(functionName,[parameterType.class]),获取 functionName 对应的特定方法,包括公共、保护、默认(包)访问和私有方法
    • className.getDeclaredMethods(),获取某个类或接口声明的所有方法 , 包括公共、保护、默认(包)访问和私有方法,但不包括其继承类的方法

    示例:

    import java.lang.reflect.Method;
    
    class Ref{
        public Ref(){
            String name = "1ndex";
        }
        public void ShowInfo(String name, int age){
            System.out.println(name + " is " + age);
        }
    }
    
    public class RefTest{
        public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException{
            Class<?> cls = Class.forName("Ref");
            
            //className.getMethod(functionName,[parameterType.class])
            Method method = cls.getMethod("ShowInfo",String.class,int.class);
            
            //className.getMethods()
            Method[] methods = cls.getMethods();
            
            //className.getDeclaredMethods()
            Method[] declareMethods = cls.getDeclaredMethods();
            
            System.out.println("className.getMethod(functionName,[parameterType.class]):
    " + method);
            
            System.out.println("
    className.getMethods():");
            for(Method m:methods){
                System.out.println(m);
            }
            
            System.out.println("
    className.getDeclaredMethods():");
            for(Method m:declareMethods){
                System.out.println(m);
            }
        }
        
    }
    

    使用该类实例化一个对象

    • className.newInstance(),调用无参构造函数
    • className.getConstructor(parameterType.class).newInstance("参数值"),调用 public 有参构造函数,之后只用调用实例化后的对象的公有方法
    • className.getDeclaredConstructor(parameterType.class).newInstance("参数值"),这个方法会返回指定参数类型的构造方法。包括 public、protected 以及 private 修饰符修饰的
    • className.getDeclaredConstructors(parameterType.class).newInstance("参数值"),这个方法会返回指定参数类型的所有构造方法。包括 public、protected 以及 private 修饰符修饰的
      示例:
    
    import java.lang.reflect.InvocationTargetException;
    
    class Ref{
        public Ref(){
            System.out.println("无参构造函数!
    ");
        }
        public Ref(String motto){
            System.out.println("有参构造函数!
    " + motto);
        }
    }
    
    public class RefTest{
        public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException{
            Class<?> cls = Class.forName("Ref");
            
            //className.newInstance(),调用无参构造函数
            Ref obj1 = (Ref)cls.newInstance();
            
            //className.getConstructor(parameterType.class).newInstance("参数值"),调用有参构造函数
            Ref obj2 = (Ref)cls.getConstructor(String.class).newInstance("一给我里Giao!");
        }
        
    }
    

    调用实例对象中的方法

    • Method.invoke(obj , args[]),传入实例对象和参数即可执行目标方法

    示例:

    import java.lang.reflect.Method;
    import java.lang.reflect.InvocationTargetException;
    
    class Ref{
        public Ref(){
            String name = "1ndex";
        }
        public void ShowInfo(String motto){
            System.out.println(motto);
        }
    }
    
    public class RefTest{
        public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException{
            // 获取类
            Class<?> cls = Class.forName("Ref");
            //获取类中方法
            Method getFunc = cls.getMethod("ShowInfo",String.class);
            //实例化对象
            Ref obj = (Ref)cls.newInstance();
            //调用对象中的方法
            getFunc.invoke(obj,"一给我里Giao!");
        }
        
    }
    

    tips:

    • 如何调用特定的私有方法
      实例:
    import java.lang.reflect.Method;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Constructor;
    
    
    public class RefTest{
        public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException{
    
            Class<?> cls = Class.forName("java.lang.Runtime");
            Method getFunc = cls.getMethod("exec",String.class);
            
            Constructor<?> cst = cls.getDeclaredConstructor();
            cst.setAccessible(true);
            
            Object obj = cst.newInstance();
            
            getFunc.invoke(obj,"calc");
        }
        
    }
    
  • 相关阅读:
    phpstudy apache 服务无法启动
    Nginx+keepalived实现负载均衡高可用配置
    Linux系统下zookeeper客户端命令使用
    JVM探究之 —— 类文件结构(脑图)
    JVM探究之 —— 类加载器-双亲委派模型
    Centos7 配置静态IP并使用xshell远程连接
    JVM探究之 —— 类加载过程
    JVM探究之 —— 垃圾回收(二)
    避免git clone和push时每次都需要输入用户名和密码
    jsch配置sftp服务器ssh免密登录
  • 原文地址:https://www.cnblogs.com/wjrblogs/p/14421386.html
Copyright © 2020-2023  润新知