压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

認識 JavaAgent——獲取目標進程已加載的所有類

作者:Longofo@知道創(chuàng)宇404實驗室

之前在一個應用中搜索到一個類,但是在反序列化測試的時出錯,錯誤不是class notfound,是其他0xxx這樣的錯誤,通過搜索這個錯誤大概是類沒有被加載。最近剛好看到了JavaAgent,初步學習了下,能進行攔截,主要通過Instrument Agent來進行字節(jié)碼增強,可以進行字節(jié)碼插樁,bTrace,Arthas?等操作,結(jié)合ASM,javassist,cglib框架能實現(xiàn)更強大的功能。Java RASP也是基于JavaAgent實現(xiàn)的。趁熱記錄下JavaAgent基礎(chǔ)概念,以及簡單使用JavaAgent實現(xiàn)一個獲取目標進程已加載的類的測試。

JVMTI與Java Instrument

Java平臺調(diào)試器架構(gòu)(Java Platform Debugger Architecture,JPDA)是一組用于調(diào)試Java代碼的API(摘自維基百科):

  • Java調(diào)試器接口(Java Debugger Interface,JDI)——定義了一個高層次Java接口,開發(fā)人員可以利用JDI輕松編寫遠程調(diào)試工具
  • Java虛擬機工具接口(Java Virtual Machine Tools Interface,JVMTI)——定義了一個原生(native)接口,可以對運行在Java虛擬機的應用程序檢查狀態(tài)、控制運行
  • Java虛擬機調(diào)試接口(JVMDI)——JVMDI在J2SE 5中被JVMTI取代,并在Java SE 6中被移除
  • Java調(diào)試線協(xié)議(JDWP)——定義了調(diào)試對象(一個 Java 應用程序)和調(diào)試器進程之間的通信協(xié)議

JVMTI 提供了一套”代理”程序機制,可以支持第三方工具程序以代理的方式連接和訪問 JVM,并利用 JVMTI 提供的豐富的編程接口,完成很多跟 JVM 相關(guān)的功能。JVMTI是基于事件驅(qū)動的,JVM每執(zhí)行到一定的邏輯就會調(diào)用一些事件的回調(diào)接口(如果有的話),這些接口可以供開發(fā)者去擴展自己的邏輯。

JVMTIAgent是一個利用JVMTI暴露出來的接口提供了代理啟動時加載(agent on load)、代理通過attach形式加載(agent on attach)和代理卸載(agent on unload)功能的動態(tài)庫。Instrument Agent可以理解為一類JVMTIAgent動態(tài)庫,別名是JPLISAgent(Java Programming Language Instrumentation Services Agent),是專門為java語言編寫的插樁服務提供支持的代理。

Instrumentation接口

以下接口是Java SE 8?API文檔中[1]提供的(不同版本可能接口有變化):

void addTransformer(ClassFileTransformer transformer, boolean canRetransform)//注冊ClassFileTransformer實例,注冊多個會按照注冊順序進行調(diào)用。所有的類被加載完畢之后會調(diào)用ClassFileTransformer實例,相當于它們通過了redefineClasses方法進行重定義。布爾值參數(shù)canRetransform決定這里被重定義的類是否能夠通過retransformClasses方法進行回滾。

void addTransformer(ClassFileTransformer transformer)//相當于addTransformer(transformer, false),也就是通過ClassFileTransformer實例重定義的類不能進行回滾。

boolean removeTransformer(ClassFileTransformer transformer)//移除(反注冊)ClassFileTransformer實例。

void retransformClasses(Class<?>... classes)//已加載類進行重新轉(zhuǎn)換的方法,重新轉(zhuǎn)換的類會被回調(diào)到ClassFileTransformer的列表中進行處理。

void appendToBootstrapClassLoaderSearch(JarFile jarfile)//將某個jar加入到Bootstrap Classpath里優(yōu)先其他jar被加載。

void appendToSystemClassLoaderSearch(JarFile jarfile)//將某個jar加入到Classpath里供AppClassloard去加載。

Class[] getAllLoadedClasses()//獲取所有已經(jīng)被加載的類。

Class[] getInitiatedClasses(ClassLoader loader)//獲取所有已經(jīng)被初始化過了的類。

long getObjectSize(Object objectToSize)//獲取某個對象的(字節(jié))大小,注意嵌套對象或者對象中的屬性引用需要另外單獨計算。

boolean isModifiableClass(Class<?> theClass)//判斷對應類是否被修改過。

boolean isNativeMethodPrefixSupported()//是否支持設(shè)置native方法的前綴。

boolean isRedefineClassesSupported()//返回當前JVM配置是否支持重定義類(修改類的字節(jié)碼)的特性。

boolean isRetransformClassesSupported()//返回當前JVM配置是否支持類重新轉(zhuǎn)換的特性。

void redefineClasses(ClassDefinition... definitions)//重定義類,也就是對已經(jīng)加載的類進行重定義,ClassDefinition類型的入?yún)藢念愋虲lass<?>對象和字節(jié)碼文件對應的字節(jié)數(shù)組。

void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix)//設(shè)置某些native方法的前綴,主要在找native方法的時候做規(guī)則匹配。

redefineClasses與redefineClasses

重新定義功能在Java SE 5中進行了介紹,重新轉(zhuǎn)換功能在Java SE 6中進行了介紹,一種猜測是將重新轉(zhuǎn)換作為更通用的功能引入,但是必須保留重新定義以實現(xiàn)向后兼容,并且重新轉(zhuǎn)換操作也更加方便。

Instrument Agent兩種加載方式

在官方API文檔[1]中提到,有兩種獲取Instrumentation接口實例的方法 :

  1. JVM在指定代理的方式下啟動,此時Instrumentation實例會傳遞到代理類的premain方法。
  2. JVM提供一種在啟動之后的某個時刻啟動代理的機制,此時Instrumentation實例會傳遞到代理類代碼的agentmain方法。

premain對應的就是VM啟動時的Instrument Agent加載,即agent on load,agentmain對應的是VM運行時的Instrument Agent加載,即agent on attach。兩種加載形式所加載的Instrument Agent都關(guān)注同一個JVMTI事件 –?ClassFileLoadHook事件,這個事件是在讀取字節(jié)碼文件之后回調(diào)時用,也就是說premain和agentmain方式的回調(diào)時機都是類文件字節(jié)碼讀取之后(或者說是類加載之后),之后對字節(jié)碼進行重定義或重轉(zhuǎn)換,不過修改的字節(jié)碼也需要滿足一些要求,在最后的局限性有說明。

premain與agentmain的區(qū)別:

premain和agentmain兩種方式最終的目的都是為了回調(diào)Instrumentation實例并激活sun.instrument.InstrumentationImpl#transform()(InstrumentationImpl是Instrumentation的實現(xiàn)類)從而回調(diào)注冊到Instrumentation中的ClassFileTransformer實現(xiàn)字節(jié)碼修改,本質(zhì)功能上沒有很大區(qū)別。兩者的非本質(zhì)功能的區(qū)別如下:

  1. premain方式是JDK1.5引入的,agentmain方式是JDK1.6引入的,JDK1.6之后可以自行選擇使用premain或者agentmain。
  2. premain需要通過命令行使用外部代理jar包,即-javaagent:代理jar包路徑;agentmain則可以通過attach機制直接附著到目標VM中加載代理,也就是使用agentmain方式下,操作attach的程序和被代理的程序可以是完全不同的兩個程序。
  3. premain方式回調(diào)到ClassFileTransformer中的類是虛擬機加載的所有類,這個是由于代理加載的順序比較靠前決定的,在開發(fā)者邏輯看來就是:所有類首次加載并且進入程序main()方法之前,premain方法會被激活,然后所有被加載的類都會執(zhí)行ClassFileTransformer列表中的回調(diào)。
  4. agentmain方式由于是采用attach機制,被代理的目標程序VM有可能很早之前已經(jīng)啟動,當然其所有類已經(jīng)被加載完成,這個時候需要借助Instrumentation#retransformClasses(Class<?>… classes)讓對應的類可以重新轉(zhuǎn)換,從而激活重新轉(zhuǎn)換的類執(zhí)行ClassFileTransformer列表中的回調(diào)。
  5. 通過premain方式的代理Jar包進行了更新的話,需要重啟服務器,而agentmain方式的Jar包如果進行了更新的話,需要重新attach,但是agentmain重新attach還會導致重復的字節(jié)碼插入問題,不過也有Hotswap和DCE VM方式來避免。

通過下面的測試也能看到它們之間的一些區(qū)別。

premain加載方式

premain方式編寫步驟簡單如下:

1.編寫premain函數(shù),包含下面兩個方法的其中之一:

java public static void premain(String agentArgs, Instrumentation inst); public static void premain(String agentArgs);

如果兩個方法都被實現(xiàn)了,那么帶Instrumentation參數(shù)的優(yōu)先級高一些,會被優(yōu)先調(diào)用。agentArgs是premain函數(shù)得到的程序參數(shù),通過命令行參數(shù)傳入

2.定義一個 MANIFEST.MF 文件,必須包含 Premain-Class 選項,通常也會加入Can-Redefine-Classes 和 Can-Retransform-Classes 選項

3.將 premain 的類和 MANIFEST.MF 文件打成 jar 包

4.使用參數(shù) -javaagent: jar包路徑啟動代理

premain加載過程如下:

1.創(chuàng)建并初始化 JPLISAgent
2.MANIFEST.MF 文件的參數(shù),并根據(jù)這些參數(shù)來設(shè)置 JPLISAgent 里的一些內(nèi)容
3.監(jiān)聽?VMInit?事件,在 JVM 初始化完成之后做下面的事情:
(1)創(chuàng)建 InstrumentationImpl 對象 ;
(2)監(jiān)聽 ClassFileLoadHook 事件 ;
(3)調(diào)用 InstrumentationImpl 的loadClassAndCallPremain方法,在這個方法里會去調(diào)用 javaagent 中 MANIFEST.MF 里指定的Premain-Class 類的 premain 方法

下面是一個簡單的例子(在JDK1.8.0_181進行了測試):

PreMainAgent

package com.longofo;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class PreMainAgent {
    static {
        System.out.println("PreMainAgent class static block run...");
    }

    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("PreMainAgent agentArgs : " + agentArgs);
        Class<?>[] cLasses = inst.getAllLoadedClasses();

        for (Class<?> cls : cLasses) {
            System.out.println("PreMainAgent get loaded class:" + cls.getName());
        }

        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("PreMainAgent transform Class:" + className);
            return classfileBuffer;
        }
    }
}

MANIFEST.MF:

Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: com.longofo.PreMainAgent

Testmain

package com.longofo;

public class TestMain {

    static {
        System.out.println("TestMain static block run...");
    }

    public static void main(String[] args) {
        System.out.println("TestMain main start...");
        try {
            for (int i = 0; i < 100; i++) {
                Thread.sleep(3000);
                System.out.println("TestMain main running...");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("TestMain main end...");
    }
}

將PreMainAgent打包為Jar包(可以直接用idea打包,也可以使用maven插件打包),在idea可以像下面這樣啟動:

命令行的話可以用形如java -javaagent:PreMainAgent.jar路徑 -jar TestMain/TestMain.jar啟動

結(jié)果如下:

PreMainAgent class static block run...
PreMainAgent agentArgs : null
PreMainAgent get loaded class:com.longofo.PreMainAgent
PreMainAgent get loaded class:sun.reflect.DelegatingMethodAccessorImpl
PreMainAgent get loaded class:sun.reflect.NativeMethodAccessorImpl
PreMainAgent get loaded class:sun.instrument.InstrumentationImpl$1
PreMainAgent get loaded class:[Ljava.lang.reflect.Method;
...
...
PreMainAgent transform Class:sun/nio/cs/ThreadLocalCoders
PreMainAgent transform Class:sun/nio/cs/ThreadLocalCoders$1
PreMainAgent transform Class:sun/nio/cs/ThreadLocalCoders$Cache
PreMainAgent transform Class:sun/nio/cs/ThreadLocalCoders$2
...
...
PreMainAgent transform Class:java/lang/Class$MethodArray
PreMainAgent transform Class:java/net/DualStackPlainSocketImpl
PreMainAgent transform Class:java/lang/Void
TestMain static block run...
TestMain main start...
PreMainAgent transform Class:java/net/Inet6Address
PreMainAgent transform Class:java/net/Inet6Address$Inet6AddressHolder
PreMainAgent transform Class:java/net/SocksSocketImpl$3
...
...
PreMainAgent transform Class:java/util/LinkedHashMap$LinkedKeySet
PreMainAgent transform Class:sun/util/locale/provider/LocaleResources$ResourceReference
TestMain main running...
TestMain main running...
...
...
TestMain main running...
TestMain main end...
PreMainAgent transform Class:java/lang/Shutdown
PreMainAgent transform Class:java/lang/Shutdown$Lock

可以看到在PreMainAgent之前已經(jīng)加載了一些必要的類,即PreMainAgent get loaded class:xxx部分,這些類沒有經(jīng)過transform。然后在main之前有一些類經(jīng)過了transform,在main啟動之后還有類經(jīng)過transform,main結(jié)束之后也還有類經(jīng)過transform,可以和agentmain的結(jié)果對比下。

agentmain加載方式

agentmain方式編寫步驟簡單如下:

1.編寫agentmain函數(shù),包含下面兩個方法的其中之一:

   public static void agentmain(String agentArgs, Instrumentation inst);
   public static void agentmain(String agentArgs);

如果兩個方法都被實現(xiàn)了,那么帶Instrumentation參數(shù)的優(yōu)先級高一些,會被優(yōu)先調(diào)用。agentArgs是premain函數(shù)得到的程序參數(shù),通過命令行參數(shù)傳入

2.定義一個 MANIFEST.MF 文件,必須包含 Agent-Class 選項,通常也會加入Can-Redefine-Classes 和 Can-Retransform-Classes 選項

3.將 agentmain 的類和 MANIFEST.MF 文件打成 jar 包

4.通過attach工具直接加載Agent,執(zhí)行attach的程序和需要被代理的程序可以是兩個完全不同的程序:

   // 列出所有VM實例
   List<VirtualMachineDescriptor> list = VirtualMachine.list();
   // attach目標VM
   VirtualMachine.attach(descriptor.id());
   // 目標VM加載Agent
   VirtualMachine#loadAgent("代理Jar路徑","命令參數(shù)");

agentmain方式加載過程類似:

1.創(chuàng)建并初始化JPLISAgent
2.解析MANIFEST.MF 里的參數(shù),并根據(jù)這些參數(shù)來設(shè)置 JPLISAgent 里的一些內(nèi)容
3.監(jiān)聽?VMInit?事件,在 JVM 初始化完成之后做下面的事情:
(1)創(chuàng)建 InstrumentationImpl 對象 ;
(2)監(jiān)聽 ClassFileLoadHook 事件 ;
(3)調(diào)用 InstrumentationImpl 的loadClassAndCallAgentmain方法,在這個方法里會去調(diào)用javaagent里 MANIFEST.MF 里指定的Agent-Class類的agentmain方法。

下面是一個簡單的例子(在JDK 1.8.0_181上進行了測試):

SufMainAgent

package com.longofo;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class SufMainAgent {
    static {
        System.out.println("SufMainAgent static block run...");
    }

    public static void agentmain(String agentArgs, Instrumentation instrumentation) {
        System.out.println("SufMainAgent agentArgs: " + agentArgs);

        Class<?>[] classes = instrumentation.getAllLoadedClasses();
        for (Class<?> cls : classes) {
            System.out.println("SufMainAgent get loaded class: " + cls.getName());
        }

        instrumentation.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("SufMainAgent transform Class:" + className);
            return classfileBuffer;
        }
    }
}

MANIFEST.MF

Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Agent-Class: com.longofo.SufMainAgent

TestSufMainAgent

package com.longofo;

import com.sun.tools.attach.*;

import java.io.IOException;
import java.util.List;

public class TestSufMainAgent {
    public static void main(String[] args) throws IOException, AgentLoadException, AgentInitializationException, AttachNotSupportedException {
        //獲取當前系統(tǒng)中所有 運行中的 虛擬機
        System.out.println("TestSufMainAgent start...");
        String option = args[0];
        List<VirtualMachineDescriptor> list = VirtualMachine.list();
        if (option.equals("list")) {
            for (VirtualMachineDescriptor vmd : list) {
                //如果虛擬機的名稱為 xxx 則 該虛擬機為目標虛擬機,獲取該虛擬機的 pid
                //然后加載 agent.jar 發(fā)送給該虛擬機
                System.out.println(vmd.displayName());
            }
        } else if (option.equals("attach")) {
            String jProcessName = args[1];
            String agentPath = args[2];
            for (VirtualMachineDescriptor vmd : list) {
                if (vmd.displayName().equals(jProcessName)) {
                    VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());
                    virtualMachine.loadAgent(agentPath);
                }
            }
        }
    }
}

Testmain

package com.longofo;

public class TestMain {

    static {
        System.out.println("TestMain static block run...");
    }

    public static void main(String[] args) {
        System.out.println("TestMain main start...");
        try {
            for (int i = 0; i < 100; i++) {
                Thread.sleep(3000);
                System.out.println("TestMain main running...");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("TestMain main end...");
    }
}

將SufMainAgent和TestSufMainAgent打包為Jar包(可以直接用idea打包,也可以使用maven插件打包),首先啟動Testmain,然后先列下當前有哪些Java程序:

attach SufMainAgent到Testmain:

在Testmain中的結(jié)果如下:

TestMain static block run...
TestMain main start...
TestMain main running...
TestMain main running...
TestMain main running...
...
...
SufMainAgent static block run...
SufMainAgent agentArgs: null
SufMainAgent get loaded class: com.longofo.SufMainAgent
SufMainAgent get loaded class: com.longofo.TestMain
SufMainAgent get loaded class: com.intellij.rt.execution.application.AppMainV2$1
SufMainAgent get loaded class: com.intellij.rt.execution.application.AppMainV2
...
...
SufMainAgent get loaded class: java.lang.Throwable
SufMainAgent get loaded class: java.lang.System
...
...
TestMain main running...
TestMain main running...
...
...
TestMain main running...
TestMain main running...
TestMain main end...
SufMainAgent transform Class:java/lang/Shutdown
SufMainAgent transform Class:java/lang/Shutdown$Lock

和前面premain對比下就能看出,在agentmain中直接getloadedclasses的類數(shù)目比在premain直接getloadedclasses的數(shù)量多,而且premain getloadedclasses的類+premain transform的類和agentmain getloadedclasses基本吻合(只針對這個測試,如果程序中間還有其他通信,可能會不一樣)。也就是說某個類之前沒有加載過,那么都會通過兩者設(shè)置的transform,這可以從最后的java/lang/Shutdown看出來。

測試Weblogic的某個類是否被加載

這里使用weblogic進行測試,代理方式使用agentmain方式(在jdk1.6.0_29上進行了測試):

WeblogicSufMainAgent

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class WeblogicSufMainAgent {
    static {
        System.out.println("SufMainAgent static block run...");
    }

    public static void agentmain(String agentArgs, Instrumentation instrumentation) {
        System.out.println("SufMainAgent agentArgs: " + agentArgs);

        Class<?>[] classes = instrumentation.getAllLoadedClasses();
        for (Class<?> cls : classes) {
            System.out.println("SufMainAgent get loaded class: " + cls.getName());
        }

        instrumentation.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("SufMainAgent transform Class:" + className);
            return classfileBuffer;
        }
    }
}

WeblogicTestSufMainAgent:

import com.sun.tools.attach.*;

import java.io.IOException;
import java.util.List;

public class WeblogicTestSufMainAgent {
    public static void main(String[] args) throws IOException, AgentLoadException, AgentInitializationException, AttachNotSupportedException {
        //獲取當前系統(tǒng)中所有 運行中的 虛擬機
        System.out.println("TestSufMainAgent start...");
        String option = args[0];
        List<VirtualMachineDescriptor> list = VirtualMachine.list();
        if (option.equals("list")) {
            for (VirtualMachineDescriptor vmd : list) {
                //如果虛擬機的名稱為 xxx 則 該虛擬機為目標虛擬機,獲取該虛擬機的 pid
                //然后加載 agent.jar 發(fā)送給該虛擬機
                System.out.println(vmd.displayName());
            }
        } else if (option.equals("attach")) {
            String jProcessName = args[1];
            String agentPath = args[2];
            for (VirtualMachineDescriptor vmd : list) {
                if (vmd.displayName().equals(jProcessName)) {
                    VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());
                    virtualMachine.loadAgent(agentPath);
                }
            }
        }
    }
}

列出正在運行的Java應用程序:

進行attach:

Weblogic輸出:

假如在進行Weblogic t3反序列化利用時,如果某個類之前沒有被加載,但是能夠被Weblogic找到,那么利用時對應的類會通過Agent的transform,但是有些類雖然在Weblogic目錄下的某些Jar包中,但是weblogic不會去加載,需要一些特殊的配置Weblogic才會去尋找并加載。

Instrumentation局限性

大多數(shù)情況下,使用Instrumentation都是使用其字節(jié)碼插樁的功能,籠統(tǒng)說是類重轉(zhuǎn)換的功能,但是有以下的局限性:

  1. premain和agentmain兩種方式修改字節(jié)碼的時機都是類文件加載之后,就是說必須要帶有Class類型的參數(shù),不能通過字節(jié)碼文件和自定義的類名重新定義一個本來不存在的類。這里需要注意的就是上面提到過的重新定義,剛才這里說的不能重新定義是指不能重新?lián)Q一個類名,字節(jié)碼內(nèi)容依然能重新定義和修改,不過字節(jié)碼內(nèi)容修改后也要滿足第二點的要求。
  2. 類轉(zhuǎn)換其實最終都回歸到類重定義Instrumentation#retransformClasses()方法,此方法有以下限制:
    1.新類和老類的父類必須相同;
    2.新類和老類實現(xiàn)的接口數(shù)也要相同,并且是相同的接口;
    3.新類和老類訪問符必須一致。 新類和老類字段數(shù)和字段名要一致;
    4.新類和老類新增或刪除的方法必須是private static/final修飾的;
    5.可以刪除修改方法體。

實際中遇到的限制可能不止這些,遇到了再去解決吧。如果想要重新定義一全新類(類名在已加載類中不存在),可以考慮基于類加載器隔離的方式:創(chuàng)建一個新的自定義類加載器去通過新的字節(jié)碼去定義一個全新的類,不過只能通過反射調(diào)用該全新類的局限性。

小結(jié)

  1. 文中只是描述了JavaAgent相關(guān)的一些基礎(chǔ)的概念,目的只是知道有這個東西,然后驗證下之前遇到的一個問題。寫的時候也借鑒了其他大佬寫的幾篇文章[4]&[5]
  2. 在寫文章的過程中看了一些如一類PHP-RASP實現(xiàn)的漏洞檢測的思路[6],利用了污點跟蹤、hook、語法樹分析等技術(shù),也看了幾篇大佬們整理的Java RASP相關(guān)文章[2]&[3],如果自己要寫基于RASP的漏洞檢測/利用工具的話也可以借鑒到這些思路

代碼放到了github上,有興趣的可以去測試下,注意pom.xml文件中的jdk版本,在切換JDK測試如果出現(xiàn)錯誤,記得修改pom.xml里面的JDK版本。

參考

1.https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/Instrumentation.html

2.https://paper.seebug.org/513/#0x01-rasp

3.https://paper.seebug.org/1041/#31-java-agent

4.http://www.throwable.club/2019/06/29/java-understand-instrument-first/#Instrumentation%E6%8E%A5%E5%8F%A3%E8%AF%A6%E8%A7%A3

5.https://www.cnblogs.com/rickiyang/p/11368932.html

6.https://c0d3p1ut0s.github.io/%E4%B8%80%E7%B1%BBPHP-RASP%E7%9A%84%E5%AE%9E%E7%8E%B0/

本文由 Seebug Paper 發(fā)布,如需轉(zhuǎn)載請注明來源。本文地址:https://paper.seebug.org/1099/
轉(zhuǎn)載自安全客:?https://www.anquanke.com/post/id/194956?

上一篇:CDecryptPwd(一)——Navicat

下一篇:騰訊 iOA 零信任安全技術(shù)實踐