11/11/2020 閱讀自:p牛 “Java 安全漫談 - 01.反射篇(1)”
反射是大多數(shù)語(yǔ)言必不可少的部分,對(duì)象可通過(guò)反射獲取其他的類,類可以通過(guò)反射拿到所有的方法(包括私有),拿到的方法可以調(diào)用。通過(guò)反射可以將 Java 這種靜態(tài)語(yǔ)言附加動(dòng)態(tài)特性。
理解動(dòng)態(tài)特性:一段代碼,改變其中的變量,將會(huì)導(dǎo)致這段代碼產(chǎn)生功能性的變化。
public void execute(String className, String methodName) throws Exception {
Class clazz = Class.forName(className);
clazz.getMethod(methodName).invoke(clazz.newInstance());
}
獲取類的方法:
forName實(shí)例化對(duì)象的方法:
newInstance獲取函數(shù)的方法:
getMethod執(zhí)行函數(shù)的方法:
invoke
獲取“類”的三個(gè)方法
-
obj.getClass():如果上下文存在某個(gè)類的實(shí)例obj那么我么可以直接通過(guò)obj.getClass()來(lái)獲取它的類 -
Test.class:如果你已經(jīng)加載了某個(gè)類,只是想獲取到它的java.lang.Class對(duì)象,那么就直接拿它的class屬性即可。這個(gè)方法其實(shí)不屬于反射 -
Class.forName:如果你知道某個(gè)類的名字,想獲取到這個(gè)類,就可以使用forName來(lái)獲取
//兩個(gè)重載函數(shù)
//className表示類名,第二個(gè)參數(shù)表示是否初始化,第三個(gè)參數(shù)就是ClassLoader(就是一個(gè)”加載器“,告訴JAVA虛擬機(jī)如何加載這個(gè)類,默認(rèn)的ClassLoader就是根據(jù)類名來(lái)加載類,這個(gè)類名是類完整路徑)
Class<?> forName(String name)
Class<?> forName(String name, **boolean** initialize, ClassLoader loader)
初始化可以理解為類的初始化

image.png
static {} 是類初始化的時(shí)候調(diào)用,{} 中的代碼會(huì)放在構(gòu)造函數(shù)的 super() 后面,但在當(dāng)前構(gòu)造函數(shù)內(nèi)容的前面。
一個(gè)簡(jiǎn)單的反射例子
如果存在一個(gè)函數(shù)ref如下,且name可控,那么我們可以構(gòu)造一個(gè)惡意類進(jìn)行調(diào)用執(zhí)行
//A.java
import static java.lang.Class.forName;
public class A {
public void ref(String name) throws Exception{
Class.forName(name);
}
public static void main(String[] args) throws Exception {
A a = new A();
a.ref("TouchFile");
}
}
//TouchFile.java
public class TouchFile {
static {
try{
System.out.println("this is `TouchFIle`");
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/success"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e){
System.out.println(e.getMessage());
}
}
}

image.png

image.png