天天看點

手把手教你寫一個Java Agent,實作“免費激活”

相信很多人都“免費激活”過 IDEA吧,在IDEA 的vmoptions配置裡,加行配置就行:

手把手教你寫一個Java Agent,實作“免費激活”

或者是這樣“拖到IDEA視窗中”的形式:

手把手教你寫一個Java Agent,實作“免費激活”
手把手教你寫一個Java Agent,實作“免費激活”

再或者用過一些APM工具,在JVM啟動腳本上增加了-javaagent:/path/to/apm-agent.jar,就可以自動進行追蹤。再或者用過Arthas之類的JVM診斷工具,這些工具都是通過Java Agent的技術去實作的。**

比如上面說的“免費激活”,其實就是在運作時期修改了驗證license的相關代碼。JAVA 裡 Agent 這麼強大的功能,你難道不打算自己親自寫一個試試嗎?

Java Agent 算是JVM的一個插件,以一個Jar包的形式存在。可以做到在運作時期,修改你的位元組碼檔案,進而達到增強、修改等效果,通過 JVM 提供的 Instrumentation API來實作。

一個Java Agent,由以下幾個元件構成:

手把手教你寫一個Java Agent,實作“免費激活”

Agent Class - Agent的功能類

Packaging - 在MANIFEST.MF檔案中定義Agent Class的位置和方式

“裝載點”,比如-javaagent:<jarfile>[=arguments],指定加載的agent.jar檔案

廢話不多說,下面正式開始編寫這個Agent

首先要建立一個Agent Class,這個Class作為我們Agent插件的入口類。配置好-javaagent後,JVM在啟動時會執行我們Agent Class的premain方法

在premain方法中,除了args參數,還有一個instrumentation對象。這個是Java Agent的核心對象,通過該對象可以注冊ClassFileTransformer。

**ClassFileTransformer **就是負責位元組碼轉換的核心接口了,已注冊的ClassFileTransformer可以攔截JVM中所有類的加載,并且可以擷取到已加載類的位元組碼,來看一下這個接口的源碼:

了解了ClassFileTransformer接口之後,現在來寫一個ClassLoggerTransformer實作類。為了簡單,這個實作類隻有一個功能:将已加載的位元組碼轉儲到檔案中

好了,第一個Agent 的功能代碼部分已經完成了,下面需要 Agent 解決入口的配置

現在我們需要将代碼建構成一個Jar,并且Jar内的MANIFEST.MF檔案中,需要包含Agent Class的配置,最終我們的MANIFEST.MF檔案應該是這樣:

通過Maven的建構插件,很容易完成MANIFEST.MF檔案的配置:

隻需要在項目的src/main/resources/META-INF/路徑下,增加一個MANIFEST.MF的模闆,模闆檔案裡按照上面介紹的定義即可,最後mvn clean package就可以建構出我們的agent jar了(預設目錄在${projectpath}/target/),這個jar包内會包含我們上面的MANIFEST.MF模闆檔案

好了,大功告成,我們第一款Agent已經開發完了,下面來測試一下:

增加agent運作後,所有運作時期加載的Class的位元組碼,就會轉儲到我們的classes目錄下了

如果你是在 IDEA 中運作,也可以在Run/Debug Configurations面闆中,add vm options

手把手教你寫一個Java Agent,實作“免費激活”

上面這個例子好像有點過于簡單,隻是“攔截”了位元組碼資料進行了轉儲,并沒有進行位元組碼的修改。其實ClassFileTransformer.transform的傳回值,就是我們要替換的資料;隻需要在transform方法中傳回新的位元組碼資料,就可以做到增強/替換類了(不過這個增強/替換是有一些限制的,比如不能修改方法簽名之類的,本文不做過多介紹)

介紹完了基本的Agent實作,下面來學習一個Agent的實際例子:通過Agent來“免費激活”

前言中提到的,IDEA“免費激活”的工具也是通過Agent實作的,其實基本原理很簡單,就是寫一個Agent,動态修改驗證license的那些代碼而已。

比如我們使用一款需要授權許可證的Java 軟體,其内部驗證許可證的代碼是下面這段(僞代碼)

那麼我們隻需要通過Agent,動态的來修改這個verifyLicense方法,将驗證結果修改為直接通過,就可以繞過這個許可驗證機制了,還不用修改原始Jar包

那麼怎麼修改這個類方法呢?

有兩種方式:

提前解壓jar包,反編譯那個Class檔案,得到Java檔案後修改verifyLicense方法後重新編譯

在ClassFileTransformer實作中,通過傳入的該類位元組碼資料,使用一些位元組碼操作工具進行修改

本文例子為了簡單,使用第一種方式,提前反編譯、修改,再儲存重新編譯的Class檔案到Agent 項目裡:

隻需要建立一個ClassFileTransformer,進行這個驗證許可證Class的替換:

然後在Agent Class中,注冊這個HackVerifierClassFileTransformer

最後隻需要像上面那樣,配置下MANIFEST.MF的生成,然後建構Agent Jar包,就完成了我們這個“免費激活”的Agent 插件

以後運作該 Java 軟體時,隻需要增加-javaagent:/path/to/hack-agent.jar,就實作了“免費激活”

文中例子完整的代碼在https://github.com/kongwu-/agent-samples,有需要的同學可以自行下載下傳

ASM

cglib

javaassist

ByteBuddy

以上的幾個位元組碼操作類庫,最推薦的是ByteBuddy,使用方式上最簡單