记录学习Java反射

文摘   2024-08-29 12:46   云南  

本篇文章记录学习Java反射 。 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性

获取Class类

根据类名:类名.class根据对象:对象.getClass()根据全限定类名:Class.forName(全限定类名)

package 反射;  
import java.lang.reflect.InvocationTargetException;
public class demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { Test test = new Test(); System.out.println(test);
// .class根据类名 获取class对象 Class s = Test.class; System.out.println(s);
// .getClass 根据对象,获取class对象 Class s1 = new Test().getClass(); System.out.println(s1);
// .forName Class s2 = Class.forName("反射.Test"); System.out.println(s2); } }

获取Class类中的构造方法 getConstructor

获取Constructor对象是通过Class类中的方法获取的,Class类与Constructor相关的主要方法如下:

方法名称方法说明
forName(String ClassName)返回与带有给定字符串名的类或接口相关联的 Class 对象。
getConstructor(Class<>.. parameterTypes)返回指定参数类型、具有public访问权限的构造函数对象
getConstructors()返回所有具有public访问权限的构造函数的Constructor对象数组
getDeclaredConstructor(Class<>.. parameterTypes)返回指定参数类型、所有声明的(包括private)构造函数对象
getDeclaredConstructors()返回所有声明的(包括private)构造函数对象
newInstance()调用无参构造器创建此 Class 对象所表示的类的一个新实例。

获取一个无参的构造方法

在Test 类中设置了,无参的构造方法

package 反射;  
public class Test { // 定义成员变量 public String name="xiaomi"; public int age = 18;
public Test(){
}
// public Test(String name){ // this.name = name; // }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
package 反射;  
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { try {
// .forName 根据全限名称获取class对象 Class<?> clazz = Class.forName("反射.Test");
// 获取一个无参的构造方法 Object instance = clazz.getConstructor().newInstance();
System.out.println("构造方法的类:"+clazz.getName());

} catch (Exception e) { e.printStackTrace(); }
} }

获取一个有参的构造方法

Test类中构造方法,接收了一个String类型的变量

public Test(String name){      this.name = name;  }

在getConstructor 中要定义一个 String.class

package 反射;  
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { try {
// .forName 根据全限名称获取class对象 Class<?> clazz = Class.forName("反射.Test");
// getConstructor 获取构造方法 Object instance = clazz.getConstructor(String.class).newInstance("我是构造方法");
String name = (String) clazz.getMethod("getName").invoke(instance);
System.out.println(name);

} catch (Exception e) { e.printStackTrace(); }
} }



获取Class类中的私有 (private) 构造方法 getDeclaredConstructor

示例

package 反射;  
public class Test2 { // 定义成员变量 public String name="xiaomi"; public int age = 18;
private Test2(){
}

public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; } }
package 反射;  
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class demo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { try { Class<?> clazz = Class.forName("反射.Test2"); Constructor<?> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true);
Object ins = constructor.newInstance(); String name = (String) clazz.getMethod("getName").invoke(ins); System.out.println(name);
}catch (Exception e){ e.printStackTrace(); } } }


获取class类中 Method 方法

下面是Class类获取Method对象相关的方法:

方法名称方法说明
getDeclaredMethod()返回一个指定参数的Method对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。public private
getDeclaredMethods()返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
getMethod()返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。public
getMethods()返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

例如:我需要获取Test类中的getName方法

package 反射;  
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { try {
// .forName 根据全限名称获取class对象 Class<?> clazz = Class.forName("反射.Test");
// getConstructor 获取构造方法 Object instance = clazz.getConstructor(String.class).newInstance("name 是 getName ");
String name = (String) clazz.getMethod("getName").invoke(instance);
System.out.println(name);

} catch (Exception e) { e.printStackTrace(); }
} }


获取class类中的FieId

Class类与Field对象相关方法如下:

方法返回值方法名称方法说明
FieldgetDeclaredField(String name)获取指定name名称的(包含private修饰的)字段,不包括继承的字段
Field[]getDeclaredFields()获取Class对象所表示的类或接口的所有(包含private修饰的)字段,不包括继承的字段
FieldgetField(String name)获取指定name名称、具有public修饰的字段,包含继承字段
Field[]getFields()获取修饰符为public的字段,包含继承字段
package 反射;  
import java.lang.reflect.Field;
public class demoFieId { public static void main(String[] args) { try { Class<?> clazz = Class.forName("反射.Test2");
Test2 st= (Test2) clazz.newInstance();
Field name = clazz.getField("name"); // 修改name的值 name.set(st,"wdd"); System.out.println(st.name.toString());
}catch (Exception e){ e.printStackTrace(); } } }


使用反射系统执行命令类

获取类的⽅法: forName 实例化类对象的⽅法: newInstance 获取函数的⽅法: getMethod 执⾏函数的⽅法: invoke

getMethod 系列方法获取的是当前类中所有公共方法,包括从父类继承的方法 getDeclaredMethod 系列方法获取的是当前类中“声明”的方法,是实在写在这个类里的,包括私有的方法,但从父类里继承来的就不包含了

invoke 的作用是执行方法,它的第一个参数是:
如果这个方法是一个普通方法,那么第一个参数是类对象
如果这个方法是一个静态方法,那么第一个参数是类

创建恶意的类,用来演示forName 反射加载类

创建执行弹出计算器的类

package reflex.test;  
public class calc { static { try { Runtime rt = Runtime.getRuntime(); String[] commands = {"calc.exe"}; Process pc = rt.exec(commands); pc.waitFor(); } catch (Exception e) { // do nothing } } }

通过Class.forName 反射加载恶意类,实现命令执行

package reflex.test;  
import java.lang.reflect.InvocationTargetException;
public class demo1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class clazz = Class.forName("reflex.test.calc"); //通过forName 反射通用calc恶意类 } }

java.lang.Runtime

单列模式 getRuntime

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

package 反射;  
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class cmd { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { try{
// java.lang.Runtime // 使用反射 java.lang.Runtime 执行calc Class<?> clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),"calc"); }catch (Exception e){ e.printStackTrace(); } } }

private 私有Runtime

package 反射;  
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class cmd { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { try{
Class<?> clazz = Class.forName("java.lang.Runtime"); Constructor<?> m = clazz.getDeclaredConstructor(); m.setAccessible(true); clazz.getMethod("exec", String.class).invoke(m.newInstance(),"calc");
}catch (Exception e){ e.printStackTrace(); } } }

java.lang.ProcessBuilder

ProcessBuilder有两个构造函数


public ProcessBuilder(List<String> command) { if (command == null) throw new NullPointerException(); this.command = command; }
/** * Constructs a process builder with the specified operating * system program and arguments. This is a convenience * constructor that sets the process builder's command to a string * list containing the same strings as the {@code command} * array, in the same order. It is not checked whether * {@code command} corresponds to a valid operating system * command. * * @param command a string array containing the program and its arguments */public ProcessBuilder(String... command) { this.command = new ArrayList<>(command.length); for (String arg : command) this.command.add(arg); }

正常调用 ProcessBuilder

ProcessBuilder p = new ProcessBuilder();  p.command("calc").start();

反射调用 ProcessBuilder

ProcessBuilder List.class

package reflex.test;  
import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.List;
public class demo4 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { Class classz = Class.forName("java.lang.ProcessBuilder"); classz.getMethod("start").invoke(classz.getConstructor(List.class).newInstance(Arrays.asList("calc.exe"))); } }


ProcessBuilder String[].class

package 反射;  
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class demo3 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { try{
Class<?> clazz = Class.forName("java.lang.ProcessBuilder"); clazz.getMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(new String[][]{{"calc.exe"}}));
}catch (Exception e){ e.printStackTrace(); } } }


安全逐梦人
渗透实战知识分享,漏洞复现,代码审计,安全工具分享