关山难越,谁悲失路之人;萍水相逢,尽是他乡之客。
百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程教程 > 技术文章 > 正文

源码分析 | 咋嘞?你的IDEA过期了吧!加个Jar包就破解了为什么?

guanshanw 2023-09-16 10:33 52 浏览 0 评论

推荐阅读:

阿里P8架构师“呕心沥血”1年总结出这份Linux基础到进阶学习文档

年前面试京东3面凉经~ 面试过程与真题全分享+备战春招(java)

一、前言介绍

2020年了,对于一个程序猿来说;

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

当你过了元旦,爽了周末,清早上班,拿起杯子,加点新(薪)水,打开电脑,收起烦恼,翘起小脚,上扬嘴角。一切就绪都准备好,好!撸代码!啊!!!IDEA duang duang duang,过期了!

脑瓜一热赶紧搜索破解码;

  • 第一个,失败
  • 第二个,失败
  • 第三个,失败
  • ...
  • 第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


第二步测试前先打包下工程,这个时候你会看到如下结果;

[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] ------------------------------------------------------------------------

被代理前

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 框架中有非常多的使用

相关推荐

七条简单命令让您玩转Git
七条简单命令让您玩转Git

凭借着出色的协作能力、快速部署效果与代码构建辅助作用,Git已经得到越来越多企业用户的青睐。除了用于开发商业及消费级应用之外,众多科学及政府机构也开始尝试使用这...

2023-10-07 12:14 guanshanw

基本完整的关于Git分支branch的操作
基本完整的关于Git分支branch的操作

Git使用背景项目中要用到dev或者其他分支开发完代码,需要将该分支合并到master的需求操作步骤下面以dev名称为lex为分支名为例来操作一遍客户端操作:...

2023-10-07 12:14 guanshanw

Git 进阶(合并与变基)
Git 进阶(合并与变基)

在Git中整合来自不同分支的修改主要有两种方法:合并(merge)以及变基(rebase)合并(merge)merge流程图merge的原理是找到这两个分...

2023-10-07 12:13 guanshanw

Git学习笔记 003 Git进阶功能 part5 合并(第一部分)

合并(merge)是很常用的操作。尤其是一个庞大的很多人参与开发的企业级应用。一般会设定一个主分支,和多个副分支。在副分支开发完成后,合并到主分支中。始终保持主分支是一个完整的,稳定的最新状态的分支。...

非标题党,三张图帮你理解git merge和git rebase的区别
非标题党,三张图帮你理解git merge和git rebase的区别

初始场景:基于正常的开发分支修改几个小bug,然后在合并到开发分支上。gitmergegitcheckoutfeaturegitmergeho...

2023-10-07 12:13 guanshanw

git 初次使用(01)
git 初次使用(01)

先从github上克隆代码下来:使用vscode克隆代码如下图,填写上github仓库地址:vscode有时候克隆代码速度比较慢,可以用命令行方式克隆gitc...

2023-10-07 12:12 guanshanw

Git 远程操作

4.Git远程操作命令说明gitremote远程版本库操作gitfetch从远程获取版本库gitpull下载远程代码并合并gitpush上传远程代码并合并4.1远程版本库操作gitre...

Git常用命令-总结
Git常用命令-总结

创建git用户$gitconfig--globaluser.name"YourName"$gitconfig--globaluser.em...

2023-10-07 12:12 guanshanw

git中删除从别人clone下来项目的git信息,并修改为自己的分支

如果你从别人的Git存储库中克隆了一个项目,并想要删除与该存储库相关的Git信息,并将其修改为你自己的分支,则可以执行以下步骤:使用gitclone命令克隆存储库:gitclone<u...

git系列-回滚和放弃本地修改

回滚历史提交就是reset的功能。这种情况是已经提交远程仓库,需要回滚到之前的提交。gitreset--hardcommitId//注:强制提交后,当前版本后面的提交版本将会删掉!gi...

GIT使用小技巧大全
GIT使用小技巧大全

在大型软件工程的开发过程中,版本控制是无法绕过去的;目前来说,最火的版本控制软件就是GIT了。早两年SVN比较火,不过被大神linus喷了几次后,就日落西山了,...

2023-10-07 12:11 guanshanw

git相关命令-上
git相关命令-上

这些命令都是看了文档后,个人觉得比较有用的一些,展示给大家。回到远程仓库的状态抛弃本地所有的修改,回到远程仓库的状态。gitfetch--all&...

2023-10-07 12:10 guanshanw

Git命令行接口:掌握Git的必备技能
Git命令行接口:掌握Git的必备技能

Git是一款强大的分布式版本控制工具,它支持命令行界面操作。熟练掌握Git命令行接口,是开发者使用Git的必备技能之一。在这篇文章中,我们将介绍Git命令行接口...

2023-10-07 12:10 guanshanw

Git命令详解
Git命令详解

相信各位小伙伴们应该都对git有一些了解,毕竟作为代码管理的神器,就算不是IT行业的小伙伴肯定也或多或少的听说过一些。今天就来和小伙伴们分享一下自己总结的常用命...

2023-10-07 12:10 guanshanw

工作7年收集到的git命令
工作7年收集到的git命令

概念git中的术语解释:仓库也叫版本库(repository)stage:暂存区,add后会存到暂存区,commit后提交到版本库git安装linux...

2023-10-07 12:10 guanshanw

取消回复欢迎 发表评论: