> Author: shaobaobaoer
> Codes : https://github.com/ninthDevilHAUNSTER/JavaSecLearning
> Mail: shaobaobaoer@126.com
> WebSite: shaobaobaoer.cn
最近在学习JAVA安全。上个礼拜摸了一个 JAVA_ADB项目 ,本来想着把ArknightsAutoHelper摸个Jar出来,想想还是工程量太大了,而且还有些JAVA高级编程还没弄通,就当是熟悉一下java的语法了。本周开始正式学习JAVA安全的知识。
感谢dalao们的博客,让我获益匪浅~
https://javasec.org/javase/
Java是编译型语言,我们编写的java文件需要编译成后class文件后才能够被JVM运行。
Java反射(Reflection)是Java非常重要的动态特性,通过使用反射我们不仅可以获取到任何类的成员方法(Methods)、成员变量(Fields)、构造方法(Constructors)等信息,还可以动态创建Java类实例、调用任意的类方法、修改任意的类成员变量值等。Java反射机制是Java语言的动态性的重要体现。
Java反射操作的是java.lang.Class对象,通常我们有如下3种
String className = "java.lang.Runtime"; Class<?> clazz = Class.forName(className); Class<?> clazz = java.lang.Runtime.class; Class<?> clazz = this.getClass().getClassLoader().loadClass(className); //Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass(className); // 第三种也可以这么写,反正就是要找打一个classloader类,调用其LoadClass的方法
不要因为Import了就写成Runtime。这应该是不同两种机制。
与获取类实例相关的类为 Constructor 类,并对应clazz.getConstructor(s),clazz.getDeclaredConstructor(s)方法
// 获取构造方法 // 使用Runtime类的Class对象获取Runtime类的无参数构造方法(getDeclaredConstructor()) // 因为Runtime的构造方法是private的我们无法直接调用,所以我们需要通过反射去修改方法的访问权限(constructor.setAccessible(true))。 Constructor<?> constructor = runtimeClass1.getDeclaredConstructor(); constructor.setAccessible(true); // 创建Runtime类示例,等价于 Runtime rt = new Runtime(); Object runtimeInstance = constructor.newInstance();
与获取Class方法相关的类为 Method 类,并对应clazz.getMethod(s),clazz.getDelcareMethod(s)方法
getMethod getDeclaredMethod getMethod
Class<?> clazz = Class.forName("java.lang.Runtime"); Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method.getName()); } Method method = clazz.getMethod("exec", String.class);
执行将采用method.invoke方法
public Object invoke(Object obj, Object... args)
与获取 Class 成员变量相关的类为 Feild 类,并对应clazz.getField(s),clazz.getDelcareField(s)方法
// 反射调用类变量 Field[] f = clazz.getDeclaredFields(); for (Field _f : f) { String _f_name = _f.getName(); }
获取将采用.get方法,返回这个变量的类。
public Object get(Object obj)
赋值将采用.set方法。
public void set(Object obj, Object value)
语言修饰符,就是形如static,void,final这种的。
与获取 Class 语言修饰符相关的类为 Modifier ,
从类继承图可以得知,Field、Constructor、Method均实现了Member的接口,而Member的接口中就存在着 getModifier 这个方法。因此该方法这三个类均有实现。
实际上 getModifier 返回的是一串数字。这串数字是如何转化为 static等语言修饰符的呢?
Modifier类中定义了非常多的INT型私有常量。
/** * The {@code int} value representing the {@code public} * modifier. */ public static final int PUBLIC = 0x00000001; ... /** * The {@code int} value representing the {@code abstract} * modifier. */ public static final int ABSTRACT = 0x00000400;
通过简单的按位与方法,就可以获取到语言修饰符。
有一些方法是不能被直接调用的,因为有final、private的存在。
Class<?> clazz = Class.forName("java.lang.Process"); Process a = Runtime.getRuntime().exec("cmd /c dir"); Method m = a.getClass().getDeclaredMethod("getInputStream"); m.invoke(a); >>>>>>> java.lang.IllegalAccessException: class xxx cannot access a member of class java.lang.ProcessImpl (in module java.base) with modifiers "public"
Class<?> clazz = Class.forName("java.lang.Runtime"); Constructor<?> c = clazz.getDeclaredConstructor(); Object o = c.newInstance(); >>>>>>> java.lang.IllegalAccessException: class xxxx cannot access a member of class java.lang.Runtime (in module java.base) with modifiers "private"
比如说 ProcessImpl
这一个类是final的,类内所有的东西都不可直接调用,需要通过反射去修改方法的访问权限。
又比如说 Runtime
的构造方法是private的。我们无法直接调用,需要修改权限。
分析类继承图,可以得知 Constructor
, Method
, Field
均继承了 AccessibleObject
该类中定义了 啥叫 可达(Accessible),也可以通过 setAccessible
方法修改权限。
@CallerSensitive // overrides in Method/Field/Constructor are @CS public static void setAccessible(AccessibleObject[] array, boolean flag) @CallerSensitive // overrides in Method/Field/Constructor are @CS public void setAccessible(boolean flag)
经过权限修改,这些方法就可以访问了,但是由于 @CallerSensitive
,所以运行时候会有警告信息
Class<?> clazz = Class.forName("java.lang.Runtime"); Constructor<?> c = clazz.getDeclaredConstructor(); c.setAccessible(true); Object o = c.newInstance();
综上,可以整合一下代码,看看Runtime类的相关细节。
Class<?> runtimeClass1 = Class.forName(className); // 反射调用类变量 System.out.println(String.format("%s 的所有类变量", className)); Field[] f = runtimeClass1.getDeclaredFields(); for (Field _f : f) { String _f_name = _f.getName(); String mod = Modifier.toString(_f.getModifiers()); System.out.println(String.format( "%s %s", mod, _f_name )); } System.out.println(String.format("%s 的所有构造函数", className)); Constructor<?>[] c = runtimeClass1.getDeclaredConstructors(); for (Constructor<?> _c : c) { String mod = Modifier.toString(_c.getModifiers()); // 取得访问权限 getModifiers返回的是字节码,通过异或(可能)操作,可以获取响应权限 String metName = _c.getName(); // 取得方法名称 Class<?> xx[] = _c.getParameterTypes(); StringBuilder strb = new StringBuilder(); for (Class<?> x : xx) { strb.append(x.getName()); // 稍微解析一下 入口参数 } System.out.println(String.format( "%s %s(%s)", mod, metName, strb.toString().replace(";", " , ") )); } // 反射调用类方法 Method[] m = runtimeClass1.getDeclaredMethods(); System.out.println(String.format("%s 的所有方法", className)); for (Method _m : m ) { String mod = Modifier.toString(_m.getModifiers()); // 取得访问权限 getModifiers返回的是字节码,通过异或(可能)操作,可以获取响应权限 String metName = _m.getName(); // 取得方法名称 String return_type = _m.getReturnType().getName(); // 获取返回的东西 Class<?> xx[] = _m.getParameterTypes(); StringBuilder strb = new StringBuilder(); for (Class<?> x : xx) { strb.append(x.getName()); // 稍微解析一下 入口参数 } System.out.println(String.format( "%s %s(%s) -> %s", mod, metName, strb.toString().replace(";", " , "), return_type ));
很遗憾的说,推酷将在这个月底关闭。人生海海,几度秋凉,感谢那些有你的时光。
原文 https://shaobaobaoer.cn/java-an-quan-xue-xi-bi-ji-yi-java-fan-she-ji-zhi/