源碼分析|咋嘞?你的IDEA過期了吧!加個Jar包就破解了,為什麼?

NO IMAGE

微信公眾號:bugstack蟲洞棧 | 博客:bugstack.cn

沉澱、分享、成長,專注於原創專題案例,以最易學習編程的方式分享知識,讓自己和他人都能有所收穫。目前已完成的專題有;Netty4.x實戰專題案例、用Java實現JVM、基於JavaAgent的全鏈路監控、手寫RPC框架、架構設計專題案例、源碼分析等。

你用劍🗡、我用刀🔪,好的代碼都很燒😏,望你不吝出招💨!

一、前言介紹

2020年了,對於一個程序猿來說;

2020 = 1024 + 996 | 404 + 404 + 404 + 404 + 404
2021 = 1024 + 997
2022 = 1024 + 9106
2023 = 1024 + 9107
...
20xx = 從今年開始可怕

當你過了元旦,爽了週末,清早上班,拿起杯子,加點新(薪)水,打開電腦,收起煩惱,翹起小腳,上揚嘴角。一切就緒都準備好,好!擼代碼!啊!!!IDEA duang duang duang,過期了!

源碼分析|咋嘞?你的IDEA過期了吧!加個Jar包就破解了,為什麼?

腦瓜一熱趕緊搜索破解碼;

  • 第一個,失敗
  • 第二個,失敗
  • 第三個,失敗
  • 第N個,終於,破解了三個月,先用著,先用著,以後再說!

可能大部分夥伴都在搜各種一堆一大串的破解碼往裡面粘,一個個試到最後終於過了。但也有一部分老司機是不搜破解碼的,他們使用jar包破解,有效期100年。

那麼!本文並不想引導用戶都去使用破解版,像IDEA這麼優秀,其實給你提供了很多選擇;

  1. 如果你是學生可以免費使用
  2. 分為社區版和旗艦版,你可以使用社區版 Free, open-source
  3. 一般大公司都是有正版授權的,可以使用
  4. 如果你有開源項目也可以申請 IDEA 授權

所以,個人開發使用社區版本即可,不要使用破解。

好!迴歸正題,本文主要講解是為什麼放個Jar包就能破解,最後在使用一個jar進行破解演示。在以下章節中你可以學習到如下知識;

  • Java Agent 非硬編碼式代理類,這也就是常說的探針技術
  • ASM 字節碼編程簡單使用
  • 工程打包額外加載其他 jar 方法
  • 最後是一個破解演示,僅適合個人學習使用

二、案例工程

我們通過一個案例工程來模擬破解過程是怎麼做到的,其實每個版本的IDEA都在增強防護機制,破解也越來越難。

itstack-demo-code-idea
└── src
├── main
│   ├── java
│   │   └── org.itstack.demo
│   │       └── JetbrainsCrack.java
│   └── resources	
│       └── META-INF	
│           └── MANIFEST.MF
└── test
└── java
├── com.jetbrains.ls.newLicenses
│   └── DecodeCertificates.java			 
└── org.itstack.demo.test
└── ApiTest.java

三、環境配置

  1. JDK 1.8
  2. IDEA 2019.3.1
  3. asm-all 3.3.1

四、代碼講述

在案例中我們模擬 IDEA 有一個 DecodeCertificates 類,用於做授權碼校驗。之後通過我們的 java agent 編程模擬授權被破解。

1. Java Agent 介紹

在 JDK1.5 以後,JVM 提供了 agent 技術構建一個獨立於應用程序的代理程序(即為Agent),用來協助監測、運行甚至替換其他JVM上的程序。使用它可以實現虛擬機級別的AOP功能。

2. ASM 介紹

ASM 是一個 JAVA 字節碼分析、創建和修改的開源應用框架。在 ASM 中提供了諸多的API用於對類的內容進行字節碼操作的方法。與傳統的 BCEL 和 SERL 不同,在 ASM 中提供了更為優雅和靈活的操作字節碼的方式。目前 ASM 已被廣泛的開源應用架構所使用,例如:Spring、Hibernate 等。

3. 開始我們的模擬破解之路

JetbrainsCrack.java & Agent 操作類

/**
* 博客:http://bugstack.cn
* 公眾號:bugstack蟲洞棧 | 更多原處優質乾貨
* Agent 類,所有程序啟動只要配置了 -javaagent: 都會走到 premain 方法
*/
public class JetbrainsCrack {
public static void premain(String args, Instrumentation inst) {
System.out.println("**************************************");
System.out.println("*       公眾號:bugstack蟲洞棧       *");
System.out.println("*     博客:https://bugstack.cn      *");
System.out.println("*   你用劍,我用刀,好的代碼都很燒! *");
System.out.println("**************************************");
inst.addTransformer(new MethodEntryTransformer());
}
static class MethodEntryTransformer implements ClassFileTransformer {
private Logger logger = LoggerFactory.getLogger(MethodEntryTransformer.class);
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
try {
if (className.equals("com/jetbrains/ls/newLicenses/DecodeCertificates")) {
ClassReader cr = new ClassReader(classfileBuffer);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
List<MethodNode> methodNodes = cn.methods;
for (MethodNode methodNode : methodNodes) {
if ("decodeLicense".equals(methodNode.name)) {
InsnList insns = methodNode.instructions;
//清除指令
insns.clear();
insns.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 將本地指定的引用存入棧中
insns.add(new InsnNode(Opcodes.ARETURN));          // 從方法中返回引用類型的數據
// 訪問結束
methodNode.visitEnd();
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
byte[] bytes = cw.toByteArray();
// 輸出字節碼到Class
this.outputClazz(bytes);
// 返回最新字節碼
return cw.toByteArray();
}
}
}
} catch (Exception e) {
return classfileBuffer;
}
return classfileBuffer;
}
private void outputClazz(byte[] bytes) {
// 輸出類字節碼
FileOutputStream out = null;
try {
out = new FileOutputStream("ASMDecodeCertificates.class");
logger.info("ASM類輸出路徑:{}", (new File("")).getAbsolutePath());
out.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != out) try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
  • 在這個類中可以看到有一個 premain 方法,這個是在被 java agent 處理後的程序入口,所有信息類和方法都會到這個入口
  • 之後我們使用 inst.addTransformer(new MethodEntryTransformer()); 添加我們自己的處理邏輯,這個邏輯也是用字節碼編程技術代理類的過程。這個過程也就是我們平時開發中那些不需硬編碼就可以監控方法執行時長的邏輯一樣
  • MethodEntryTransformer 實現了 ClassFileTransformer 的 transform 方法,也就是真正操作字節碼的過程。
    • 在這個類方法中首先需要找到我們的授權碼校驗類 com/jetbrains/ls/newLicenses/DecodeCertificates ,每一個版本的IDEA不一樣,同時授權邏輯校驗也不一樣
    • 緊接著在找到授權校驗類裡面的校驗方法,if (“decodeLicense”.equals(methodNode.name))
    • 接下來就需要對字節碼進行處理了,這裡面的處理過程比較粗暴,直接將原來方法裡的指令內容清空。然後使用 new VarInsnNode(Opcodes.ALOAD, 1) 將本地指定的引用存入棧中
    • 之後將我們的入參內容直接返回,new InsnNode(Opcodes.ARETURN),從方法中返回引用類型的數據。在以往舊版本的 IDEA 破解中比較簡單,直接把最終需要的破解內容返回即可,裡面描述了 IDEA 各個軟件的使用期限
    • 最終將我們處理後的字節碼返回給方法,return cw.toByteArray();這個時候雖然你大爺還是你大爺,但你大娘已經不是你大娘了
  • 為了測試的驗證我們將變更後的字節碼代碼(大娘)輸出到工程目錄下,也就是一個 class 文件,下文測試時候驗證

4. DecodeCertificates.java & 模擬 ideaIU-15.0.1 軟件授權碼校驗類

public class DecodeCertificates {
public String decodeLicense(String usingKey) {
// 模擬校驗授權碼
return "usingKey is error:"+ usingKey;
}
}
  • 這個類比較簡單只是模擬有這麼個方法用於校驗授權碼

5. ApiTest.java & 測試類

/**
* 博客:http://bugstack.cn
* 公眾號:bugstack蟲洞棧 | 更多原處優質乾貨
* 測試類配置 VM 參數
* Idea VM options:-javaagent:E:\itstack\GIT\itstack.org\itstack-demo-code\itstack-demo-code-idea\target\itstack-demo-code-idea-1.0-SNAPSHOT.jar
*/
public class ApiTest {
private static Logger logger = LoggerFactory.getLogger(ApiTest.class);
public static void main(String[] args) throws Exception {
DecodeCertificates decodeCertificates = new DecodeCertificates();
// 模擬usingKey:認購有效期至2089年7月8日
String license = decodeCertificates.decodeLicense("Subscription is active until July 8, 2089");
logger.info("測試結果:{}", license);
}
}

6. MANIFEST.MF 配置引導啟動時加載

Manifest-Version: 1.0
Premain-Class: org.itstack.demo.JetbrainsCrack
Can-Redefine-Classes: true

7. POM 配置打包時加入ASM包

<!-- 將javassist包打包到Agent中 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<artifactSet>
<includes>
<include>asm:asm-all:jar:</include>
</includes>
</artifactSet>
</configuration>
</plugin>

五、工程測試

  1. 先單純的直接運行ApiTest.java ,測試結果如下(模擬返回授權不可用);

    21:23:46.101 [main] INFO  org.itstack.demo.test.ApiTest - 測試結果:usingKey is error:Subscription is active until July 8, 2089
    
  2. 第二步測試前先打包下工程,這個時候你會看到如下結果;

    [INFO] --- maven-install-plugin:2.4:install (default-install) @ itstack-demo-code-idea ---
    [INFO] Installing E:\itstack\GIT\itstack.org\itstack-demo-code\itstack-demo-code-idea\target\itstack-demo-code-idea-1.0-SNAPSHOT.jar to D:\Program Files (x86)\apache-maven-3.6.2\repository\org\itstack\demo\itstack-demo-code-idea\1.0-SNAPSHOT\itstack-demo-code-idea-1.0-SNAPSHOT.jar
    [INFO] Installing E:\itstack\GIT\itstack.org\itstack-demo-code\itstack-demo-code-idea\dependency-reduced-pom.xml to D:\Program Files (x86)\apache-maven-3.6.2\repository\org\itstack\demo\itstack-demo-code-idea\1.0-SNAPSHOT\itstack-demo-code-idea-1.0-SNAPSHOT.pom
    [INFO] Installing E:\itstack\GIT\itstack.org\itstack-demo-code\itstack-demo-code-idea\target\itstack-demo-code-idea-1.0-SNAPSHOT-sources.jar to D:\Program Files (x86)\apache-maven-3.6.2\repository\org\itstack\demo\itstack-demo-code-idea\1.0-SNAPSHOT\itstack-demo-code-idea-1.0-SNAPSHOT-sources.jar
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  3.080 s
    [INFO] Finished at: 2020-01-05T23:25:08+08:00
    [INFO] ------------------------------------------------------------------------
    
  • 這裡的 itstack-demo-code-idea-1.0-SNAPSHOT.jar 就是我們的 Agent 包,按實際情況複製自己的路徑
  1. 配置 VM options:-javaagent:E:\itstack\GIT\itstack.org\itstack-demo-code\itstack-demo-code-idea\target\itstack-demo-code-idea-1.0-SNAPSHOT.jar

    源碼分析|咋嘞?你的IDEA過期了吧!加個Jar包就破解了,為什麼?

  2. 運行 ApiTest 測試,正確結果如下;

    23:29:42.803 [main] INFO  org.itstack.demo.test.ApiTest - 測試結果:usingKey is error:Subscription is active until July 8, 2089
    Process finished with exit code 0
    
    • 這個過程就是你使用 jar 包破解 IDEA 的過程,瞭解這個技術點可以用在很多不需要硬編碼就能做到的服務中,比如監控,調試等
  3. 別忘了我們還在 Agent 中輸出了新的字節碼,看看這個時候的類是什麼樣(你大爺還是你大爺,但你大娘可不是你大娘了)

被代理前

public class DecodeCertificates {
public String decodeLicense(String usingKey) {
// 模擬校驗授權碼
return "usingKey is error:"+ usingKey;
}
}

被代理後

package com.jetbrains.ls.newLicenses;
public class DecodeCertificates {
public DecodeCertificates() {
}
public String decodeLicense(String usingKey) {
return usingKey;
}
}

六、綜上總結

  • 建議個人使用社區版即可,不要嘗試破解尊重IDEA,本文只為學習 javaagent 技術
  • ASM 這個東西特別強大,其實字節碼編程還有 javassist,在一起 RPC 框架中有非常多的使用
  • 關於 java agent 我已經專題方式寫過案例文章,可以參考;bugstack.cn/itstack-dem…

七、關注公眾號

源碼分析|咋嘞?你的IDEA過期了吧!加個Jar包就破解了,為什麼?

相關文章

Redux的中間件,Axios的攔截器、Vuex的插件讓你迷惑嗎?實現一個精簡版的就徹底搞懂了。

最近從0學習Git,詳細分類總結了這份Git命令寶典

Redis6.0新特性之集群代理

iOS底層從頭梳理dyld加載流程