이 기사에서는 java의 반사 메커니즘과 관련된 문제를 주로 소개하는 Java에 대한 관련 지식을 제공합니다. 프로그램 정보를 동적으로 얻고 객체를 동적으로 호출하는 기능을 Java 언어의 반사 메커니즘이라고 합니다. 모두에게 유용합니다.
추천 학습: "java tutorial"
대인이 Java 역직렬화 취약점을 배우기 위한 포럼 및 기타 방법에 대해 이야기하거나 보는 것을 들을 때마다 반사 메커니즘이라는 단어가 있을 것이고, 그 큰 사람은 차용합니다. 이 단어를 사용해서 페이로드를 만들어보겠습니다. Java deserialization을 처음 배운 분들은 조금 헷갈리실 수도 있는데, 웨이브를 빨리 배우셨네요. 그리고 큰 사람들은 점점 더 커질 것입니다. 그래서 이 글에서는 주로 Java 반사 메커니즘에 대해 이야기합니다
Java의 반사 메커니즘은 프로그램의 실행 상태에서 모든 클래스의 객체를 생성할 수 있고, 어떤 객체가 속한 클래스를 이해할 수 있다는 것을 의미합니다. 모든 클래스의 멤버 변수와 메서드를 이해할 수 있고 모든 개체의 속성과 메서드를 호출할 수 있습니다. 프로그램 정보를 동적으로 획득하고 객체를 동적으로 호출하는 이러한 기능을 Java 언어의 반영 메커니즘이라고 합니다. Reflection은 동적 언어의 핵심으로 간주됩니다.
저는 말 표현을 잘 못하므로 그림처럼 해보자
반사 메커니즘을 사용하지 않은 예
//定义一个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(); }}
이때 동물을 추가하려면
위 내용을 반사 메커니즘으로 수정
//定义一个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(); }}
이번에 동물을 추가하려면
들어오는 클래스 이름을 제어할 수 있으며, 기존의 모든 클래스를
으로 조정할 수 있는 것 같습니다. 우리가 가장 많이 사용하는 것은 아마도
Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());
다음으로 리플렉션 메커니즘을 사용하여 컴퓨터(calc) 또는 메모장(notepad)을 팝업합니다
팝업할 컴퓨터가 너무 많아서 이번에는 메모장을 띄워보겠습니다. 한마디로 팝업이 되니 신기하네요
Runtime.getRuntime().exec("notepad");
getRuntime 기능을 살펴보겠습니다
이 기능을 배웠습니다. 런타임 클래스가 객체를 얻는 방식인데, 개인적으로 매번 호출하는 것이 번거롭다고 느껴서 객체 생성을 위해 함수로 캡슐화합니다
클래스 획득 방법 object
클래스 초기화
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实例化类似于new a = (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());
}}
: 상위 클래스 정적 초기화 블록 - > 하위 클래스 정적 초기화 블록
child 클래스 인스턴스화 순서
: 상위 클래스 정적 초기화 블록 - > 상위 클래스 초기화 블록 - > 하위 클래스 초기화 블록 - > 위에서 Class.forName을 사용하고 클래스 정적 초기화 블록을 제어할 수 있으면 모든 코드를 실행할 수 있습니다.
내부 클래스를 호출하여
Class.forName("java.lang.Runtime")을 사용하여 클래스( java.lang.Runtime은 런타임 클래스의 전체 경로입니다.)
getMethod
Class.forName("java.lang.Runtime").getMethod ("exec", String.class)getMethod는 리플렉션을 통해 클래스의 특정 공개 메서드를 얻는 데 사용됩니다.
Java는 클래스 오버로딩을 지원하지만 함수 이름만으로는 함수를 판별할 수 없으므로 getMethod 호출 시 해당 메소드의 매개변수 유형 목록을 전달해야 합니다.
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");로그인 후 복사推荐学习:《java视频教程》
위 내용은 예제를 통해 Java 역직렬화의 반영 메커니즘에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!