浅谈CVE-2022-22965漏洞成因(二)

admin 2022年6月30日01:55:34浅谈CVE-2022-22965漏洞成因(二)已关闭评论262 views字数 21730阅读72分26秒阅读模式

前言:记录一篇自己入门java安全的故事,捋一下思路,轻量知识 ,重在调试 !

.

这篇文章四个部分:

引入篇:整理一下CVE-2022-22965漏洞的来龙去脉

基础篇:回顾Java中一些基础的内容

调试篇:阅读Spring MVC部分源码

分析篇:分析篇:分析CVE-2010-1622、CVE-2022-22965的漏洞成因

.

基础篇

( 紧接 "浅谈CVE-2022-22965漏洞成因(一)",回顾一些后面分析程序时要用到的Java基础 )

1、Java Bean

Java中的Bean是一种特殊的类,用来封装数据,传递信息,下面给出一个Bean:

```
public class Person {
private String name;
private int age;
private Boolean student;

public String getName() {
    return name;
}

public int getAge() {
    return age;
}

public Boolean isStudent() {
    return student;
}

public void setName(String name) {
    this.name = name;
}

public void setAge(int age) {
    this.age = age;
}

public void setStudent(Boolean student) {
    this.student = student;
}

}
```

  • “类”这个概念很好理解,直白的说就是有“class”关键字修饰
  • 封装的数据可以理解为定义了一些私有属性,如, private关键字修饰的变量
  • 传递信息的过程则指Bean被调用并通过Bean内的公共方法或getter/setter访问Bean属性的过程
  • Bean是特殊的类可以表现在Bean属性与Bean的getter/setter方法相互对应
    如果一个属性为abc,那么相对应的getter/setter方法就是:
  • ( 公式:getter/setter方法+首字母大字的属性abc )

getAbc() 和 setAbc()

特殊的,布尔型变量形如 boolean student,对应的getter/setter方法分别为:

isStudent() 和 setStudent

更多举例:

java
String name
getName()
setName(String name)
===================================
int age
getAge()
setAge(int age)
===================================
Boolean student;
getStudent()
isStudent(Boolean student)

2、BeanInfo

BeanInfo是JDK自带的Java.Beans包下的一个接口,根据官方的描述,BeanInfo通过Bean属性( properties )、事件( events )和其他特殊特性( features )来实现对一个已经实例化类的准确描述,下面给出一个BeanInfo的完整结构:

```

仅需关注我标注的地方

public interface BeanInfo {

获取一个Bean的整体信息

BeanDescriptor getBeanDescriptor();

获取一个Bean的所有事件的描述信息

EventSetDescriptor[] getEventSetDescriptors();

int getDefaultEventIndex();

获取一个Bean的所有属性的描述信息

PropertyDescriptor[] getPropertyDescriptors();

int getDefaultPropertyIndex();

获取一个Bean的所有方法的描述信息

MethodDescriptor[] getMethodDescriptors();

BeanInfo[] getAdditionalBeanInfo();
Image getIcon(int iconKind);
static final int ICON_COLOR_16x16 = 1;
static final int ICON_COLOR_32x32 = 2;
static final int ICON_MONO_16x16 = 3;
static final int ICON_MONO_32x32 = 4;

}

```

对于一个Java应用的开发人员来说,可以通过实现该接口的方法来定制自己需要的BeanInfo,这个我们在调试Spring MVC 的过程中也有所涉及。

3、PropertyDescriptor

PropertyDescriptor即属性描述器,顾名思义,这个类完整的描述了一个属性的所有信息,PropertyDescriptor继承自FeatureDescriptor:

```
public class PropertyDescriptor {

private final MethodRef readMethodRef = new MethodRef();
private final MethodRef writeMethodRef = new MethodRef();
private Reference<? extends Class<?>> propertyEditorClassRef;

private boolean bound;
private boolean constrained;

private String baseName;

private String writeMethodName;
private String readMethodName;

.......
设置PropertyDescriptor属性的方法(包括getter/setter)
.......

}
```

这里我们仅需要知道,PropertyDescriptor本身描述了一个Bean属性的可读可写权限,一个Bean属性是否可读或可最终是通过Java Bean的getter/setter方法来实的,但getter/setter方法的调用则是通过给Method类传参PropertyDescripto后调用反射实现的

4、Introspector

浅谈CVE-2022-22965漏洞成因(二)
Introspector同样是JDK自带的Java.Beans包下的一个类,Introspector就是内省,通过Introspector类提供的方法,我们可以完整的获取到目标 Java Bean 的属性、事件和方法,即BeanInfo,官方原版的描述如下:

The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.For each of those three kinds of information, the Introspector will separately analyze the bean's class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean.For each class "Foo", explicit information may be available if there exists a corresponding "FooBeanInfo" class that provides a non-null value when queried for the information. We first look for the BeanInfo class by taking the full package-qualified name of the target bean class and appending "BeanInfo" to form a new class name. If this fails, then we take the final classname component of this name, and look for that class in each of the packages specified in the BeanInfo package search path.Thus for a class such as "sun.xyz.OurButton" we would first look for a BeanInfo class called "sun.xyz.OurButtonBeanInfo" and if that failed we'd look in each package in the BeanInfo search path for an OurButtonBeanInfo class. With the default search path, this would mean looking for "sun.beans.infos.OurButtonBeanInfo".If a class provides explicit BeanInfo about itself then we add that to the BeanInfo information we obtained from analyzing any derived classes,but we regard the explicit information as being definitive for the current class and its base classes, and do not proceed any further up the superclass chain.If we don't find explicit BeanInfo on a class, we use low-level reflection to study the methods of the class and apply standard design patterns to identify property accessors, event sources, or public methods. We then proceed to analyze the class's superclass and add in the information from it (and possibly on up the superclass chain).

翻译过来大意就是通过内省获取Bean属性时,会先尝试按默认的规则找找是否存在现成的目标的BeanInfo,如果不存在,最后会递归解析并调用反射来尽可能构造一个完整的目标BeanInfo,常用到的方法如下:

浅谈CVE-2022-22965漏洞成因(二)

浅谈CVE-2022-22965漏洞成因(二)

更多详情,参考官方文档:https://docs.oracle.com/javase/8/docs/api/

归纳下来后,有两类,一类不能设立解析Bean属性时停止的位置,一类可以设立解析Bean属性时停止的位置:

  • BeanInfo getBeanInfo(Class beanClass)
  • BeanInfo getBeanInfo(Class beanClass, Class stopClass)

我们用第二种(设立解析时停止位置)来获取一下Person类的属性(Person类,参上)

```java
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

public class Main {
public static void main(String[] args) throws Exception {
//获取Person类所有的属性
BeanInfo info = Introspector.getBeanInfo(Person.class,Object.class);

    //遍历Person类所有的属性
    PropertyDescriptor[] properties =
            info.getPropertyDescriptors();
    for (PropertyDescriptor pd : properties) {
        System.out.println("Property: " + pd.getName());

    }
}

}
```

上面的代码运行后,成功获取到的Person类的所有属性,这与实际的Person类中的情况相符:

(原Person类)

浅谈CVE-2022-22965漏洞成因(二)
(运行后)

浅谈CVE-2022-22965漏洞成因(二)
我们再用第一种(不设立解析时停止位置)来获取一下Person类的属性(Person类,参上)

浅谈CVE-2022-22965漏洞成因(二)

浅谈CVE-2022-22965漏洞成因(二)
此时就会发现,Student里虽然没有定义class属性,但在通过Introspector.getBeanInfo方法解析并获取Student类BeanInfo的PropertyDescriptor时,莫名多出了一个class属性。 原因就在于Object是Java 类中所用类的超类,而Object类里有一个getClass()方法,因此导致递归解析到父类时便会多获取到了一个Bean的Property。

浅谈CVE-2022-22965漏洞成因(二)
这里就可以抛出一个疑问:

为什么Object类存在一个getClass()方法Student类的PropertyDescriptors就要多一个class属性?

获取一个Bean的属性,最直观的办法我们都能想到,就是调用Bean的getter/setter方法,因此如果能批量调取Bean的所有getter/setter方法就能获取到Bean的所有属性。

并且,这样做比直接访问Bean属性更容易实现,因为getter/setter方法有固定的首格式,且与Bean属性对照,而单一的Bean属性名却没有统一的规律。

但是Introspector.getBeanInfo一个目标类,实际并不是直接批量调用了Bean的getter/setter方法,而是通过推导实现的

按照Ruilin师傅的说法,Introspector.getBeanInfo一个目标类,直接通过getter/setter方法的命名规则就能获得一个Bean的各种属性。

也就是说,目标Bean里有getter或setter方法的任意一个,Introspector.getBeanInfo时就会默认认为存在一个相对应的Bean属性。

再者,由于Introspector本身在获取BeanInfo时存在"尽可能完整的"的特性,因此递归解析到了Object并从它的getClass()方法中解析出了一个class属性,最后封装到目标的BeanInfo里。

这里我们可以通过几个例子粗浅的感受一下这个过程:

第一组:删掉name、age、student三个属性,保留三个属性对应的getter/setter方法,修改这些getter/setter内容为空

```java
public class Person {

public String getName() {
    return null;
}

public int getAge() {
    return 0;
}

public Boolean isStudent() {
    return null;
}

public void setName(String name) {

}

public void setAge(int age) {

}

public void setStudent(Boolean student) {

}

}
```

第二组:在第一组的基础上删除所有setter方法

```java
public class Person {

public String getName() {
    return null;
}

public int getAge() {
    return 0;
}

public Boolean isStudent() {
    return null;
}

}
```

第三组:在第一组的基础上删除所有getter方法

```java
public class Person {

public void setName(String name) {

}

public void setAge(int age) {

}

public void setStudent(Boolean student) {

}

}
```

运行、遍历Person类后,最后的结果无一例外,依然是上面提到的三个属性

浅谈CVE-2022-22965漏洞成因(二)
第四组:直接对Object作内省

浅谈CVE-2022-22965漏洞成因(二)

5、Java反射机制

Java反射就是借用Java中内置的反射库使编写的Java程序具有了动态的操作Java类的能力,具体表现在利用Java反射机制我们可以:

  • 在Java程序运行中分析一个类
  • 在运行中查看对象
  • 使用Method对象 等

.

我们先来看看反射库是什么(不同jdk版本的反射库略有不同,这里我们对比着看一下)

.

rt.jar是jre/lib下的一个运行时库,这个包会在JVM环境启动时被加载,rt.jar包含了我们最熟悉的java.lang包,下面分别打印出jdk8和jdk11的lang包结构:

jdk 1.8

java
java.lang
AbstractMethodError.java
AbstractStringBuilder.java
annotation
   AnnotationFormatError.java
   Annotation.java
   AnnotationTypeMismatchException.java
   Documented.java
   ElementType.java
   IncompleteAnnotationException.java
   Inherited.java
   Native.java
   package-info.java
   Repeatable.java
   Retention.java
   RetentionPolicy.java
   Target.java
Appendable.java
ApplicationShutdownHooks.java
ArithmeticException.java
ArrayIndexOutOfBoundsException.java
ArrayStoreException.java
AssertionError.java
AssertionStatusDirectives.java
AutoCloseable.java
Boolean.java
BootstrapMethodError.java
Byte.java
CharacterData00.java
CharacterData01.java
CharacterData02.java
CharacterData0E.java
CharacterData.java
CharacterDataLatin1.java
CharacterDataPrivateUse.java
CharacterDataUndefined.java
Character.java
CharacterName.java
CharSequence.java
ClassCastException.java
ClassCircularityError.java
ClassFormatError.java
Class.java
ClassLoaderHelper.java
ClassLoader.java
ClassNotFoundException.java
ClassValue.java
Cloneable.java
CloneNotSupportedException.java
Comparable.java
Compiler.java
ConditionalSpecialCasing.java
Deprecated.java
Double.java
EnumConstantNotPresentException.java
Enum.java
Error.java
ExceptionInInitializerError.java
Exception.java
Float.java
FunctionalInterface.java
IllegalAccessError.java
IllegalAccessException.java
IllegalArgumentException.java
IllegalMonitorStateException.java
IllegalStateException.java
IllegalThreadStateException.java
IncompatibleClassChangeError.java
IndexOutOfBoundsException.java
InheritableThreadLocal.java
InstantiationError.java
InstantiationException.java
instrument
   ClassDefinition.java
   ClassFileTransformer.java
   IllegalClassFormatException.java
   Instrumentation.java
   UnmodifiableClassException.java
Integer.java
InternalError.java
InterruptedException.java
invoke
   AbstractValidatingLambdaMetafactory.java
   BoundMethodHandle.java
   CallSite.java
   ConstantCallSite.java
   DelegatingMethodHandle.java
   DirectMethodHandle.java
   DontInline.java
   ForceInline.java
   InfoFromMemberName.java
   InjectedProfile.java
   InnerClassLambdaMetafactory.java
   InvokeDynamic.java
   InvokerBytecodeGenerator.java
   Invokers.java
   LambdaConversionException.java
   LambdaFormBuffer.java
   LambdaFormEditor.java
   LambdaForm.java
   LambdaMetafactory.java
   MemberName.java
   MethodHandleImpl.java
   MethodHandleInfo.java
   MethodHandle.java
   MethodHandleNatives.java
   MethodHandleProxies.java
   MethodHandles.java
   MethodHandleStatics.java
   MethodTypeForm.java
   MethodType.java
   MutableCallSite.java
   package-info.java
   ProxyClassesDumper.java
   SerializedLambda.java
   SimpleMethodHandle.java
   Stable.java
   SwitchPoint.java
   TypeConvertingMethodAdapter.java
   VolatileCallSite.java
   WrongMethodTypeException.java
Iterable.java
LinkageError.java
Long.java
management
   BufferPoolMXBean.java
   ClassLoadingMXBean.java
   CompilationMXBean.java
   GarbageCollectorMXBean.java
   LockInfo.java
   ManagementFactory.java
   ManagementPermission.java
   MemoryManagerMXBean.java
   MemoryMXBean.java
   MemoryNotificationInfo.java
   MemoryPoolMXBean.java
   MemoryType.java
   MemoryUsage.java
   MonitorInfo.java
   OperatingSystemMXBean.java
   PlatformComponent.java
   PlatformLoggingMXBean.java
   PlatformManagedObject.java
   RuntimeMXBean.java
   ThreadInfo.java
   ThreadMXBean.java
Math.java
NegativeArraySizeException.java
NoClassDefFoundError.java
NoSuchFieldError.java
NoSuchFieldException.java
NoSuchMethodError.java
NoSuchMethodException.java
NullPointerException.java
NumberFormatException.java
Number.java
Object.java
OutOfMemoryError.java
Override.java
package-info.java
Package.java
ProcessBuilder.java
ProcessEnvironment.java
ProcessImpl.java
Process.java
Readable.java
ref
   FinalizerHistogram.java
   Finalizer.java
   FinalReference.java
   PhantomReference.java
   Reference.java
   ReferenceQueue.java
   SoftReference.java
   WeakReference.java
reflect
   AccessibleObject.java
   AnnotatedArrayType.java
   AnnotatedElement.java
   AnnotatedParameterizedType.java
   AnnotatedType.java
   AnnotatedTypeVariable.java
   AnnotatedWildcardType.java
   Array.java
   Constructor.java
   Executable.java
   Field.java
   GenericArrayType.java
   GenericDeclaration.java
   GenericSignatureFormatError.java
   InvocationHandler.java
   InvocationTargetException.java
   MalformedParameterizedTypeException.java
   MalformedParametersException.java
   Member.java
   Method.java
   Modifier.java
   package-info.java
   ParameterizedType.java
   Parameter.java
   Proxy.java
   ReflectAccess.java
   ReflectPermission.java
   Type.java
   TypeVariable.java
   UndeclaredThrowableException.java
   WeakCache.java
   WildcardType.java
ReflectiveOperationException.java
Runnable.java
RuntimeException.java
Runtime.java
RuntimePermission.java
SafeVarargs.java
SecurityException.java
SecurityManager.java
Short.java
Shutdown.java
StackOverflowError.java
StackTraceElement.java
StrictMath.java
StringBuffer.java
StringBuilder.java
StringCoding.java
StringIndexOutOfBoundsException.java
String.java
SuppressWarnings.java
System.java
Terminator.java
ThreadDeath.java
ThreadGroup.java
Thread.java
ThreadLocal.java
Throwable.java
TypeNotPresentException.java
UnknownError.java
UnsatisfiedLinkError.java
UnsupportedClassVersionError.java
UnsupportedOperationException.java
VerifyError.java
VirtualMachineError.java
Void.java

jdk 11

java.lang
AbstractMethodError.java
AbstractStringBuilder.java
annotation
   AnnotationFormatError.java
   Annotation.java
   AnnotationTypeMismatchException.java
   Documented.java
   ElementType.java
   IncompleteAnnotationException.java
   Inherited.java
   Native.java
   package-info.java
   Repeatable.java
   Retention.java
   RetentionPolicy.java
   Target.java
Appendable.java
ApplicationShutdownHooks.java
ArithmeticException.java
ArrayIndexOutOfBoundsException.java
ArrayStoreException.java
AssertionError.java
AssertionStatusDirectives.java
AutoCloseable.java
Boolean.java
BootstrapMethodError.java
Byte.java
CharacterData00.java
CharacterData01.java
CharacterData02.java
CharacterData0E.java
CharacterData.java
CharacterDataLatin1.java
CharacterDataPrivateUse.java
CharacterDataUndefined.java
Character.java
CharacterName.java
CharSequence.java
ClassCastException.java
ClassCircularityError.java
ClassFormatError.java
Class.java
ClassLoaderHelper.java
ClassLoader.java
ClassNotFoundException.java
ClassValue.java
Cloneable.java
CloneNotSupportedException.java
Comparable.java
Compiler.java
ConditionalSpecialCasing.java
Deprecated.java
Double.java
EnumConstantNotPresentException.java
Enum.java
Error.java
ExceptionInInitializerError.java
Exception.java
FdLibm.java
Float.java
FunctionalInterface.java
IllegalAccessError.java
IllegalAccessException.java
IllegalArgumentException.java
IllegalCallerException.java
IllegalMonitorStateException.java
IllegalStateException.java
IllegalThreadStateException.java
IncompatibleClassChangeError.java
IndexOutOfBoundsException.java
InheritableThreadLocal.java
InstantiationError.java
InstantiationException.java
Integer.java
InternalError.java
InterruptedException.java
invoke
   AbstractConstantGroup.java
   AbstractValidatingLambdaMetafactory.java
   BootstrapCallInfo.java
   BootstrapMethodInvoker.java
   BoundMethodHandle.java
   CallSite.java
   ClassSpecializer.java
   ConstantBootstraps.java
   ConstantCallSite.java
   ConstantGroup.java
   DelegatingMethodHandle.java
   DirectMethodHandle.java
   GenerateJLIClassesHelper.java
   InfoFromMemberName.java
   InjectedProfile.java
   InnerClassLambdaMetafactory.java
   InvokeDynamic.java
   InvokerBytecodeGenerator.java
   Invokers.java
   LambdaConversionException.java
   LambdaFormBuffer.java
   LambdaFormEditor.java
   LambdaForm.java
   LambdaMetafactory.java
   MemberName.java
   MethodHandleImpl.java
   MethodHandleInfo.java
   MethodHandle.java
   MethodHandleNatives.java
   MethodHandleProxies.java
   MethodHandles.java
   MethodHandleStatics.java
   MethodTypeForm.java
   MethodType.java
   MutableCallSite.java
   package-info.java
   ProxyClassesDumper.java
   SerializedLambda.java
   SimpleMethodHandle.java
   StringConcatException.java
   StringConcatFactory.java
   SwitchPoint.java
   TypeConvertingMethodAdapter.java
   VarForm.java
   VarHandleBooleans.java
   VarHandleByteArrayAsChars.java
   VarHandleByteArrayAsDoubles.java
   VarHandleByteArrayAsFloats.java
   VarHandleByteArrayAsInts.java
   VarHandleByteArrayAsLongs.java
   VarHandleByteArrayAsShorts.java
   VarHandleByteArrayBase.java
   VarHandleBytes.java
   VarHandleChars.java
   VarHandleDoubles.java
   VarHandleFloats.java
   VarHandleGuards.java
   VarHandleInts.java
   VarHandle.java
   VarHandleLongs.java
   VarHandleObjects.java
   VarHandleShorts.java
   VarHandles.java
   VolatileCallSite.java
   WrongMethodTypeException.java
Iterable.java
LayerInstantiationException.java
LinkageError.java
LiveStackFrameInfo.java
LiveStackFrame.java
Long.java
Math.java
module
   Configuration.java
   FindException.java
   InvalidModuleDescriptorException.java
   ModuleDescriptor.java
   ModuleFinder.java
   ModuleReader.java
   ModuleReference.java
   package-info.java
   ResolutionException.java
   ResolvedModule.java
   Resolver.java
Module.java
ModuleLayer.java
NamedPackage.java
NegativeArraySizeException.java
NoClassDefFoundError.java
NoSuchFieldError.java
NoSuchFieldException.java
NoSuchMethodError.java
NoSuchMethodException.java
NullPointerException.java
NumberFormatException.java
Number.java
Object.java
OutOfMemoryError.java
Override.java
package-info.java
Package.java
ProcessBuilder.java
ProcessEnvironment.java
ProcessHandleImpl.java
ProcessHandle.java
ProcessImpl.java
Process.java
PublicMethods.java
Readable.java
ref
   Cleaner.java
   FinalizerHistogram.java
   Finalizer.java
   FinalReference.java
   package-info.java
   PhantomReference.java
   Reference.java
   ReferenceQueue.java
   SoftReference.java
   WeakReference.java
reflect
   AccessibleObject.java
   AnnotatedArrayType.java
   AnnotatedElement.java
   AnnotatedParameterizedType.java
   AnnotatedType.java
   AnnotatedTypeVariable.java
   AnnotatedWildcardType.java
   Array.java
   Constructor.java
   Executable.java
   Field.java
   GenericArrayType.java
   GenericDeclaration.java
   GenericSignatureFormatError.java
   InaccessibleObjectException.java
   InvocationHandler.java
   InvocationTargetException.java
   MalformedParameterizedTypeException.java
   MalformedParametersException.java
   Member.java
   Method.java
   Modifier.java
   package-info.java
   ParameterizedType.java
   Parameter.java
   ProxyGenerator.java
   Proxy.java
   ReflectAccess.java
   ReflectPermission.java
   Type.java
   TypeVariable.java
   UndeclaredThrowableException.java
   WildcardType.java
ReflectiveOperationException.java
Runnable.java
RuntimeException.java
Runtime.java
RuntimePermission.java
SafeVarargs.java
SecurityException.java
SecurityManager.java
Short.java
Shutdown.java
StackFrameInfo.java
StackOverflowError.java
StackStreamFactory.java
StackTraceElement.java
StackWalker.java
StrictMath.java
StringBuffer.java
StringBuilder.java
StringCoding.java
StringConcatHelper.java
StringIndexOutOfBoundsException.java
String.java
StringLatin1.java
StringUTF16.java
SuppressWarnings.java
System.java
Terminator.java
ThreadDeath.java
ThreadGroup.java
Thread.java
ThreadLocal.java
Throwable.java
TypeNotPresentException.java
UnknownError.java
UnsatisfiedLinkError.java
UnsupportedClassVersionError.java
UnsupportedOperationException.java
VerifyError.java
VersionProps.java
VirtualMachineError.java
Void.java
WeakPairMap.java

我们再在java.lang包下找到reflect库,并对比一下不同版本的区别:

浅谈CVE-2022-22965漏洞成因(二)

浅谈CVE-2022-22965漏洞成因(二)
基本上都差不多,java.lang.reflect包就是Java为我们提供的反射库

.

再者,通过上图,我们可以发现在java.lang包下都有一个Class.java

.

前面我们有提到,通过java反射我们可以在java程序运行时动态的分析一个类,而这个动态分析一个类的过程就离不开这个 Class.java。也就是说通过java反射动态的分析一个类离不开java.lang包下的 Class.java

我们知道,一个编写的Java代码会保存成 b,而这种 demo.java格式是不能直接被JVM虚拟机运行的,需要先将 demo.java编译成 demo.class后才能被JVM虚拟机运行。

.

这种 .class格式的文件就是字节码文件,里面是二进制内容。当demo.class被加载进内存并生成一个demo对象时,同时也会加载Class.java并生成一个Class对象用于管理demo对象。换言之,也就是说通过Class这个对象,我们可以获得demo对象对象的完整信息。

.

要理解这个过程我们需要先来了解一下Java代码的执行时过程,见下图:

浅谈CVE-2022-22965漏洞成因(二)

可以归纳为如下这几个关键点:

  • Java代码编写后要编译成 .class文件
  • .class文件是字节码,可加密,可用不同语言实现,是Java跨平台的关键
  • JVM执行Java程序功能仅仅是通过解析 .class 文件实现的
  • JDK中内置 Class 类 实现了对 .class 文件的描述与管理
  • Object类是所有类的超类,Class类则可以说是所有运行时类的超类
  • new 一个对象的过程可以理解为加载 .class 文件并在内存中创建对象的过程
  • 内存中,多个People类的实例化对象只能有一个与People类相关联的Class类的实例化对象
  • 通过内存中的Class对象我们不仅可以实现People类的操作,还能实现与Class类相关的Method类、Constructor类的操作,也就是真正的反射

再者,通过Class.java导入的包头,我们也应该知道,java反射与Class.java密不可分,但严格来说Class.java并不属于反射的范畴,因为它不在反射库中,但是Class.java中大量的使用了反射库的功能。

jdk1.8 Class.java引入了反射库:

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Member;
import java.lang.reflect.Field;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.AnnotatedType;
import java.lang.ref.SoftReference;
import java.io.InputStream;
import java.io.ObjectStreamField;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
import sun.misc.Unsafe;
import sun.reflect.CallerSensitive;
import sun.reflect.ConstantPool;
import sun.reflect.Reflection;
import sun.reflect.ReflectionFactory;
import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.repository.ClassRepository;
import sun.reflect.generics.repository.MethodRepository;
import sun.reflect.generics.repository.ConstructorRepository;
import sun.reflect.generics.scope.ClassScope;
import sun.security.util.SecurityConstants;
import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;
import sun.reflect.annotation.*;
import sun.reflect.misc.ReflectUtil;

既然Class对象如此重要,我们先来了解一下获取Class对象的方法,一共有三个:

1.使用forName方法获取class对象(最常用且最好用的方法)

Class pClass= Class.forName("pojo.People")

该方法是一个静态方法,属于Class 类本身,不受是否实例化一个类对象的影响,仅仅需要在forName()方法里传入一个类的具体包路径就能获取到该类的class对象

浅谈CVE-2022-22965漏洞成因(二)
Class.forName方法的实现

```
Class

@CallerSensitive
public static Class<?> forName(String className)throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

private static native Class<?> forName0(String name, boolean initialize,ClassLoader loader, Class<?> caller)throws ClassNotFoundException;

reflect

@CallerSensitive
public static native Class<?> getCallerClass();
```

也就是说Class.forName方法最终是通过调用反射的reflect.getCallerClass来实现获取一个类对象的Class对象的。

而最终的反射的具体实现我们是无需关注的,因为native关键字修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在其他语言实现的文件中(如C和C++),Java通过JNI接口来封装了底层实现。

2.使用Object.getClass方法获取class对象

```java

通过new关键字产生People对象和Class对象

People people = new People();
Class pClass = people.getClass();
```

3.使用class属性获取class对象

Class pClass = People.class;

class属性是一个静态属性,静态的属性可以被所有相关对象共享,且任何的数据类型都有class属性,结合下面的图我们就很好理解这个class属性

浅谈CVE-2022-22965漏洞成因(二)
我们总结一下这以上三种方法获取class对象的特点:

浅谈CVE-2022-22965漏洞成因(二)
最后谈一下反射,反射就是获取到内存中student1这个Student类的实例对象的Class对象后通过反射库操作Student类的各种构造方法、属性域、公有私有方法等。

.

直接看一个实例,理解如何通过反射调用计算器就能理解什么是Java反射

java
//先通过反射获取到了java.lang.Runtime对象的Class对象,即clazz
Class clazz = Class.forName("java.lang.Runtime");
//java.lang.Runtime里面有exec方法,我们直接通过clazz去调用反射库的Method方法去拿exec方法(记得将参数类型传入)
//再用invoke方法去执行(记得传入调用对象和参数)
//而获取调用对象时又用了一次反射
clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke("java.lang.Runtime"),"calc.exe");

浅谈CVE-2022-22965漏洞成因(二)

浅谈CVE-2022-22965漏洞成因(二)

浅谈CVE-2022-22965漏洞成因(二)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月30日01:55:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   浅谈CVE-2022-22965漏洞成因(二)http://cn-sec.com/archives/1148878.html