主頁 >  其他 > 初探Java安全之JavaAgent

初探Java安全之JavaAgent

2022-11-23 07:16:12 其他

在JDK1.5版本開始,Java增加了Instrumentation(Java Agent API)和JVMTI(JVM Tool Interface)功能,該功能可以實作JVM再加載某個class檔案對其位元組碼進行修改,也可以對已經加載的位元組碼進行一個重新的加載,而在1.6版本新增了attach(附加方式)方式,可以對運行中的Java行程插入Agent,Java Agent可以去實作位元組碼插樁、動態跟蹤分析等,比如RASP產品和Java Agent記憶體馬,

有兩種模式:
1、啟動Java程式時添加-javaagent(Instrumentation API實作方式)或-agentpath/-agentlib(JVMTI的實作方式)引數,如java -javaagent:/data/XXX.jar LingXeTest,
2、JDK1.6新增了attach(附加方式)方式,可以對運行中的Java行程附加Agent,

這兩種運行方式的最大區別在于第一種方式只能在程式啟動時指定Agent檔案,而attach方式可以在Java程式運行后根據行程ID動態注入Agent到JVM,

所以類似于想要注入Agent型記憶體馬,一般會用attach的方式,

Javaagent是java命令的一個引數,引數 javaagent 可以用于指定一個jar包

Java Agent和普通的Java類并沒有任何區別,普通的Java程式中規定了main方法為程式入口,而Java Agent則將premain(Agent模式)和agentmain(Attach模式)作為了Agent程式的入口,兩者所接受的引數是完全一致的,如下:

public static void premain(String args, Instrumentation inst) {}
public static void agentmain(String args, Instrumentation inst) {}

而在Attach模式下的premain()方法有兩種寫法,如下:

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

JVM會去優先加載帶 Instrumentation 簽名的方法,加載成功忽略第二種,如果第一種沒有,則加載第二種方法,

Java Agent還限制了我們必須以jar包的形式運行或加載,我們必須將撰寫好的Agent程式打包成一個jar檔案,除此之外,Java Agent還強制要求了所有的jar檔案中必須包含/META-INF/MANIFEST.MF檔案,且該檔案中必須定義好Premain-Class(Agent模式)或Agent-Class:(Agent模式)配置,如:

Premain-Class: com.anbai.sec.agent.CrackLicenseAgent
Agent-Class: com.anbai.sec.agent.CrackLicenseAgent

如果我們需要修改已經被JVM加載過的類的位元組碼,那么還需要設定在MANIFEST.MF中添加

Can-Retransform-Classes: true或Can-Redefine-Classes: true

javaagent引數相關:

-agentlib:<libname>[=<選項>] 加載本機代理庫 <libname>, 例如 -agentlib:hprof
另請參閱 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:<pathname>[=<選項>]
按完整路徑名加載本機代理庫
-javaagent:<jarpath>[=<選項>]
加載 Java 編程語言代理, 請參閱 java.lang.instrument

jarpath 是指向代理程式 JAR 檔案的路徑,options 是代理選項,此開關可以在同一命令列上多次使用,從而創建多個代理程式,多個代理程式可以使用同一 jarpath,代理 JAR 檔案必須符合 JAR 檔案規范,下面的清單屬性是針對代理 JAR 檔案定義的:
Premain-Class
代理類,即包含 premain 方法的類,此屬性是必需的,如果它不存在,JVM 將中止,注:這是類名,而不是檔案名或路徑,
Boot-Class-Path
由引導類加載器搜索的路徑串列,路徑表示目錄或庫(在許多平臺上通常作為 jar 或 zip 庫被參考),查找類的特定于平臺的機制出現故障之后,引導類加載器會搜索這些路徑,按列出的順序搜索路徑,串列中的路徑由一個或多個空格分開,路徑使用分層 URI 的路徑組件的語法,如果該路徑以斜杠字符(“/”)開頭,則為絕對路徑,否則為相對路徑,相對路徑根據代理 JAR 檔案的絕對路徑決議,忽略格式不正確的路徑和不存在的路徑,此屬性是可選的,
Can-Redefine-Classes
布林值(truefalse,與大小寫無關),能夠重定義此代理所需的類,值如果不是 true,則被認為是 false,此屬性是可選的,默認值為 false,
代理 JAR 檔案附加到類路徑之后,

而關于java.lang.instrument包位于rt.jar,一共有5個檔案

其實這一部分把注釋翻譯過來,有些類和某些方法依舊不理解是什么意思,也有些看懂了但不知道怎么用,先鴿著,

public final class ClassDefinition {
    /**
     *  要重定義的類
     */
    private final Class<?> mClass;

    /**
     *  用于替換的本地 class ,為 byte 陣列
     */
    private final byte[]   mClassFile;

    /**
     *  構造方法,使用提供的類和類檔案位元組創建一個新的 ClassDefinition 系結
     */
    public ClassDefinition( Class<?> theClass, byte[]  theClassFile) {
        if (theClass == null || theClassFile == null) {
            throw new NullPointerException();
        }
        mClass      = theClass;
        mClassFile  = theClassFile;
    }

    /**
     * 以下為 getter 方法
     */
    public Class<?>  getDefinitionClass() {
        return mClass;
    }

    public byte[] getDefinitionClassFile() {
        return mClassFile;
    }
}

ClassFileTransformer是一個轉換類檔案的代理介面,我們可以在獲取到Instrumentation物件后通過addTransformer方法添加自定義類檔案轉換器,

使用addTransformer方法可以注冊一個我們自定義的Transformer到Java Agent,當有新的類被JVM加載時JVM會自動回呼叫我們自定義的Transformer類的transform方法,傳入該類的transform資訊(類名、類加載器、類位元組碼等),我們可以根據傳入的類資訊決定是否需要修改類位元組碼,修改完位元組碼后我們將新的類位元組碼回傳給JVM,JVM會驗證類和相應的修改是否合法,如果符合類加載要求JVM會加載我們修改后的類位元組碼,

package java.lang.instrument;

public interface ClassFileTransformer {

  /**
   * 類檔案轉換方法,重寫transform方法可獲取到待加載的類相關資訊
   *
   * @param loader              定義要轉換的類加載器;如果是引導加載器,則為 null
   * @param className           類名,如:java/lang/Runtime
   * @param classBeingRedefined 如果是被重定義或重轉換觸發,則為重定義或重轉換的類;如果是類加載,則為 null
   * @param protectionDomain    要定義或重定義的類的保護域
   * @param classfileBuffer     類檔案格式的輸入位元組緩沖區(不得修改)
   * @return 位元組碼byte陣列,
   */
  byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                          ProtectionDomain protectionDomain, byte[] classfileBuffer);

}

重寫transform方法需要注意以下事項:

  1. ClassLoader如果是被Bootstrap ClassLoader(引導類加載器)所加載那么loader引數的值是空,
  2. 修改類位元組碼時需要特別注意插入的代碼在對應的ClassLoader中可以正確的獲取到,否則會報ClassNotFoundException,比如修改java.io.FileInputStream(該類由Bootstrap ClassLoader加載)時插入了我們檢測代碼,那么我們將必須保證FileInputStream能夠獲取到我們的檢測代碼類,
  3. JVM類名的書寫方式路徑方式:java/lang/String而不是我們常用的類名方式:java.lang.String,
  4. 類位元組必須符合JVM校驗要求,如果無法驗證類位元組碼會導致JVM崩潰或者VerifyError(類驗證錯誤),
  5. 如果修改的是retransform類(修改已被JVM加載的類),修改后的類位元組碼不得新增方法、修改方法引數、類成員變數,
  6. addTransformer時如果沒有傳入retransform引數(默認是false)就算MANIFEST.MF中配置了Can-Redefine-Classes: true而且手動呼叫了retransformClasses方法也一樣無法retransform,
  7. 卸載transform時需要使用創建時的Instrumentation實體,

java.lang.instrument.Instrumentation是監測運行在JVM程式的Java API,利用Instrumentation我們可以實作如下功能:

  1. 動態添加或移除自定義的ClassFileTransformer(addTransformer/removeTransformer),JVM會在類加載時呼叫Agent中注冊的ClassFileTransformer;
  2. 動態修改classpath(appendToBootstrapClassLoaderSearch、appendToSystemClassLoaderSearch),將Agent程式添加到BootstrapClassLoader和SystemClassLoaderSearch(對應的是ClassLoader類的getSystemClassLoader方法,默認是sun.misc.Launcher$AppClassLoader)中搜索;
  3. 動態獲取所有JVM已加載的類(getAllLoadedClasses);
  4. 動態獲取某個類加載器已實體化的所有類(getInitiatedClasses),
  5. 重定義某個已加載的類的位元組碼(redefineClasses),
  6. 動態設定JNI前綴(setNativeMethodPrefix),可以實作Hook native方法,
  7. 重新加載某個已經被JVM加載過的類位元組碼retransformClasses),

原始碼如下:

public interface Instrumentation {
  
    //增加一個Class 檔案的轉換器,轉換器用于改變 Class 二進制流的資料,引數 canRetransform 設定是否允許重新轉換,
    void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

    //在類加載之前,重新定義 Class 檔案,ClassDefinition 表示對一個類新的定義,如果在類加載之后,需要使用 retransformClasses 方法重新定義,addTransformer方法配置之后,后續的類加載都會被Transformer攔截,對于已經加載過的類,可以執行retransformClasses來重新觸發這個Transformer的攔截,類加載的位元組碼被修改后,除非再次被retransform,否則不會恢復,
    void addTransformer(ClassFileTransformer transformer);

    //洗掉一個類轉換器
    boolean removeTransformer(ClassFileTransformer transformer);

    boolean isRetransformClassesSupported();

    //在類加載之后,重新定義 Class,這個很重要,該方法是1.6 之后加入的,事實上,該方法是 update 了一個類,
    void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;

    boolean isRedefineClassesSupported();

  
    void redefineClasses(ClassDefinition... definitions)
        throws  ClassNotFoundException, UnmodifiableClassException;

    boolean isModifiableClass(Class<?> theClass);

    @SuppressWarnings("rawtypes")
    Class[] getAllLoadedClasses();

  
    @SuppressWarnings("rawtypes")
    Class[] getInitiatedClasses(ClassLoader loader);

    //獲取一個物件的大小
    long getObjectSize(Object objectToSize);


   
    void appendToBootstrapClassLoaderSearch(JarFile jarfile);

  
    void appendToSystemClassLoaderSearch(JarFile jarfile);

  
    boolean isNativeMethodPrefixSupported();

  
    void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
}

前面都是理論,我們來簡單寫一個小Demo感受一下如何使用Java Agent技術,

大致分為以下流程(以-javaagent模式為例):

  1. 撰寫一個Agent類,其中定義premain方法并呼叫Instrumentation#addTransformer方法添加一個自定義的Transformer
  2. 自定義一個Transformer類,實作Instrumentation介面,在transform方法中寫入自己想要的AOP邏輯
  3. 創建MANIFEST.MF檔案,可以手動寫也可以通過Maven的插件(pom.xml)
  4. 打包Agent的jar包
  5. 在需要使用JavaAgent的專案添加JVM啟動引數-javaagent并指定我們打包好的jar

這里需要2個專案,1個為javaagent的jar包,另1個為被javaagent代理的類,最終在被代理類的main方法執行前先執行我們Agent中的premain方法

0x01 撰寫javaagent相關代碼
先創建一個Maven專案,其中創建一個Agent類,里面需要包含premain方法

package com.zh1z3ven;

import java.lang.instrument.Instrumentation;

public class Agent {
    public static void premain(String agentArgs, Instrumentation inst){
        System.out.println("agentArgs"+agentArgs);
        inst.addTransformer(new DefineTransformer(),true);//呼叫addTransformer添加一個Transformer
    }

}

創建DefineTransformer類,實作ClassFileTransformer介面

package com.zh1z3ven;

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

public 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 new byte[0];
    }
}

0x02 創建MANIFEST.MF檔案
手動創建的話需要在resources/META-INF目錄下創建MANIFEST.MF檔案,內容如下:注意多留一行空行

Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: com.zh1z3ven.Agent

通過pom.xml中呼叫Maven的插件去創建該檔案

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <archive>
                        <!--自動添加META-INF/MANIFEST.MF -->
                        <manifest>
                            <addClasspath>true</addClasspath>
                        </manifest>
                        <manifestEntries>
                            <Premain-Class>com.zh1z3ven.Agent</Premain-Class>
                            <Agent-Class>com.zh1z3ven.Agent</Agent-Class>
                            <Can-Redefine-Classes>true</Can-Redefine-Classes>
                            <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

打包好jar后,檔案會在jar包中

一些可能會用到的引數說明:

Premain-Class :包含 premain 方法的類(類的全路徑名)
Agent-Class :包含 agentmain 方法的類(類的全路徑名)
Boot-Class-Path :設定引導類加載器搜索的路徑串列,查找類的特定于平臺的機制失敗后,引導類加載器會搜索這些路徑,按列出的順序搜索路徑,串列中的路徑由一個或多個空格分開,路徑使用分層 URI 的路徑組件語法,如果該路徑以斜杠字符(“/”)開頭,則為絕對路徑,否則為相對路徑,相對路徑根據代理 JAR 檔案的絕對路徑決議,忽略格式不正確的路徑和不存在的路徑,如果代理是在 VM 啟動之后某一時刻啟動的,則忽略不表示 JAR 檔案的路徑,(可選)
Can-Redefine-Classes :true表示能重定義此代理所需的類,默認值為 false(可選)
Can-Retransform-Classes :true 表示能重轉換此代理所需的類,默認值為 false (可選)
Can-Set-Native-Method-Prefix: true表示能設定此代理所需的本機方法前綴,默認值為 false(可選)

0x03 撰寫測驗類
隨意寫一個

public class a {
    public static void main(String[] args) {
        System.out.println("main Method");
    }
}

0x04 -javaagent模式啟動
JVM啟動引數添加

-javaagent:target/JavaAgent-1.0-SNAPSHOT.jar

執行main方法之前會加載所有的類,包括系統類和自定義類,而在ClassFileTransformer中會去攔截系統類和自己實作的類物件,邏輯則是在ClassFileTransformer實作類的transform方法中定義,
而在這里transform給我的感覺是類似于一個filter會去攔截/遍歷一些要在JVM中加載的類,而在transform方法中我們可以定義一些邏輯,比如if className== xxx時走入一個邏輯去實作AOP,而其中就可以利用如javassist技術修改位元組碼并作為transform方法的回傳值,這樣就在該類在JVM中加載前(-javaagent模式)修改了位元組碼

這里在之前a類中新添加一個方法,并在Agent里我們自定義的Transformerttransform添加一個邏輯,使用javassist去修改我們a類中新添加的方法,

a類中新加一個call方法

package MemoryShell.JavaAgent;

public class a {
    public static void main(String[] args) {
        System.out.println("main Method");
        call();
    }

    public static void call(){
        System.out.println("say hello ...");
    }
}

DefineTransformer

package com.zh1z3ven;

import javassist.*;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public 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); //列印加載的類
        if ("MemoryShell/JavaAgent/a".equals(className)){

            try {
                ClassPool classPool = ClassPool.getDefault();
                CtClass ctClass = classPool.get("MemoryShell.JavaAgent.a");
                CtMethod call = ctClass.getDeclaredMethod("call");
                // 列印后加了一個彈計算器的操作
                String MethodBody = "{System.out.println(\"say hello ...\");" +
                        "java.lang.Runtime.getRuntime().exec(\"open -a Calculator\");}";
                call.setBody(MethodBody);
                byte[] bytes = ctClass.toBytecode();
    
                //detach的意思是將記憶體中曾經被javassist加載過的a物件移除,如果下次有需要在記憶體中找不到會重新走javassist加載
                ctClass.detach();
                return bytes;

            } catch (NotFoundException e) {
                e.printStackTrace();
            } catch (CannotCompileException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return new byte[0];
    }

}

打成jar包,指定JVM引數后運行a類

-javaagent:target/JavaAgent-1.1-SNAPSHOT.jar

在Java SE 6 以后在Instrumentation介面中提供了新的方法agentmain可以在 main 函式開始運行之后再運行,

//采用attach機制,被代理的目標程式VM有可能很早之前已經啟動,當然其所有類已經被加載完成,這個時候需要借助Instrumentation#retransformClasses(Class<?>... classes)讓對應的類可以重新轉換,從而激活重新轉換的類執行ClassFileTransformer串列中的回呼
public static void agentmain (String agentArgs, Instrumentation inst)

public static void agentmain (String agentArgs)

同樣,agentmain 方法中帶Instrumentation引數的方法也比不帶優先級更高,開發者必須在MANIFEST.MF檔案里面設定“Agent-Class”來指定包含 agentmain 函式的類,

在Java6 以后實作啟動后加載的新實作是Attach api,Attach API 很簡單,只有 2 個主要的類,都在 com.sun.tools.attach 包里面:

  1. VirtualMachine 字面意義表示一個Java 虛擬機,也就是程式需要監控的目標虛擬機,提供了獲取系統資訊(比如獲取記憶體dump、執行緒dump,類資訊統計(比如已加載的類以及實體個數等), loadAgent,Attach 和 Detach (Attach 動作的相反行為,從 JVM 上面解除一個代理)等方法,可以實作的功能可以說非常之強大 ,該類允許我們通過給attach方法傳入一個jvm的pid(行程id),遠程連接到jvm上 ,代理類注入操作只是它眾多功能中的一個,通過loadAgent方法向jvm注冊一個代理程式agent,在該agent的代理程式中會得到一個Instrumentation實體,該實體可以 在class加載前改變class的位元組碼,也可以在class加載后重新加載,在呼叫Instrumentation實體的方法時,這些方法會使用ClassFileTransformer介面中提供的方法進行處理,
  2. VirtualMachineDescriptor 則是一個描述虛擬機的容器類,配合 VirtualMachine 類完成各種功能,

attach實作動態注入的原理如下:

通過VirtualMachine類的attach(pid)方法,便可以attach到一個運行中的java行程上,之后便可以通過loadAgent(agentJarPath)來將agent的jar包注入到對應的行程,然后對應的行程會呼叫agentmain方法,

0x01 在JavaAgent專案中新撰寫一個AgentMain類

package com.zh1z3ven;

import java.lang.instrument.Instrumentation;

public class AgentMain {
    public static void agentmain(String agentArgs, Instrumentation instrumentation) {
        instrumentation.addTransformer(new AgentMainTransformer(), true);
    }
}

0x02 新建一個自定義的Transformer
transform方法中邏輯依舊是修改a類的call方法位元組碼去彈calc

package com.zh1z3ven;

import javassist.*;

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

public class AgentMainTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

        if ("MemoryShell.JavaAgent.a".equals(className)) {
            try {
                ClassPool classPool = ClassPool.getDefault();
                CtClass ctClass = classPool.get("MemoryShell.JavaAgent.a");
                CtMethod call = ctClass.getDeclaredMethod("call");
                // 列印后加了一個彈計算器的操作
                String MethodBody = "{java.lang.Runtime.getRuntime().exec(\"open -a Calculator\");" +
                        "System.out.println(\"say hello ...\");}";
                call.setBody(MethodBody);
                byte[] bytes = ctClass.toBytecode();
                return bytes;
                //detach的意思是將記憶體中曾經被javassist加載過的a物件移除,如果下次有需要在記憶體中找不到會重新走javassist加載
                //  ctClass.detach();


            } catch (Exception e) {
                e.printStackTrace();
                return classfileBuffer;
            }
        }else {
            return classfileBuffer;
        }


    }


}

0x03 測驗AgentMainTest類
將jar通過jvm pid注入進來,使其修改a類中call方法的位元組碼

package MemoryShell.JavaAgent;

import com.sun.tools.attach.*;

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

public class AgentMainTest {
    public static void main(String[] args) {
        System.out.println("running JVM start ");
        List<VirtualMachineDescriptor> list = VirtualMachine.list(); // 尋找當前系統中所有運行著的JVM行程
        for (VirtualMachineDescriptor vmd : list) {
            //如果虛擬機的名稱為 xxx 則 該虛擬機為目標虛擬機,獲取該虛擬機的 pid
            //然后加載 agent.jar 發送給該虛擬機
            System.out.println(vmd.displayName()); //vmd.displayName()看到當前系統都有哪些JVM行程在運行
            if (vmd.displayName().endsWith("MemoryShell.JavaAgent.AgentMainTest")) {
                VirtualMachine virtualMachine = null;
                try {
                    virtualMachine = VirtualMachine.attach(vmd.id());
                    virtualMachine.loadAgent("/Users/xxxx/JavaSourceCode/JavaCode/JavaAgent/target/JavaAgent-1.0-SNAPSHOT.jar");

                    virtualMachine.detach();

                } catch (AttachNotSupportedException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (AgentLoadException e) {
                    e.printStackTrace();
                } catch (AgentInitializationException e) {
                    e.printStackTrace();
                }

            }
        }
    }

}

0x04 記得修改MANIFEST.MF或直接改pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
        <archive>
            <!--自動添加META-INF/MANIFEST.MF -->
            <manifest>
                <addClasspath>true</addClasspath>
            </manifest>
            <manifestEntries>
                <Agent-Class>com.zh1z3ven.AgentMain</Agent-Class>
                <Can-Redefine-Classes>true</Can-Redefine-Classes>
                <Can-Retransform-Classes>true</Can-Retransform-Classes>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

0x05 打包,先運行測驗AgentMainTest類將jar注入進來使其修改a類的位元組碼,之后運行a的main方法,呼叫到call方法時是我們修改過后的位元組碼了,所以會彈calc

Agent模式與Attach模式小結:

  1. 上面Attach這種情況是修改的還沒被JVM加載的類,已加載的Java類是不會再被Agent處理的,這時候我們需要在Attach到目標行程后呼叫instrumentation.redefineClasses,讓JVM重新該Java類,這樣我們就可以使用Agent機制修改該類的位元組碼了,
    public static void agentmain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException,
     ClassNotFoundException {
     inst.addTransformer(new Transformer(), true);
     inst.retransformClasses(Class.forName("com.example.xxxclass"));
     }
  2. premain和agentmain兩種方式修改位元組碼的時機都是類檔案加載之后,也就是說必須要帶有Class型別的引數,不能通過位元組碼檔案和自定義的類名重新定義一個本來不存在的類,
  3. 類的位元組碼修改稱為類轉換(Class Transform),類轉換其實最終都回歸到類重定義Instrumentation#redefineClasses()方法,此方法有以下限制:
    • 新類和老類的父類必須相同;
    • 新類和老類實作的介面數也要相同,并且是相同的介面;
    • 新類和老類訪問符必須一致, 新類和老類欄位數和欄位名要一致;
    • 新類和老類新增或洗掉的方法必須是private static/final修飾的;
    • 可以修改方法體,
  4. java agent 中的所有依賴,在原行程中的 classpath 中都要能找到,否則在注入時原行程會報錯NoClassDefFoundError,
  5. agent 行程的 classpath 中必須有 tools.jar(提供 VirtualMachine attach api ),jdk 默認有 tools.jar,jre 默認沒有,并且Linux和Windows之間是存在一個tools.jar適配問題,

https://www.cnblogs.com/nice0e3/p/14086165.html
https://www.cnblogs.com/rickiyang/p/11368932.html
https://su18.org/post/irP0RsYK1/
javasec.org

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/538027.html

標籤:其他

上一篇:Java FreeMarker模板引擎注入深入分析

下一篇:第一次打靶

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more