This article brings you relevant knowledge about java, which mainly introduces issues related to the reflection mechanism of java. The function of dynamically obtaining program information and dynamically calling objects is called reflection of the Java language. Mechanism, I hope it will be helpful to everyone.
Recommended study: "java tutorial"
Every time I hear a big guy talking or watch forums and other ways to learn java When deserializing vulnerabilities, there is a word called reflection mechanism. The boss uses this word to create a payload for you. For those of us who have just learned Java deserialization, we may be a little confused. Anyway, I am confused. , so I quickly learned a lesson, otherwise the gap between me and the big guys will become wider and wider. So this article mainly talks about the java reflection mechanism
Java's reflection (reflection) mechanism means that in the running state of the program, objects of any class can be constructed, and you can understand The class to which any object belongs can understand the member variables and methods of any class, and can call the properties and methods of any object. This function of dynamically obtaining program information and dynamically calling objects is called the reflection mechanism of the Java language. Reflection is seen as the key to dynamic languages.
I’m not very good at expressing myself in words, so let’s use the above picture to illustrate
an example of not using the reflection mechanism
//定义一个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(); }}
To add animals at this time, just
Modify the above to the reflection mechanism
//定义一个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实例化类似于new a = (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(); }}
Add animals at this time Just need to
It saves a step, the incoming class name is controllable, and it seems to exist Classes can adjust
The ones we use most are probably
Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());
Below we use the reflection mechanism to pop up the computer (calc) or notepad ( notepad)
Since there are a lot of pop-ups on the computer, I will just play Notepad this time. All in all, it’s great to be able to pop it up
Runtime.getRuntime().exec("notepad");
Let’s take a look at the getRuntime function
I learned that this function is the way for the Runtime class to obtain objects. Personally, I feel that it is troublesome to call it every time. In order not to call it once to create an object, it is encapsulated into a function
How to obtain class objects
Class initialization
Modify the zoo class, add initial block, static initial block, and constructor
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实例化类似于new a = (animals) Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); } return a; }}
Class initialization execution sequence: Static initial block
Class instantiation execution sequence: Static initial block-> Initial block- > Constructor
From this we know that class initialization and class instantiation are different
Next add the zoo1 class to inherit the zoo class
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()); }}
Subclass initialization sequence: Parent class static initialization block - > Subclass static initialization block
Subclass instantiation sequence: Parent class Static initialization block - > Subclass static initialization block - > Parent class initialization block - > Parent class constructor - > Subclass initialization block - > Subclass constructor
It can be known from the above that when Class.forName is used and the class static initialization block is controllable, any code can be executed
Call the internal class
Class.forName("java.lang.Runtime") to get the class (java.lang.Runtime is the full path of the Runtime class)
getMethod
The function of getMethod is to obtain a specific public method of the class through reflection.
Java supports class overloading, but a function cannot be determined by just a function name, so when calling getMethod, a list of parameter types needs to be passed to its method
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类有两个构造函数
分别使用构造方法
执行完构造方法实例后,在进行强制转化使用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");
推荐学习:《java视频教程》
The above is the detailed content of Detailed explanation of the reflection mechanism of Java deserialization with examples. For more information, please follow other related articles on the PHP Chinese website!