本科畢設作過Python的RASP以後,對這項技術頗有興趣,當時OpenRASP開始出現,而且Java的實現很是接近真正的運行時防護的概念。一直沒有時間和足夠的動力學習Java,最近一口氣學了很多Java相關的東西,準備從反序列化和RASP兩個方向繼續深刻學一下Java。這邊筆記主要也是記錄整個學習過程,目標是仿照OpenRASP的java實現,完成一個Java的RASP。html
javaagent是java命令提供的一個參數,這個參數能夠指定一個jar包,在真正的程序沒有運行以前先運行指定的jar包。而且對jar包有兩個要求:java
這個premain方法會在java命令行指定的main函數以前運行。c++
在java命令參數種,還能夠看到其它參數,例如apache
-agentlib:<libname>[=<選項>] 加載本機代理庫 <libname>, 例如 -agentlib:hprof 另請參閱 -agentlib:jdwp=help 和 -agentlib:hprof=help -agentpath:<pathname>[=<選項>] 按完整路徑名加載本機代理庫 -javaagent:<jarpath>[=<選項>] 加載 Java 編程語言代理, 請參閱 java.lang.instrument
javaagent能夠指定不少個,jvm會依次執行不一樣的jar。前面提到的premain方法有兩種定義方式編程
public static void premain(String agentArgs, Instrumentation inst) public static void premain(String agentArgs)
根據sun.instrument.InstrumentationImpl 的源代碼,能夠知道,會優先調用第一種寫法。這種方法能夠在JDK1.5及以後的版本使用jvm
使用javaagent須要幾個步驟:maven
在premain方法執行時,獲取的Instrumentation對象還會加載大部分類,包括後面main方法執行時須要加載的各類類,可是抓不到系統類。也就是說,在這個位置在main方法執行前,就能夠攔截或者重寫類,結合ASM、javassist、cglib方式就能夠實現對類的改寫或者插樁。編程語言
如今來實現一下,目錄結構以下ide
-java-agent ----src ----|----main ----|----------java ----|--------------com ----|-------------------bitterz ----|----------------------PreMain ----|pom.xml
pom.xml使用idea建立maven項目自帶的pom.xml便可,而後加入以下配置函數
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifestEntries> <Premain-Class>com.bitterz.PreMain</Premain-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build>
修改裏面的premain便可,這樣配置以後,直接使用idea的maven->package就能夠打包成一個可使用的agent.jar。
com.bitterz.PreMain以下:
package com.bitterz; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; public class PreMain { public static void premain(String agentArgs, Instrumentation inst){ System.out.println("agentArgs:" + agentArgs); inst.addTransformer(new DefineTransformer(), true); } static class DefineTransformer implements ClassFileTransformer{ @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { System.out.println("premain load Class: " + className); // 注意這裏的輸出 return classfileBuffer; } } }
而後再建立一個要執行的main
package com.bitterz; public class Main { public static void main(String[] args) { System.out.println("Main.main() in test project"); } }
一樣修改pom.xml配置,只須要再<manifestEntries>
標籤下添加一個<Main-Class>
便可用idea的maven打包成一個jar,而且指定了main類。
兩個項目用maven打包後,在命令行執行一下
能夠看到premain先輸出了加載的各類類,包括com.bitterz.Main,而後纔是真正的main執行,最後結束時,premain還加載了一些結束時須要的類。到此,在啓動main方法前,實現對後續類的加載或進一步修改操做,已經有了雛形
前面的方法須要在main函數啓動前,執行agent,但有些時候,jvm已經啓動了,並且服務不能輕易暫停,但這個時候仍是想對jvm中的類作一些修改應該怎麼辦呢?
這就要引入attch機制了,jdk1.6以後在Instrumentation中添加了一種agentmain的代理方法,能夠在main函數執行以後再運行。和premain函數同樣,開發者能夠編寫一個包含agentmain函數的Java類,它也有兩種寫法:
public static void agentmain (String agentArgs, Instrumentation inst) public static void agentmain (String agentArgs)
一樣的,帶有Instrumentation的方法會被優先調用,開發者必須再MANIFEST.MF文件中設置Agent-Class
來指定包含agentmain函數的類。
這種attach機制的具體實如今com.sun.tools.attach
中,有以下兩個類:
VirtualMachine
字面意義表示一個Java 虛擬機,也就是程序須要監控的目標虛擬機,提供了獲取系統信息(好比獲取內存dump、線程dump,類信息統計(好比已加載的類以及實例個數等), loadAgent,Attach 和 Detach (Attach 動做的相反行爲,從 JVM 上面解除一個代理)等方法,能夠實現的功能能夠說很是之強大 。該類容許咱們經過給attach方法傳入一個jvm的pid(進程id),遠程鏈接到jvm上
代理類注入操做只是它衆多功能中的一個,經過loadAgent
方法向jvm註冊一個代理程序agent,在該agent的代理程序中會獲得一個Instrumentation實例,該實例能夠 在class加載前改變class的字節碼,也能夠在class加載後從新加載。在調用Instrumentation實例的方法時,這些方法會使用ClassFileTransformer接口中提供的方法進行處理。
VirtualMachineDescriptor
則是一個描述虛擬機的容器類,配合 VirtualMachine 類完成各類功能
具體實現過程:經過VirtualMachine類的attach(pid)
方法,即可以attach到一個運行中的java進程上,以後即可以經過loadAgent(agentJarPath)
來將agent的jar包注入到對應的進程,而後對應的進程會調用agentmain方法。
從jdk根目錄的lib/tools.jar源碼一路追蹤了一下VirtualMachine.attach方法,發現傳入一個pid以後,在Windows下會經過WindowsVirtualMachine
這個類的構造函數,調用native方法,實現對jvm進程的attach
底層方法還得靠c/c++來實現(滑稽),瞭解這個機制以後,回到前面的agentmain的實現流程。首先啓動一個一直運行的jvm
package com.bitterz; public class Main { public static void main(String[] args) throws InterruptedException { System.out.println("Main.main() in test project start!!"); Thread.sleep(300000000); System.out.println("Main.main() in test project end!!"); } }
啓動以後,把再寫一個agentmain,而且還要寫好MANIFEST.MF文件配置,代碼和pom.xml以下:
package com.bitterz; import java.lang.instrument.Instrumentation; public class AgentMain { public static void agentmain(String agentArgs, Instrumentation instrumentation) { System.out.println("agentmain start!"); System.out.println(instrumentation.toString()); } }
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifestEntries> <Agent-Class>com.bitterz.AgentMain</Agent-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build>
使用maven package打包成一個jar文件便可
再開啓動另外一個java程序,使用進程號attach到前面一直運行的jvm,並使用loadAgent給這個jvm添加代理jar:
package com.bitterz.attach; import com.sun.tools.attach.AgentInitializationException; import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.VirtualMachine; import java.io.IOException; public class AttachTest { public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException { VirtualMachine attach = VirtualMachine.attach("12244"); // 命令行找到這個jvm的進程號 attach.loadAgent("C:\\Users\\helloworld\\Desktop\\java learn\\java-attach\\target\\java-attach-1.0-SNAPSHOT.jar"); attach.detach(); } }
運行這個java文件,會看到前面一直sleep運行的jvm會輸出agentmain裏面給定的輸出!
這裏也就說明,經過attach機制,咱們能夠對指定運行中的jvm添加agent,而在premain方法中獲取到Instrumentation對象,經過對Instrumentation對象添加transformer類,能夠實現類轉換(Class Transform),也就是在transform函數中結合修改字節碼的方法(ASM、Javassist、cglib等)能夠進一步實現RASP!
後續的文章將會寫一寫如何實現這些對指定類方法的Hook,以及如何運行時對底層函數的參數進行過濾。
http://www.javashuo.com/article/p-dzoqxtxo-gu.html
https://www.cnblogs.com/kendoziyu/p/maven-auto-build-javaagent-jar.html