Java反序列化之反射机制
目录
- 前言
- Java反射机制
- 反射机制方法
- 指定构造方法生成实例
- 执行私有方法
- 总结
前言
每次听到大佬在讲或者看论坛等一些方式学java反序列化漏洞时,都会有一个词叫做反射机制,大佬顺势借着这个词,就给你造出一个payload,对于刚学java反序列化的我们,可能有点会懵圈,反正我是懵了,所以就赶紧学了一波,不然和大佬差距越来越大。所以这篇文章主要讲述java反射机制
Java反射机制
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。
我不太擅长文字表达,还是上图操作把
不用反射机制的例子
//定义一个animals接口
interface animals {public abstract void print();
}
//定义类来实现animals接口的抽象方法
class Dog implements animals {public void print() {System.out.println("Dog");}
}class Cat implements animals {public void print() {System.out.println("Cat");}
}// 构造一个zoo类
// 之后如果我们在添加其他的实例的时候只需要修改zoo类
class zoo {public static animals getInstance(String animalsName) {animals a = null;if ("Dog".equals(animalsName)) {a = new Dog();}if ("Cat".equals(animalsName)) {a = new Cat();}return a;}
}public class reflection {public static void main(String[] args) {//借助zoo类寻找对应的类来实现接口animals a=zoo.getInstance("Cat");if(a!=null)a.print();}
}
这时候添加动物,只需要
- 添加类
- 修改zoo
- 修改main函数的动物类
把上面修改为反射机制
//定义一个animals接口
interface animals {public abstract void print();
}//定义类来实现animals接口的抽象方法
class Dog implements animals {public void print() {System.out.println("Dog");}
}class Cat implements animals {public void print() {System.out.println("Cat");}
}// 构造一个zoo类
// 之后如果我们在添加其他的实例的时候只需要修改zoo类
class zoo {public static animals getInstance(String className) {animals a = null;try {//借助Class.forName寻找类名,并用newInstance实例化类似于newa = (animals) Class.forName(className).newInstance();} catch (Exception e) {e.printStackTrace();}return a;}
}public class reflection {public static void main(String[] args) {//借助zoo类寻找对应的类来实现接口(classname为当前包名加类名)animals a = zoo.getInstance("com.cc1.Dog");if (a != null)a.print();}
}
这时候添加动物只需要
- 添加类
- 修改main函数的动物类
省了一步,传入类名可控,发现好像是存在的类都可以调
反射机制方法
我们用的最多的可能是
- forName(调用类)
- getMethod(调用类下方法)
- invoke(执行)
- newInstance(实例化对象)
Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());
下面我们用反射机制来弹出计算机(calc)或者记事本(notepad)
由于弹出计算机有点多这次我就弹记事本把,总而言之,能弹出来就很美妙
Runtime.getRuntime().exec("notepad");
我们看下getRuntime函数
得知,该函数是Runtime类获取对象的方式,个人感觉是每用一次就调一次比较麻烦,为了不调用一次建立一个对象所以封装成了函数
类对象获取方式
- Class.forName(类名获取)
- zoo.class(已经加载过的类)
- obj.class(实例)
类初始化
修改zoo类,增加初始块、静态初始块、和构造函数
class zoo {//初始块{System.out.println("1 " + this.getClass());}//静态初始块static {System.out.println("2 " + zoo.class);}public zoo() {System.out.println("3 " + this.getClass());}public static animals getInstance(String className) {animals a = null;try {//借助Class.forName寻找类名,并用newInstance实例化类似于newa = (animals) Class.forName(className).newInstance();} catch (Exception e) {e.printStackTrace();}return a;}
}
类初始化执行顺序:静态初始块
类实例化执行顺序:静态初始块 - > 初始块 - > 构造函数
由此得知,类初始化和类实例化不一样
接下来增加zoo1类继承zoo类
class zoo1 extends zoo{//初始块{System.out.println("11 " + this.getClass());}//静态初始块static {System.out.println("12 " + zoo.class);}public zoo1() {System.out.println("13 " + this.getClass());}
}
子类初始化顺序:父类静态初始化块 - > 子类静态初始化块
子类实例化顺序:父类静态初始化块 - > 子类静态初始化块 - > 父类初始化块 - > 父类构造函数 - > 子类初始化块 - >子类构造函数
以上可以得知,当使用Class.forName时,且类静态初始化块可控,可以执行任意代码
调用内部类
Class.forName(“java.lang.Runtime”)来获取类(java.lang.Runtime是Runtime类的完整路径)
getMethod
getMethod 的作用是通过反射获取类的某个特定的公有方法。
java支持类重载,但不能仅通过一个函数名确定一个函数,所以在调用getMethod时,需要传给它方法的参数类型列表
Class.forName(“java.lang.Runtime”).getMethod(“exec”, String.class)
invoke
静态和动态方法的区别
invoke方法在getMethod类下,作用时传递参数,执行方法
public Object invoke(Object obj, Object… args)
第一个参数是getMethod获取的方法的类对象(如果方法是静态方法则传类)
获取exec函数的类对象
Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”))
由于getRuntime是静态方法,所以传类
invoke(Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”)),“calc.exe”)
最后我们合并一下
Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")), "notepad");
指定构造方法生成实例
String str="notepad";
ProcessBuilder pb = new ProcessBuilder(str);
pb.start();
getConsturctor(函数可以选定指定接口格式的构造函数(由于构造函数也可以根据参数来进行重载)
选定后我们可以通过newInstance(),并传入构造函数的参数执行构造函数
ProcessBuilder类有两个构造函数
- public ProcessBuilder(String… command)(String…变长的字符串数组String[].class)
- public ProcessBuilder(List command)
分别使用构造方法
- Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[][]{{“notepad”}})
- Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))
执行完构造方法实例后,在进行强制转化使用start函数即可
( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();
实际中,肯定用不了,哪有这么好的事,还是接着反射把
Class.forName(“java.lang.ProcessBuilder”).getMethod(“start”).invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList(“notepad”)));
这里可能有人会好奇我写的里那的另一个构造函数,String…command这个传参为什么用new String[][]{{“notepad”}},不应该是new String[]{“notepad”},现在用应该的
((ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[]{“notepad”})).start();
在这行打断点调试
我们传的是一个字符串数组到了实例化的时候变成了一个字符串,再看看另一个构造函数(List)
( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();
依旧还是这行打断点
由此可知,List传入时会被当作Object的第一项,而String[]会被当做Object,所以多加一层[]{}
执行私有方法
通过函数getDeclaredConstructor获取私有方法,再利用setAccessible(true)打破私有方法限制
Class cls = Class.forName("java.lang.Runtime");
Constructor m = cls.getDeclaredConstructor();
m.setAccessible(true);
cls.getMethod("exec", String.class).invoke(m.newInstance(), "notepad");
总结
这里也是通过反射机制调用任意类,大致让我这个门外汉也明白了反射,看到这里的你们想比应该也明白了,如果有什么疑问,我们可以一起交流学习,也请大佬多多指点
大家可以关注菜鸡的公众号,有什么好想法也可以让我学习一下,有什么问题可以一块解决,由于二维码违规,下面是base64编码的文字
5b6u5L+h5YWs5LyX5Y+34oCc5a6J5YWo5re35a2Q4oCd77yM5Y+v5Lul55So5b6u5L+h5pCc5LiA5pCc77yM5q2j5Zyo5a6M5ZaE5LitLi4uLi4u
Java反序列化之反射机制相关推荐
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
- JAVA基础--JAVA中的反射机制详解
JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能 ...
- java 有哪些反射机制_Java 的反射机制你了解多少?
不知道多少次听说过了Java反射机制的使用,比如:Spring 框架如何实例化IoC容器中的Bean,编码过程中如何动态的清理对象中的字段信息等等.工作中只是听说.看同事们编码实践,但是自己却只是概念 ...
- java代码安全检测机制_全面解析:java中的反射机制,内含代码验证解析
什么是反射? 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功 ...
- 根据实例详解Java中的反射机制
概念: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java ...
- JAVA Reflection(反射机制)续
接上一篇文章 JAVA Reflection(反射机制) 动态数组 java.lang.reflect.Array static Object set(Object array, int index ...
- JAVA Reflection(反射机制)
Java 反射机制 反射机制简介 反射机制应用示例 简单的Ioc实现 代理模式 Java动态代理 简单的Aop实现 "程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言" ...
- Java语言基础-反射机制、正则表达式
反射机制 反射机制是在运行状态中,对于任意一个类,都能知道这个类(class文件)的所有属性和方法. 对于任意一个对象,都能调用它的任意一个方法和属性. 这种动态获取信息以及动态调用对象的方法的功能称 ...
- formdata 接受参数中带有class 对象_浅析JAVA中的反射机制及对Servlet的优化
今天来聊聊java中的反射机制,工作以后发现很多东西动不动就要使用反射或者动态代理,如果不能很好的理解反射,那么对于动态代理等一些重要的设计模式就会有种不够通透的感觉. 所谓的反射,就是在运行状态中, ...
最新文章
- LeetCode刷题-6
- sudo及其配置文件sudoers
- 第四范式恭祝大家新春快乐!
- BZOJ2705 [SDOI2012]Longge的问题 欧拉函数
- 【TensorFlow-windows】TensorBoard可视化
- Windows CE 6.0中断处理过程(转载)
- Spring RESTful错误处理
- mysql密码高级_mysql高级操作
- 认清一个人,看这四点就够了
- socket抓包_64、抓包分析tcp与udp
- Linux Shell编程 - 正则表达式
- FISCO BCOS 控制台 部署合约 调用 查看已部署合约的地址
- Win7系统下解决VB6.0鼠标滚轮支持
- 设计模式 (十四) Cglib动态代理模式
- 计算机系统硬件基本组成
- VScode:禁止VScode自动升级
- 《东周列国志》第十回 楚熊通僭号称王 郑祭足被胁立庶
- Apostrophe not preceded错误
- ThinkPHP门面源码解析
- 数据库插入微信表情错误
热门文章
- No gradients provided for any variable, check your graph for ops that do not support gradients
- 【历史上的今天】4 月 30 日:信息论之父出生;万维网对所有人免费开放;图灵奖算法先驱诞生
- 离散数学 --- 图论基础 --- 无向图的连通性和有向图的连通性
- 北京中科红旗软件技术有限公司
- 自主创新进展制造世界主要轴承制作强国
- 原创_Android Jetpack Compose 最全上手指南,互联网寒冬公司倒闭后
- CFA【异常检测:Embedding_based】
- python模型训练 warm_start_随机森林入门攻略(内含R、Python代码)
- 马化腾:我和太太也是QQ认识的
- vscode调试nodejs不要太爽啊