0x03反射-补充零散知识点
Runtime
类中有 exec
方法,可以用来命令执行。
一般情况下,我们使用反射机制不能对类的私有 private
字段进行操作,绕过私有权限的访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package IOStream;
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map;
public class FileStreamTest { public static void main(String[] args){ InputStream inputStream = null; try {
String[] cmds = new String[]{"calc"}; Class clazz = Class.forName("java.lang.ProcessImpl"); Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class); method.setAccessible(true); Process e = (Process) method.invoke(null, cmds, null, ".", null, true); inputStream = e.getInputStream();
} catch (ClassNotFoundException | NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } byte[] cache = new byte[1024]; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); int readLen = 0; while(true){ try { if (!((readLen = inputStream.read(cache)) != -1)) break; } catch (IOException e) { e.printStackTrace(); } byteArrayOutputStream.write(cache, 0, readLen); } System.out.println(byteArrayOutputStream); } }
|
try catch中的内容是自动生成的
-
static变量赋值 前面学过 就不多说
-
final变量赋值
直接赋值
FinalPerson:
1 2 3 4 5 6 7 8 9 10
| package ReflectPlus.pojo;
public class FinalPerson { private final String name = "happySu"; public final int age = 18;
public void printInfo(){ System.out.println(name +" " + age); } }
|
FinalReflect:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package ReflectPlus.Service;
import java.lang.reflect.Field; import java.lang.reflect.Method;
public class FinalReflection { public static void main(String[] args){ try{ Class c = Class.forName("ReflectPlus.pojo.FinalPerson"); Object m = c.newInstance(); Method printMethod = c.getDeclaredMethod("printInfo"); printMethod.invoke(m);
Field nameField = c.getDeclaredField("name"); Field ageField = c.getDeclaredField("age");
nameField.setAccessible(true); ageField.setAccessible(true); System.out.println("================"); nameField.set(m,"111"); ageField.set(m,12);
printMethod.invoke(m); }catch (Exception e){ e.printStackTrace(); } } }
|
但是根本无法修改成功 永远18!
Person:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package ReflectPlus.pojo;
public class InDirectPerson { private final StringBuilder sex = new StringBuilder("male"); public final int age = (null != null ? 18 : 18);
private final String name; public InDirectPerson(){ name = "happy"; } public void printInfo(){ System.out.println(name + " " + age + " " + sex); } }
|
Reflect:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package ReflectPlus.Service;
import java.lang.reflect.Field; import java.lang.reflect.Method;
public class InDirectReflect { public static void main(String[] args){ try{ Class c = Class.forName("ReflectPlus.pojo.InDirectPerson"); Object m = c.newInstance(); Method printMethod = c.getDeclaredMethod("printInfo"); printMethod.invoke(m);
System.out.println("=================");
Field nameField = c.getDeclaredField("name"); Field ageField = c.getDeclaredField("age"); Field sexField = c.getDeclaredField("sex");
nameField.setAccessible(true); ageField.setAccessible(true); sexField.setAccessible(true); nameField.set(m, "newhappy"); ageField.set(m,180); sexField.set(m,new StringBuilder("female")); printMethod.invoke(m);
}catch(Exception e){ e.printStackTrace(); }
}
}
|
直接成功
一点点想法:
这样看来能否修改成功的关键 不在于我们Reflect类是怎么写怎么构造的,而是Person类本身的情况
Person:
1 2 3 4 5 6 7 8 9 10 11 12
| package ReflectPlus.pojo;
public class StaticFinalPerson { static final StringBuilder name = new StringBuilder("happySu");
public void printInfo(){ System.out.println(name); }
}
|
Reflect:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package ReflectPlus.Service;
import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier;
public class StaticFinalReflect { public static void main(String[] args){ try{ Class c = Class.forName("ReflectPlus.pojo.StaticFinalPerson"); Object m = c.newInstance(); Method printMethod = c.getDeclaredMethod("printInfo"); printMethod.invoke(m);
Field nameField = c.getDeclaredField("name"); nameField.setAccessible(true); Field nameModifyField = nameField.getClass().getDeclaredField("modifiers"); nameModifyField.setAccessible(true); nameModifyField.setInt(nameField, nameField.getModifiers() & ~Modifier.FINAL);
nameField.set(m, new StringBuilder("newhappy"));
nameModifyField.setInt(nameField, nameField.getModifiers() & ~Modifier.FINAL); printMethod.invoke(m);
}catch(Exception e){ e.printStackTrace(); }
}
}
|
在原始情况下 是无法利用的
报错解决
看到无法调用private的变量 发现修改的时候粗心了
成功